这里有我对于FSM的第二种理解的写法,也是我第一次参加GameJam的懵懵懂懂的用法,首先这个FSM的中心是在一个FSM的代码中,而不是用泛型扩散到其他的代码中。也就是说,你每一个物体使用状态机就要重写一遍FSM来具体应用这个FSM。
先创建一个接口,用来给每一个状态限制,同时方便状态机来用字典存放每一个状态的切换
1 2 3 4 5 6 7
| public interface IState { void OnEnter(); void OnUpdate(); void OnFixedUpdate(); void OnExit(); }
|
创建一个枚举类型用来存放每一个所选对象需要的各种类型
1 2 3 4 5 6
| public enum StateType { A, B, C }
|
然后就要开始写FSM的主体代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class FSM : MonoBehaviour { private IState currentState; private Dictionary<StateType,IState> states = new Dictionary<StateType,IState>();
void Start() { states.Add(StateType.A, new A(this)); states.Add(StateType.B, new B(this)); states.Add(StateType.C, new C(this));
TransitionState(StateType.A); }
void Update() { currentState.OnUpdate(); }
void FixedUpdate() { currentState.OnFixedUpdate(); }
public void TransitionState(StateType type) { if (currentState != null) currentState.OnExit(); currentState = states[type]; currentState.OnEnter(); } }
|
在上面的Start
方法中,很明显的有这么三行
1 2 3
| states.Add(StateType.A, new A(this)); states.Add(StateType.B, new B(this)); states.Add(StateType.C, new C(this));
|
这就是与上一个FSM写法的最大的区别,就是中心化。
下面对其中一种状态进行定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class A : IState { private FSM manager;
public IdleState(FSM manager) { this.manager = manager; } public void OnEnter() { }
public void OnUpdate() { }
public void OnFixedUpdate() { }
public void OnExit() { } }
|
写到这里,你们肯定都豁然开朗了,在这里面是直接把FSM当作中心,用状态的构造函数来获取FSM脚本的具体方法。然后把状态的切换都写在其他的类中,改变FSM的currentState
来实现状态的切换。
这个写法中,FSM中可以写很多各个状态通用的方法,并且可以用在其他的状态中。这种写法的优点就是代码分散在很多脚本中,每一个状态都可以写一个单独的脚本,但是缺点也很明显,每次写一种新的状态机就要重写一次FSM,比较适合大的项目,状态机的数量少但是状态很多的工程中。