1. 状态机概述
在角色的生成中,由于事件的不同,动作的不同,角色会处于不同的状态中。例如对战冒险游戏,面临Boss的攻击,角色会受到例如中毒,恐惧等Debuff效果,若单纯的在一个脚本中使用if等语句进行事件处理,往往会比较冗杂,程序出现bug后也无法及时排查出问题。
状态机此时就是一个很好解决上述问题的方式。例如在玩家移动过程中,此时的状态为移动状态。设定好不同状态之后。只需要相应的判定条件即可进入状态执行对应事件。
2. 初始化状态机
2.1. PlayerStateMachine
public class PlayerStateMachine : MonoBehavior
{public PlayerState currentState {get; privet set;} //申明一个状态public void Initialize(PlayerState _startState){currentState = _startState; //初始化状态currentState.Enter(); //进入状态}public void ChangeState(PlayerState _newState){currentState.Exit(); // 退出当前状态currentState = _newState;currentState.Enter();}
}
定义PlayerStateMachine类的作用类似于一个机器,将player的各个状态进行调配,例如状态机所含Initialize方法初始化状态,以及改变当前状态。
在改变当前状态时,先要执行状态中的Exit()方法,为后续动作增加了更大的可能性。
2.2. PlayerState
public class PlayerState
{protected PlayerStateMachine stateMachine;protected Player player; protected string animatorName;public PlayerState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) // 构造函数,将上述变量传入{this.player = _player; //获取player,也可以调用player中的参数 this.stateMachine = _stateMachine;this.animatorName = _animBoolName; //动画参数的名字}public virtual void Enter(){rb = player.rb;player.anim.SetBool(animatorName,true);}public virtual void Update(){xInput = Input.GetAxisRaw("Horizontal"); //任意状态都可以持续调用}public virtual void Exit(){player.anim.SetBool(animatorName,false); //退出当前状态时,将动画参数设置为false}}
与其说PlayerState是各个状态的模板,更不如说是各状态共有的特征。简化了代码,各状态所需要的初始化在PlayerState类中以及设定好了,在后续编写状态代码时只需简单的base.Update();即可。
在父类状态中想要一直持续调用的事件,在后续也可以传导给子类状态,例如想要一直获取角色在水平轴上的Input.GetAxisRaw。通过继承的方式,子类无论在何种状态,都在持续调用这段代码。
2.3. Player
public class Player: MonoBehaviour
{//声明组件以及所需要的状态public Rigidbody2D rb {get;private set;}public Animator anim {get;private set;}public PlayerStateMachine stateMachine {get;private set}public PlayerIdleState idleState {get;private set}private void Awake() //初始化该player所拥有的状态与状态机,在实例化对象之前加载{stateMachine = new PlayerStateMachine();idleState = new PlayerIdleState(this,StateMachine,"Idle");}private void Start(){anim = GetComponentInChildren<Animator>();rb = GetComponent<Rigidbody2D>();StateMachine.Initialize(idleState); #初始化idle状态}private void Update(){StateMachine.currentState.Update(); //通过player的持续调用,持续调用当前状态的Update}
}
Player是应用的我们角色的脚本,实现为player声明好对应的状态机,更好的去初始化与改变当前状态。
通过Unity引擎自带的Update方法,进一步实现每个状态中我们所编写的Update方法。
3. 状态机的应用
3.1. Idle状态
public class PlayerIdleState : PlayerGroundedState
{public PlayerIdleState(Player _player, PlayerStateMachine _stateMachine, string _animBoolName) : base(_player, _stateMachine, _animBoolName){}public override void Enter(){base.Enter();}public override void Exit(){base.Exit();}public override void Update() //持续调用{base.Update();if (xInput != 0){stateMachine.ChangeState(player.moveState);}}
}