首先我们要确定,基于状态模式的状态模式的FSM有限状态机有三个部分:分别是状态机本身,状态,状态之间的转换。这三个部分都需要封装成对象,以便降低代码之间的耦合度。
1.FSM
public enum RoleState
{
Idle,
Walk,
Jump,
Attack,
Dead,
PickUp,
}
public class FSM //不要继承MonoBehaviour
{
//状态机运行时状态参数,当前状态,上一个状态。
public StateBase curState { get; private set; }
public StateBase lastState { get; private set; }
//用字典记录状态机中所有的状态
private Dictionary<RoleState, StateBase> states = new Dictionary<RoleState, StateBase>();
//状态机整体的参数
private StateBase defaultState;//状态机默认状态,也即第一个状态
private StateBase exitState;//状态机退出状态,也即最后一个状态
public void Init(StateBase defaultState)//状态机初始化
{
this.defaultState = defaultState;
curState = defaultState;
curState.Enter();
}
public void Update(string input)//状态机的执行,即切换状态
{
if(curState == null)
return;
StateBase nextState = curState.HandleInput(input);//处理当前输入,获取下一状态
if (nextState != curState && nextState != null)
{
curState.Exit();
lastState = curState;
curState = nextState;//状态切换
curState.Enter();
}
curState.Update();
}
public void AddState(RoleState stateId,StateBase state)
{
states.Add(stateId,state);
}
public bool Remove(RoleState stateId)
{
if (states.ContainsKey(stateId))
{
states.Remove(stateId);
return true;
}
return false;
}
public StateBase GetState(RoleState stateId)
{
if (states.ContainsKey(stateId))
return states[stateId];
return null;
}
}
2.状态的基类
public class StateBase//可以是接口,也可以是基类,具体使用哪个看情况
{
public RoleState stateId { get;private set; }//状态ID
public FSM parent { get;private set; }//属哪个状态机
public StateBase(FSM parent, RoleState stateId)
{
this.parent = parent;
this.stateId = stateId;
}
//状态的全部转换,需要在Player对象类中初始化生成并添加进对应的状态中
public List<TransitionBase> transitions = new List<TransitionBase>();
public void AddTransition(TransitionBase transition)
{
transitions.Add(transition);
}
public virtual void Enter(){}//进入状态时进行的动作
public virtual void Exit(){}//退出状态时进行的动作
//在这个状态内要执行的操作
public virtual void Update(){}//在状态内执行相关输出
public virtual StateBase HandleInput(string input)//在当前状态内处理输入
{
foreach (TransitionBase item in transitions)//判断该输入是否满足某个转移
{
if (item.fromState != this)
{
continue;
}
if(item.CanTransition(input))
{
return item.toState;
}
}
return null;
}
}
3.状态转换的基类
public class TransitionBase
{
//从某个状态转换到另一个状态
public StateBase fromState;
public StateBase toState;
public TransitionBase(StateBase fromState, StateBase toState)
{
this.fromState = fromState;
this.toState = toState;
}
public virtual bool CanTransition(string input)
{
//在这里处理输入,判断一个状态是否能进入另一个状态
return true;
}
}
状态机的使用
public class Player:MonoBehaviour
{
private FSM fsm;
public Player()
{
//在构造函数中实例化状态机,并将实例化后的状态加入状态机中,然后根据需要的状态转移图将转移类加入状态中,最后设置状态机的初始状态。
}
public void Update()
{
fsm.Update(input);
}
private string input;
public void SetInput(string input)
{
this.input = input;
}
}