有限状态机核心类包括FSMState和FSMSystem这两个类:
1.FSMState类主要作为各种状态的基类而存在,内部核心字典主要包括两部分,其中KEY值一般保存转换条件,Value值保存状态ID,这两部分通过枚举的方式进行写入.作为基类基本方法包括:
(1) 添加键值的方法
(2) 移除键值的方法
(3) 根据键获取值的方法
(4) 状态开始之前的处理方法
(5) 状态结束之前的处理方法
(6) 状态运行中的处理方法
2.FSMSystem就是一个管理类,有限状态机的核心思想就是把各种状态从简单的switch case语句中抽离出来,具体到一个个类中,每一状态类都包含一个字典,字典中又包含转换条件,状态/ID这两个键值对,作为基类基本方法包括:
(1) 添加键值的方法
(2) 移除键值的方法
(3) 初始状态启动的方法
(4) 获取当前状态的方法(第一次获取应该从初始启动方法中给予赋值,在转换状态的方法中给及刷新)
(5) 转换状态的方法
有限状态机可以理解为针对一个状态的复杂的对象,通过两个类来替代switch方法,
例如: 卫兵A有两种状态 巡逻/追击 巡逻到追击状态的切换条件是发现敌人,追击到巡逻状态的切换条件是敌人死亡,切换条件跟状态以枚举的方式保存在两个枚举当中.对于卫兵各种状态的控制通过Guard这个类来实现,所以这个类中肯定要有一个成员变量FSMSystem,通过FSMSystem fsmSystem= new FSMSystem()来实例化一个状态管理类,把初始状态通过通过添加方法添加到字典中,同时巡逻跟追击两个类也要实例化出来,其字典中保存的是面对条件要转变到哪个类.
public class Guard : MonoBehaviour
{
private FSMSystem fsmSystem;
private PatrolState patrolState;
private AttackState attackState;
private void Start()
{
patrolState = new patrolState();
attackState=new attackState();
fsmSystem=new FSMSystem();
patrolState.AddTranstion(Transitons.find, StateId.attack);
attackState.AddTranstion(Transitons.died, StateId.patrol);
fsmSystem.AddState(patrolState);
fsmSystem.AddState(attackState);
fsmSystem.InitState(patrolState);
fsmSystem.TransitonState(Transitons.died);
}
}
FSMSystem 核心代码
public class FSMSystem
{
//状态容器
private Dictionary<StateId, FSMState> statesDic;
//当前状态
private FSMState currentState;
public FSMSystem()
{
statesDic = new Dictionary<StateId, FSMState>();
}
/// <summary>
/// 添加
/// </summary>
/// <param name="trans"></param>
/// <param name="state"></param>
public void AddState(FSMState fsmstate)
{
if (fsmstate.ID == StateId.nullStateId)
{
Debug.Log("状态为空,添加失败");
return;
}
if (statesDic.ContainsKey(fsmstate.ID))
{
Debug.Log("状态已存在,不能重复添加");
return;
}
statesDic.Add(fsmstate.ID, fsmstate);
}
/// <summary>
/// 删除
/// </summary>
/// <param name="trans"></param>
public void DelState(FSMState fsmstate)
{
if (fsmstate.ID == StateId.nullStateId)
{
Debug.Log("状态为空,删除失败");
return;
}
if (!statesDic.ContainsKey(fsmstate.ID))
{
Debug.Log("状态不存在,删除失败");
return;
}
statesDic.Remove(fsmstate.ID);
}
/// <summary>
/// 获取当前状态
/// </summary>
/// <param name="trans"></param>
/// <returns></returns>
public FSMState GetCurrentState(StateId id)
{
if (id == StateId.nullStateId)
{
Debug.Log("状态为空,返回空");
return null;
}
if (!statesDic.ContainsKey(id))
{
Debug.Log("状态不存在,返回空");
return null;
}
return statesDic[id];
}
/// <summary>
/// 启动初始状态
/// </summary>
public void InitState(FSMState initState)
{
currentState = initState;
initState.OnBeforeEnter();
initState.OnInState();
}
/// <summary>
/// 状态转换
/// </summary>
/// <param name="fsmState"></param>
public void TransitonState(Transitons trans)
{
if (trans == Transitons.nullTransiton)
{
Debug.Log("转换条件为空值,状态转换失败");
return;
}
if (!currentState.RelDic.ContainsKey(trans))
{
Debug.Log("当前状态不包含对应的转换条件,状态转换失败");
}
//当前状态结束前执行的方法
currentState.OnBeforeEnd();
currentState = statesDic[currentState.GetStateId(trans)];
//新状态开始前执行的方法
currentState.OnBeforeEnter();
//新状态运行中
currentState.OnInState();
}
}
FSMState 核心代码
public enum Transitons
{
nullTransiton=0,
find,
died
}
public enum StateId
{
nullStateId=0,
attack,
patrol
}
public abstract class FSMState
{
//容器
public Dictionary<Transitons, StateId> RelDic;
//状态对应的id
protected StateId id;
public StateId ID
{
get { return id; }
}
/// <summary>
/// 添加
/// </summary>
/// <param name="trans"></param>
/// <param name="state"></param>
public void AddTranstion(Transitons trans, StateId state)
{
if (trans == Transitons.nullTransiton)
{
Debug.Log("状态条件为空,添加失败");
return;
}
if (RelDic.ContainsKey(trans))
{
Debug.Log("状态条件已存在,不能重复添加");
return;
}
RelDic.Add(trans, state);
}
/// <summary>
/// 删除
/// </summary>
/// <param name="trans"></param>
public void DelTranstion(Transitons trans)
{
if (trans == Transitons.nullTransiton)
{
Debug.Log("状态条件为空,删除失败");
return;
}
if (!RelDic.ContainsKey(trans))
{
Debug.Log("状态条件不存在,删除失败");
return;
}
RelDic.Remove(trans);
}
/// <summary>
/// 获取值
/// </summary>
/// <param name="trans"></param>
/// <returns></returns>
public StateId GetStateId(Transitons trans)
{
if (trans == Transitons.nullTransiton)
{
Debug.Log("状态条件为空,返回空");
return StateId.nullStateId;
}
if (!RelDic.ContainsKey(trans))
{
Debug.Log("状态条件不存在,返回空");
return StateId.nullStateId;
}
return RelDic[trans];
}
/// <summary>
/// 进入状态之前
/// </summary>
public abstract void OnBeforeEnter();
/// <summary>
/// 结束状态之前
/// </summary>
public abstract void OnBeforeEnd();
/// <summary>
/// 状态运行中
/// </summary>
public abstract void OnInState();
}