一、最简单的有限状态机
包括一个FiniteStateMachine类和一个FsmState类。
FsmState类只有了Enter/Update/Exit三个函数。
FiniteStateMachine提供ChangeState。
if (currentState != null)
currentState.Exit();
currentState = newState;
if (newState != null)
currentState.Enter();
FiniteStateMachine和FsmState都由同一个类Owner持有。
1)FsmState使用接口还是类?
我建议用抽象类。考虑一下到底是“Is a”还是“Can do”,我觉得是“Is a”,不要给FsmState太多其他功能。
2)ChangeState由谁来调用?
Owner。
State可以作为Owner的成员,也可以存放在字典中。
1.作为成员,比如idleState,moveState等等,再为每一个ChangeState添加相应的函数,如
ChangeStateToIdle(), 可以在其中加入具体的检查。
2.字典,使用stateId(一般是枚举类型、字符常量)作为关键字。
ChangeState可以写成通用类型,如ChangeState(string stateId)。
如果将Owner和FiniteStateMachine结合, 就类似于(四)中描述的层级状态机。
一般实现的时候会将Owner作为参数传入到Enter/Update/Exit中。
2)ChangeState的时候要不要加入限制?
如果条件复杂,参考(二)中描述的Transition机制。
但这里有一个简单的情况,要不要判断相同的状态?
if (currentState == newState)
return;
有些时候可能频繁的响应事件(比如按键)。
如果频繁地调用ChangeState(),就要考虑Enter和Exit是不是会有开销。
3)加入前一状态,提供返回功能
这个功能很简单,可以说是最简单版的下推自动机,参考(五)
一份参考代码
public class FiniteStateMachine<T>
{
private FsmState<T> currentState;
private readonly T owner;
private FsmState<T> previousState;
public FiniteStateMachine(T owner)
{
this.owner = owner;
}
public void ChangeState(FsmState<T> newState)
{
previousState = currentState;
if (currentState != null)
currentState.Exit(owner);
currentState = newState;
if (currentState != null)
currentState.Enter(owner);
}
public void ChangeStateToNil()
{
ChangeState(null);
}
public void RevertToPreviousState()
{
ChangeState(previousState);
}
public void Update()
{
if (currentState != null)
currentState.Update(owner);
}
}
public abstract class FsmState<T>
{
public abstract void Enter(T owner);
public abstract void Exit(T owner);
public abstract void Update(T owner);
}
二、增加枚举类型Transition(转移)
转移定义了一个状态是否可以移动到另个状态。
或者也可以认为是一个状态接受了某个转移命令后跳转到了另一个状态。
此时FiniteStateMachine不再提供ChangeState,而是PerfermTransition。
三、增加StateTransition类
除了基本的定义状态与状态之间可以跳转的功能外,还增加了Update功能。
也就是让跳转不要一下完成,适合用于UI之间的切换。
State的的Enter和Exit也相应的扩展了成了两个函数BeginEnter/EndEnter和BeginExit/EndExit。
再进一步扩展可以加入Condition,用来判断是否满足可以跳转的条件。
当然,如果你在状态机上层加了行为树,这个Condition就显得多余。
四、层级状态机(Hierarchical State Machine)
实现1:每个状态本身就是一个状态机,随时可以增加子状态
实现2:增加一个栈,栈上的每个状态都是下一级状态的子状态
层级状态机的一个应用是处理事件,从最底层进行响应,如果不处理就先上转发。
[待补充]
五、下推自动机 (Pushdown Automata)
下推自动机也有一个栈,但是和层级状态机完全不同。
这个栈保存的是历史信息,让状态可以恢复到之前的状态
[待补充]
参考:
<Game Programming Patterns> State Pattern (http://gameprogrammingpatterns.com/state.html)
C#代码实现:
http://wiki.unity3d.com/index.php?title=Finite_State_Machine
https://forum.unity3d.com/threads/unity-fsm.26030/
https://github.com/xanathar/FSMsharp
https://github.com/Real-Serious-Games/Fluent-State-Machine
http://jacksondunstan.com/articles/3137
https://github.com/1004370065/FSM
https://github.com/freestyleSago/FSM
https://github.com/SOnions/FSM/blob/master/FSM.cs