• Unity2D - 状态机(State Machine)详解


    1. 状态机概述

    在角色的生成中,由于事件的不同,动作的不同,角色会处于不同的状态中。例如对战冒险游戏,面临Boss的攻击,角色会受到例如中毒,恐惧等Debuff效果,若单纯的在一个脚本中使用if等语句进行事件处理,往往会比较冗杂,程序出现bug后也无法及时排查出问题。

    状态机此时就是一个很好解决上述问题的方式。例如在玩家移动过程中,此时的状态为移动状态。设定好不同状态之后。只需要相应的判定条件即可进入状态执行对应事件。

    2. 初始化状态机

    2.1. PlayerStateMachine

    1. public class PlayerStateMachine : MonoBehavior
    2. {
    3. public PlayerState currentState {get; privet set;} //申明一个状态
    4. public void Initialize(PlayerState _startState)
    5. {
    6. currentState = _startState; //初始化状态
    7. currentState.Enter(); //进入状态
    8. }
    9. public void ChangeState(PlayerState _newState)
    10. {
    11. currentState.Exit(); // 退出当前状态
    12. currentState = _newState;
    13. currentState.Enter();
    14. }
    15. }

    定义PlayerStateMachine类的作用类似于一个机器,将player的各个状态进行调配,例如状态机所含Initialize方法初始化状态,以及改变当前状态。

    在改变当前状态时,先要执行状态中的Exit()方法,为后续动作增加了更大的可能性。

    2.2. PlayerState

    1. public class PlayerState
    2. {
    3. protected PlayerStateMachine stateMachine;
    4. protected Player player;
    5. protected string animatorName;
    6. public PlayerState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) // 构造函数,将上述变量传入
    7. {
    8. this.player = _player; //获取player,也可以调用player中的参数
    9. this.stateMachine = _stateMachine;
    10. this.animatorName = _animBoolName; //动画参数的名字
    11. }
    12. public virtual void Enter()
    13. {
    14. rb = player.rb;
    15. player.anim.SetBool(animatorName,true);
    16. }
    17. public virtual void Update()
    18. {
    19. xInput = Input.GetAxisRaw("Horizontal"); //任意状态都可以持续调用
    20. }
    21. public virtual void Exit()
    22. {
    23. player.anim.SetBool(animatorName,false); //退出当前状态时,将动画参数设置为false
    24. }
    25. }

    与其说PlayerState是各个状态的模板,更不如说是各状态共有的特征。简化了代码,各状态所需要的初始化在PlayerState类中以及设定好了,在后续编写状态代码时只需简单的base.Update();即可。

    在父类状态中想要一直持续调用的事件,在后续也可以传导给子类状态,例如想要一直获取角色在水平轴上的Input.GetAxisRaw。通过继承的方式,子类无论在何种状态,都在持续调用这段代码。

    2.3. Player

    1. public class Player: MonoBehaviour
    2. {
    3. //声明组件以及所需要的状态
    4. public Rigidbody2D rb {get;private set;}
    5. public Animator anim {get;private set;}
    6. public PlayerStateMachine stateMachine {get;private set}
    7. public PlayerIdleState idleState {get;private set}
    8. private void Awake() //初始化该player所拥有的状态与状态机,在实例化对象之前加载
    9. {
    10. stateMachine = new PlayerStateMachine();
    11. idleState = new PlayerIdleState(this,StateMachine,"Idle");
    12. }
    13. private void Start()
    14. {
    15. anim = GetComponentInChildren();
    16. rb = GetComponent();
    17. StateMachine.Initialize(idleState); #初始化idle状态
    18. }
    19. private void Update()
    20. {
    21. StateMachine.currentState.Update(); //通过player的持续调用,持续调用当前状态的Update
    22. }
    23. }

    Player是应用的我们角色的脚本,实现为player声明好对应的状态机,更好的去初始化与改变当前状态。

    通过Unity引擎自带的Update方法,进一步实现每个状态中我们所编写的Update方法。

    3. 状态机的应用

    3.1. Idle状态

    1. public class PlayerIdleState : PlayerGroundedState
    2. {
    3. public PlayerIdleState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName)
    4. {
    5. }
    6. public override void Enter()
    7. {
    8. base.Enter();
    9. }
    10. public override void Exit()
    11. {
    12. base.Exit();
    13. }
    14. public override void Update() //持续调用
    15. {
    16. base.Update();
    17. if (xInput != 0)
    18. {
    19. stateMachine.ChangeState(player.moveState);
    20. }
    21. }
    22. }

  • 相关阅读:
    echarts案例之双折线渐变图
    【C++】进阶模板
    MQ面试题
    【Java】三种方案实现 Redis 分布式锁
    深入浅出Java的多线程编程——第一篇
    【自动化测试】基于Selenium + Python的web自动化框架
    MATLAB中Simulink.SimulationOutput用法
    AC自动机小结
    5款宝藏级高效办公软件,升职加薪必备,用一次就爱上
    CCF ChinaSoft 2023 论坛巡礼 | 智能化软件开发和维护论坛
  • 原文地址:https://blog.csdn.net/qq_51222843/article/details/140063054