public enum Transition //状态转换操作的枚举
{
NullTransition = 0,
StartButtonClick,
PauseButtonClick,
}
public enum StateID //状态枚举
{
NullStateID = 0,
Menu,
Play,
Pause,
GameOver,
}
///
/// This class represents the States in the Finite State System.
/// Each state has a Dictionary with pairs (transition-state) showing
/// which state the FSM should be if a transition is fired while this state
/// is the current state.
/// Method Reason is used to determine which transition should be fired .
/// Method Act has the code to perform the actions the NPC is supposed do if it's on this state.
///
public abstract class FSMState:MonoBehaviour //状态基类
{
protected FSMSystem fsm; //状态机
public FSMSystem FSM
{
set { fsm = value; }
}
protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
protected StateID stateID;
public StateID ID { get { return stateID; } }
public void AddTransition(Transition trans, StateID id)
{
// Check if anyone of the args is invalid
if (trans == Transition.NullTransition)
{
Debug.LogError("FSMState ERROR: NullTransition is not allowed for a real transition");
return;
}
if (id == StateID.NullStateID)
{
Debug.LogError("FSMState ERROR: NullStateID is not allowed for a real ID");
return;
}
// Since this is a Deterministic FSM,
// check if the current transition was already inside the map
if (map.ContainsKey(trans))
{
Debug.LogError("FSMState ERROR: State " + stateID.ToString() + " already has transition " + trans.ToString() +
"Impossible to assign to another state");
return;
}
map.Add(trans, id);
}
///
/// This method deletes a pair transition-state from this state's map.
/// If the transition was not inside the state's map, an ERROR message is printed.
///
public void DeleteTransition(Transition trans)
{
// Check for NullTransition
if (trans == Transition.NullTransition)
{
Debug.LogError("FSMState ERROR: NullTransition is not allowed");
return;
}
// Check if the pair is inside the map before deleting
if (map.ContainsKey(trans))
{
map.Remove(trans);
return;
}
Debug.LogError("FSMState ERROR: Transition " + trans.ToString() + " passed to " + stateID.ToString() +
" was not on the state's transition list");
}
///
/// This method returns the new state the FSM should be if
/// this state receives a transition and
///
public StateID GetOutputState(Transition trans)
{
// Check if the map has this transition
if (map.ContainsKey(trans))
{
return map[trans];
}
return StateID.NullStateID;
}
///
/// This method is used to set up the State condition before entering it.
/// It is called automatically by the FSMSystem class before assigning it
/// to the current state.
///
public virtual void DoBeforeEntering() { }
///
/// This method is used to make anything necessary, as reseting variables
/// before the FSMSystem changes to another one. It is called automatically
/// by the FSMSystem before changing to a new state.
///
public virtual void DoBeforeLeaving() { }
///
/// This method decides if the state should transition to another on its list
/// NPC is a reference to the object that is controlled by this class
///
public virtual void Reason() { }
///
/// This method controls the behavior of the NPC in the game World.
/// Every action, movement or communication the NPC does should be placed here
/// NPC is a reference to the object that is controlled by this class
///
public virtual void Act() { }
} // class FSMState
///
/// FSMSystem class represents the Finite State Machine class.
/// It has a List with the States the NPC has and methods to add,
/// delete a state, and to change the current state the Machine is on.
///
public class FSMSystem //状态机基类
{
private List<FSMState> states;
// The only way one can change the state of the FSM is by performing a transition
// Don't change the CurrentState directly
private StateID currentStateID;
public StateID CurrentStateID { get { return currentStateID; } }
private FSMState currentState;
public FSMState CurrentState { get { return currentState; } }
public FSMSystem()
{
states = new List<FSMState>();
}
public void SetCurrentState(FSMState s) //设置当前状态
{
currentState = s;
currentStateID = s.ID;
s.DoBeforeEntering(); //进入状态前要做的
}
///
/// This method places new states inside the FSM,
/// or prints an ERROR message if the state was already inside the List.
/// First state added is also the initial state.
///
public void AddState(FSMState s)
{
// Check for Null reference before deleting
if (s == null)
{
Debug.LogError("FSM ERROR: Null reference is not allowed");
}
s.FSM = this; //在添加状态的时候给状态
// First State inserted is also the Initial state,
// the state the machine is in when the simulation begins
if (states.Count == 0)
{
states.Add(s);
return;
}
// Add the state to the List if it's not inside it
foreach (FSMState state in states)
{
if (state.ID == s.ID)
{
Debug.LogError("FSM ERROR: Impossible to add state " + s.ID.ToString() +
" because state has already been added");
return;
}
}
states.Add(s);
}
///
/// This method delete a state from the FSM List if it exists,
/// or prints an ERROR message if the state was not on the List.
///
public void DeleteState(StateID id)
{
// Check for NullState before deleting
if (id == StateID.NullStateID)
{
Debug.LogError("FSM ERROR: NullStateID is not allowed for a real state");
return;
}
// Search the List and delete the state if it's inside it
foreach (FSMState state in states)
{
if (state.ID == id)
{
states.Remove(state);
return;
}
}
Debug.LogError("FSM ERROR: Impossible to delete state " + id.ToString() +
". It was not on the list of states");
}
///
/// This method tries to change the state the FSM is in based on
/// the current state and the transition passed. If current state
/// doesn't have a target state for the transition passed,
/// an ERROR message is printed.
///
public void PerformTransition(Transition trans) //状态的过度回调
{
// Check for NullTransition before changing the current state
if (trans == Transition.NullTransition)
{
Debug.LogError("FSM ERROR: NullTransition is not allowed for a real transition");
return;
}
// Check if the currentState has the transition passed as argument
StateID id = currentState.GetOutputState(trans);
if (id == StateID.NullStateID)
{
Debug.LogError("FSM ERROR: State " + currentStateID.ToString() + " does not have a target state " +
" for transition " + trans.ToString());
return;
}
// Update the currentStateID and currentState
currentStateID = id;
foreach (FSMState state in states)
{
if (state.ID == currentStateID)
{
// Do the post processing of the state before setting the new one
currentState.DoBeforeLeaving();
currentState = state;
// Reset the state to its desired condition before it can reason or act
currentState.DoBeforeEntering();
break;
}
}
} // PerformTransition()
} //class FSMSystem
每个单独的状态需要继承FSMState基类,这个基类中包含了状态本身的一些操作,如添加状态的转换回调,删除状态的转换回调,状态的进入回调,离开回调,还拥有一个包含了状态枚举和过度操作枚举的字典。
状态机基类保存了一个状态列表,并且专注当前的状态,拥有设置当前状态的方法,删除状态的方法,状态的过度回调。
状态机管理中的状态列表的初始化可以使用如下方式添加状态,在某个继承了状态机管理类的类中,初始化的时候,实例化几个状态的类,然后添加到列表中
public void ConstructFSM()
{
PatorlState patorl=new PatorlState();
ChaseState chase=new ChaseState();
AttackState attack=new AttackState();
AddState(patorl);
AddState(chase);
AddState(attack);
}