状态机模板FSM
背景
为什么需要状态机,试想一下,在肉鸽玩法中,玩家角色如果被冻结的话,应该阻止其移动,可以加个是否冻结中的bool字段 _isFroze,然后在移动逻辑中if判断。如果中了混乱的buff,左右移动方向交换,我们可以再加个字段再if判断,但是随着需求的增加,字段变多,管理起来就会变得混乱,如果再遇上需求变更,返工,屎山就这样堆起来了。
但是每次使用状态机都得手动实现一次状态机,不说每个人的实现方式不一样,就使用方法也不一样,这已经使多人协作开发很痛苦了。为了统一状态机机制,也为了提高创建和使用状态机的便利性,提高代码复用性,框架提出了状态机模板,封装了状态机的使用方法的内部实现逻辑,达到即装即用的高效便利目的。
状态机模板用于对象内部,所以也称为私有状态机。外部不需要也不关心内部状态的切换,可以认为,该状态机仅作为持有者的一个组件。所以持有者需要自行完成状态机的内置生命周期函数的转发。
使用
定义状态枚举
1 2 3 4 5 6 7
|
public enum Def { Idle, Walking, }
|
创建和初始化状态机
(以角色的移动状态机举例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class Holder { private FsmComponent<Holder, Def> _fsm = new FsmComponent<Holder, Def>(this); private void InitFsm() { _fsm.SetFsm(new Dictionary<Def, IFsmComponentState<Holder>>() { {Def.Idle, new IdleState()}, {Def.Walking, new WalkingState()} }); } private void Update() { _fsmMovement.OnUpdate(); } public void OnExitIdleState() { } }
|
创建各状态对应的状态类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class IdleState : IFsmComponentState<Holder> {
public void OnEnter(Holder owner, params object[] objs) { owner.animator.Play(闲置时的循环动画); } public void OnUpdate(Holder owner, params object[] objs) { } public void OnExit(Holder owner) { owner.OnExitIdleState(); } }
public class WalkingState : IFsmComponentState<Holder> { }
|
使用状态机
1 2 3 4 5 6 7 8 9
|
_fsm.ChangeFsmState(Def.Idle);
if(_fsm.IsState(Def.Idle)) { }
|
注意事项
- 为避免出现不可预测的问题,状态机初始化时,设置了状态字典 SetFsm() 后,并不会设置初始状态,此时处于空状态,需要手动设置初始状态 ChangeFsmState()。