有限状态机是把一个对象的行为分解称为易于处理的“块”或状态。例如,灯的开关,就是一个简单的有限状态机。
为什么要用?
通常,在一个程序里面,转换各种状态,需要使用一系列的if-then语句或者switch语句。如果内容少的话这会很容易理解,也合理,但是当内容非常庞大的时候,这时候这种方法写的代码就如一个怪物,这时候FSM就出现了。
代码如下:
public class FSM
{
//转换状态回调
public delegate void FSMTranslationCallFunc();
//进入状态回调
public delegate void OnEnterState();
//离开状态回调
public delegate void OnExitState();
//状态类
public class FSMState
{
public string name;
public OnEnterState onEnter;
public OnExitState onExit;
public FSMState(string name, OnEnterState enter = null, OnExitState exit = null)
{
this.name = name;
onEnter = enter;
onExit = exit;
}
//转换状态的字典
public Dictionary<string, FSMTranslation> TranslationDict = new Dictionary<string, FSMTranslation>();
}
//转换状态事件类
public class FSMTranslation
{
//前状态
public FSMState fromState;
public string name;
//要转换的状态
public FSMState toState;
public FSMTranslationCallFunc callFunc;
public FSMTranslation(FSMState fromState, string name, FSMState toState, FSMTranslationCallFunc callFunc)
{
this.fromState = fromState;
this.toState = toState;
this.name = name;
this.callFunc = callFunc;
}
}
//当前状态
public FSMState curState;
//状态字典
public Dictionary<string, FSMState> StateDict = new Dictionary<string, FSMState>();
//增加状态
public void AddState(FSMState state)
{
StateDict[state.name] = state;
}
//增加转换状态
public void AddTranslation(FSMTranslation translation)
{
StateDict[translation.fromState.name].TranslationDict[translation.name] = translation;
}
//初始化
public void Start(FSMState state)
{
curState = state;
curState.onEnter();
Debug.Log("FSM Start : " + state.name);
}
//切换状态
public void HandlerEvent(string name)
{
//name = curState.name + "To" + name;
//当前状态有目标转换状态事件的话
if (curState != null && curState.TranslationDict.ContainsKey(name))
{
//Debug.Log("From " + curState.name);
if (curState.onExit != null)
{
Debug.Log("Exit : " + curState.name);
curState.onExit();
}
//转换回调
curState.TranslationDict[name].callFunc();
curState = curState.TranslationDict[name].toState;
//Debug.Log(" To " + curState.name);
if (curState.onEnter != null)
{
Debug.Log("Enter : " + curState.name);
curState.onEnter();
}
}
}
}