游戏AI实现-分层状态机

发布于:2024-12-18 ⋅ 阅读:(201) ⋅ 点赞:(0)

分层状态机是一种特殊类型的有限状态机,它允许我们将几个在输入或更新逻辑方面相似的状态组合在一起,以便可以在多个状态中使用一个输入,而无需重复代码。他们使用多个子状态继承自的一些 “通用” 状态来共享行为。例如下图中的状态机:

从一个大的状态机开始,将类似行为的状态封装到子状态机中,子状态机可以看作一个状态,子状态机的子状态可以切换到不同子状态机的子状态机。

实现代码:

状态基类:

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 公司

(PDF格式)使用多逻辑和继承实现分层状态机 (HFSM) (researchgate.net)


网站公告

今日签到

点亮在社区的每一天
去签到