分层状态机是一种特殊类型的有限状态机,它允许我们将几个在输入或更新逻辑方面相似的状态组合在一起,以便可以在多个状态中使用一个输入,而无需重复代码。他们使用多个子状态继承自的一些 “通用” 状态来共享行为。例如下图中的状态机:
从一个大的状态机开始,将类似行为的状态封装到子状态机中,子状态机可以看作一个状态,子状态机的子状态可以切换到不同子状态机的子状态机。
实现代码:
状态基类:
public interface IState
{
void onEntry();
void update();
void onExit();
Transition[] getTransitions();
void AddTransition(Transition transition);
}
状态机:
public class HierarchicalStateMachine
{
protected Dictionary<StateEnum,IState> states;
public HierarchicalStateMachine(IState initState)
{
this.initialState = initState;
this.states = new Dictionary<StateEnum,IState>();
}
//初始状态
protected IState initialState;
//状态机的当前状态
protected IState currentState = null;
public void AddState(StateEnum stateEnum , IState state)
{
this.states[stateEnum] = state;
}
public virtual void update()
{
//如果当前状态是null,则使用initialSate
if(currentState == null) {
currentState = this.initialState;
currentState.onEntry();
}
Transition[] transitions = currentState.getTransitions();
//在当前状态中查找一个过渡
Transition transition = null;
foreach(Transition t in transitions)
{
if (t.isTriggered())
{
if(transition == null || transition?.getLevel() < t.getLevel())
{
transition = t;
}
}
}
if(transition != null)
{
StateEnum se = transition.getTargetState();
IState targetState = null;
if(this.states.TryGetValue(se, out targetState))
{
currentState.onExit();
targetState.onEntry();
//设置当前状态
currentState = targetState;
}
else
{
//如果没有找到,那么说明状态在子层
currentState.update();
}
}
else
{
currentState.update();
}
transition = null;
}
}
子状态机:
public class SubMachineState : HierarchicalStateMachine, IState
{
public SubMachineState(IState initState) : base(initState)
{
this.initialState = initState;
transitions = new List<Transition>();
}
List<Transition> transitions;
//子状态机进入事件
public virtual void onEntry()
{
}
//子状态机退出事件
public virtual void onExit()
{
}
public void AddTransition(Transition transition)
{
transitions.Add(transition);
}
public Transition[] getTransitions()
{
return this.transitions.ToArray();
}
}
过渡基类:
public class Transition
{
public virtual int getLevel()
{
return 0;
}
public virtual bool isTriggered()
{
return false;
}
public virtual StateEnum getTargetState()
{
return StateEnum.None;
}
}
状态枚举:
public enum StateEnum
{
None,
}
应用:
实现如下图所示的 HFSM
增加新的状态枚举:
public enum StateEnum
{
None,
idle,
walk,
run,
jump,
doublejump,
movementSubFSM,
jumpSubFSM
}
新建过渡类:
public class IdleStateTransition : Transition
{
Player player;
public IdleStateTransition(Player player)
{
this.player = player;
}
public override StateEnum getTargetState()
{
return StateEnum.idle;
}
public override bool isTriggered()
{
if (this.player && (this.player.Speed <= 0f && this.player.Y <= 0))
{
return true;
}
return false;
}
}
public class WalkTransition : Transition
{
Player player;
public override int getLevel()
{
return 1;
}
public WalkTransition(Player player)
{
this.player = player;
}
public override StateEnum getTargetState()
{
return StateEnum.run;
}
public override bool isTriggered()
{
if (this.player && this.player.Speed > 1f)
{
return true;
}
return false;
}
}
public class RunTransition : Transition
{
Player player;
public override int getLevel()
{
return 1;
}
public RunTransition(Player player)
{
this.player = player;
}
public override StateEnum getTargetState()
{
return StateEnum.run;
}
public override bool isTriggered()
{
if (this.player && this.player.Speed > 2.5f)
{
return true;
}
return false;
}
}
public class JumpTransition : Transition
{
Player player;
public override int getLevel()
{
return 2;
}
public JumpTransition(Player player)
{
this.player = player;
}
public override StateEnum getTargetState()
{
return StateEnum.doublejump;
}
public override bool isTriggered()
{
if (this.player && this.player.Y > 2f)
{
return true;
}
return false;
}
}
public class DoubleJumpTransition : Transition
{
Player player;
public override int getLevel()
{
return 2;
}
public DoubleJumpTransition(Player player)
{
this.player = player;
}
public override StateEnum getTargetState()
{
return StateEnum.doublejump;
}
public override bool isTriggered()
{
if (this.player && this.player.Y > 5f)
{
return true;
}
return false;
}
}
public class MovementFSMTransition : Transition
{
Player player;
public override int getLevel()
{
return 1;
}
public MovementFSMTransition(Player player)
{
this.player = player;
}
public override StateEnum getTargetState()
{
return StateEnum.movementSubFSM;
}
public override bool isTriggered()
{
if (this.player && (this.player.Speed > 0f || this.player.Y > 0f))
{
return true;
}
return false;
}
}
public class JumpFSMTransition : Transition
{
Player player;
public override int getLevel()
{
return 2;
}
public JumpFSMTransition(Player player)
{
this.player = player;
}
public override StateEnum getTargetState()
{
return StateEnum.jumpSubFSM;
}
public override bool isTriggered()
{
if (this.player && this.player.Y > 0f)
{
return true;
}
return false;
}
}
新建状态类:
public class IdleState : IState
{
public IdleState()
{
transitions = new List<Transition>();
}
List<Transition> transitions;
public Transition[] getTransitions()
{
return transitions.ToArray();
}
public void onEntry()
{
Debug.Log("进入空闲状态");
}
public void onExit()
{
Debug.Log("退出空闲状态");
}
public void update()
{
Debug.Log("空闲状态。。。");
}
public void AddTransition(Transition transition)
{
this.transitions.Add(transition);
}
public IState getState(StateEnum se)
{
return null;
}
}
public class WalkState : IState
{
public WalkState()
{
transitions = new List<Transition>();
}
List<Transition> transitions;
public Transition[] getTransitions()
{
return this.transitions.ToArray();
}
public void onEntry()
{
Debug.Log("进入走状态");
}
public void onExit()
{
Debug.Log("退出走状态");
}
public void update()
{
Debug.Log("走状态。。。");
}
public void AddTransition(Transition transition)
{
this.transitions.Add(transition);
}
public IState getState(StateEnum se)
{
return null;
}
}
public class RunState : IState
{
public RunState()
{
transitions = new List<Transition>();
}
List<Transition> transitions;
public void AddTransition(Transition transition)
{
this.transitions.Add(transition);
}
public Transition[] getTransitions()
{
return this.transitions.ToArray ();
}
public void onEntry()
{
Debug.Log("进入跑状态");
}
public void onExit()
{
Debug.Log("退出跑状态");
}
public void update()
{
Debug.Log("跑状态。。。");
}
public IState getState(StateEnum se)
{
return null;
}
}
public class JumpState : IState
{
public JumpState()
{
transitions = new List<Transition>();
}
List<Transition> transitions;
public void AddTransition(Transition transition)
{
this.transitions.Add (transition);
}
public Transition[] getTransitions()
{
return this.transitions.ToArray ();
}
public void onEntry()
{
Debug.Log("进入跳状态");
}
public void onExit()
{
Debug.Log("退出跳状态");
}
public void update()
{
Debug.Log("跳状态。。。");
}
public IState getState(StateEnum se)
{
return null;
}
}
public class DoubleJumpState : IState
{
public DoubleJumpState()
{
transitions = new List<Transition>();
}
List<Transition> transitions;
public void AddTransition(Transition transition)
{
this.transitions.Add(transition);
}
public Transition[] getTransitions()
{
return this.transitions.ToArray();
}
public void onEntry()
{
Debug.Log("进入二段跳状态");
}
public void onExit()
{
Debug.Log("退出二段跳");
}
public void update()
{
Debug.Log("二段跳。。。");
}
public IState getState(StateEnum se)
{
return null;
}
}
新建子状态机类:
public class MovementMachineState : SubMachineState
{
public MovementMachineState(IState initState) : base(initState)
{
}
public override void onEntry()
{
base.onEntry();
}
public override void onExit()
{
base.onExit();
currentState?.onExit();
}
public override void update()
{
base.update();
}
}
public class JumpMachineState : SubMachineState
{
public JumpMachineState(IState initState) : base(initState)
{
}
public override void onEntry()
{
base.onEntry();
}
public override void onExit()
{
base.onExit();
currentState?.onExit();
currentState = null;
}
public override void update()
{
base.update();
}
}
调用:
public void InitHFSM()
{
#region 初始化状态
DoubleJumpState doubleJumpState = new DoubleJumpState();
JumpState jumpState = new JumpState();
RunState runState = new RunState();
WalkState walkState = new WalkState();
IdleState idleState = new IdleState();
JumpMachineState jumpMachineState = new JumpMachineState(jumpState);
MovementMachineState movementMachineState = new MovementMachineState(walkState);
jumpMachineState.AddState(StateEnum.idle, idleState);
jumpMachineState.AddState(StateEnum.jump,jumpState);
jumpMachineState.AddState(StateEnum.doublejump,doubleJumpState);
movementMachineState.AddState(StateEnum.idle,idleState);
movementMachineState.AddState(StateEnum.walk,walkState);
movementMachineState.AddState(StateEnum.run,runState);
movementMachineState.AddState(StateEnum.jumpSubFSM,jumpMachineState);
this.m_HFSM = new HierarchicalStateMachine(idleState);
this.m_HFSM.AddState(StateEnum.idle, idleState);
this.m_HFSM.AddState(StateEnum.movementSubFSM, movementMachineState);
#endregion
#region 初始化过渡
IdleStateTransition idleTransition = new IdleStateTransition(this);
RunTransition runTransition = new RunTransition(this);
DoubleJumpTransition doubleJumpTransition = new DoubleJumpTransition(this);
MovementFSMTransition movementFSMTransition = new MovementFSMTransition(this);
JumpFSMTransition jumpFSMTransition = new JumpFSMTransition(this);
idleState.AddTransition(movementFSMTransition);
movementMachineState.AddTransition(idleTransition);
movementMachineState.AddTransition(jumpFSMTransition);
walkState.AddTransition(idleTransition);
walkState.AddTransition(runTransition);
walkState.AddTransition(jumpFSMTransition);
runState.AddTransition(idleTransition);
runState.AddTransition(movementFSMTransition);
runState.AddTransition(jumpFSMTransition);
jumpMachineState.AddTransition(movementFSMTransition);
jumpMachineState.AddTransition(runTransition);
jumpState.AddTransition(idleTransition);
jumpState.AddTransition(movementFSMTransition);
jumpState.AddTransition(doubleJumpTransition);
doubleJumpState.AddTransition(idleTransition);
#endregion
}
float gravity = 0.98f;
public void UpdateHFSM()
{
this.speed = Mathf.Abs(Input.GetAxis("Horizontal") * 5);
if (Input.GetKey(KeyCode.Space))
{
this.y = 2.5f;
}
if (Input.GetKey(KeyCode.M))
{
this.y = 5.5f;
}
if(this.y > 0)
{
this.y -= gravity * Time.deltaTime;
this.y = Mathf.Max(0, this.y);
}
this.m_HFSM?.update();
}
结果:
参考书籍与链接:
《AI FOR GAMES》
Code Class - Hierarchical State Machines (youtube.com)
Make a hierarchical finite state machine [Unity/C# tutorial] - YouTube
实现分层状态机 (HFSM) - PG Journal (takap-tech.com)
UnityHFSM |com.inspiaaa.unityhfsm |Unity 软件包 (UPM) 下载 |OpenUPM 公司