Unity有限状态机(代码层)

FSM有限状态机

一个角色 简单分为 待机 移动 攻击 受击等 状态

每个状态都需要更新 和 改变,当前状态中 每一帧 都需要更新位置、检测玩家的案件等这些信息

还有一个人机交互,比如 监听 玩家是否对其发送了 指令(攻击 受击),如果监听发生,需要从一个状态切换到另一个状态

StartGame、MainScene、GameScene、GameOverScene等,也可以使用有限状态机实现

每个状态 包含

  1. 初始化状态(给角色添加状态对象时出发,数据准备) Awake
  2. 进入状态(播放动画 获取数据等)Start
  3. 执行状态(数据更新 人机交互等)Update
  4. 结束状态(对结束的逻辑进行处理,数据释放等)Destroy

应用场景

  • 游戏敌人AI
  • 需要根据不同状态进行改变,有不同行为。
  • 如果某个类需要根据成员变量的当前值改变自身行为,需要大量的判断条件时,可以使用状态模式。

优缺点

优点

  • 将状态分离,单一职责原则
  • 简化条件的判断

缺点

  • 实现过于繁琐
  • 类数量过多,容易造成系统复杂

代码实现

Manager类

public class PlayerStateManager : MonoBehaviour
{
    private Dictionary<Type, PlayerStateBase> _states = new Dictionary<Type, PlayerStateBase>();
    private PlayerStateBase _currentState;
    private void Awake()
    {
        AddState<PlayerStateIdle>();
        AddState<PlayerStateRun> ();
        AddState<PlayerStateAttack1>();
        AddState<PlayerStateAttack2>();
        AddState<PlayerStateAttack3>();
        AddState<PlayerStateJump>();
    }

    private void Start()
    {
        ChangeState<PlayerStateIdle>();
    }

    /// <summary>
    /// 将指定状态注册到字典中
    /// </summary>
    /// <typeparam name="T"></typeparam>
    private void AddState<T>() where T : PlayerStateBase
    {
        PlayerStateBase state = gameObject.AddComponent<T>();
        state.OnInit();
        _states.Add(typeof(T), state);
    }

    /// <summary>
    /// 切换状态
    /// </summary>
    public void ChangeState<T>() where T : PlayerStateBase
    {
        if (_currentState != null)
        {
            _currentState.OnExit();
        }
        _currentState = _states[typeof(T)];
        _currentState.OnEnter();
    }

    private void Update()
    {
        if (_currentState != null)
        {
            _currentState.OnExcute();
        }
    }
}

StateBase类

public class PlayerStateBase : MonoBehaviour
{
    // 动画切换
    protected Animator Ani;
    protected string AniName;
    protected PlayerStateManager Manager;
    protected Rigidbody Rig;
    
    public virtual void OnInit()
    { 
        Ani = GetComponent<Animator>();
        Manager = GetComponent<PlayerStateManager>();
        Rig = GetComponent<Rigidbody>();
    }

    public virtual void OnEnter()
    {
    }

    public virtual void OnExcute()
    {
    }

    public virtual void OnExit()
    {
    }
}

普通类

public class PlayerStateIdle : PlayerStateBase
{
    public override void OnInit()
    {
        base.OnInit();
        AniName = "Idle";
    }

    public override void OnEnter()
    {
        Ani.SetInteger("state", 0);
    }

    public override void OnExcute()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Manager.ChangeState<PlayerStateAttack1>();
            return;
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            Manager.ChangeState<PlayerStateJump>();
            return;
        }
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector3 dir = new Vector3(h, 0, v);
        if (dir != Vector3.zero)
        {
            Manager.ChangeState<PlayerStateRun>();
        }
    }
}
上一篇
下一篇