学到了凉鞋大佬的FSM简易写法。
今天在编写2024CUSGA的作品的时候,用到了刚学到的FSM状态机的新的写法,很简单,但是也算是五脏俱全了。
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
| using System; using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine;
public interface IState { void Enter(); void Update(); void FixedUpdate(); void Exit(); }
public class CustomState : IState { private Action mOnEnter; private Action mOnUpdate; private Action mOnFixedUpdate; private Action mOnExit; public CustomState OnEnter(Action OnEnter) { mOnEnter = OnEnter; return this; } public CustomState OnUpdate(Action OnUpdate) { mOnUpdate = OnUpdate; return this; }
public CustomState OnFixedUpdate(Action OnFixedUpdate) { mOnFixedUpdate = OnFixedUpdate; return this; }
public CustomState OnExit(Action OnExit) { mOnExit = OnExit; return this; }
public void Enter() { mOnEnter?.Invoke(); } public void Update() { mOnUpdate?.Invoke(); } public void FixedUpdate() { mOnFixedUpdate?.Invoke(); } public void Exit() { mOnExit?.Invoke(); }
}
public class FSM<T> { public Dictionary<T,IState> mStates = new Dictionary<T,IState>();
public CustomState State(T t) { if (mStates.ContainsKey(t)) { return mStates[t] as CustomState; }
var state = new CustomState();
mStates.Add(t, state);
return state; }
private IState mCurrentState; private T mCurrentStateId;
public IState CurrentState => mCurrentState; public T CurrentStateId => mCurrentStateId;
public void ChangeState(T t) { if(mStates.TryGetValue(t, out var state)) { if(mCurrentState != null) { mCurrentState.Exit(); mCurrentState = state; mCurrentStateId = t; mCurrentState.Enter(); } } }
public void StartState(T t) { if(mStates.TryGetValue(t,out var state)) { mCurrentState = state; mCurrentStateId = t; state.Enter(); } }
public void FixedUpdate() { mCurrentState?.FixedUpdate(); }
public void Update() { mCurrentState?.Update(); }
public void Clear() { mCurrentState = null; mCurrentStateId = default; mStates.Clear(); } }
public class StateExample { public enum States { A, B, C }
void Example() { var fsm=new FSM<States>(); fsm.State(States.A) .OnEnter(() => { }) .OnUpdate(() => { }) .OnFixedUpdate(() => { }) .OnExit(() => { });
fsm.StartState(States.A); fsm.ChangeState(States.B); } }
|
也能处理物理层面的改变,毕竟是有FixedUpdate在的。
在使用了两天之后,我发现这个FSM的写法确实非常的清楚,能够看出每个代码的使用结果。就好像我在写的实例程序一样,只要在程序的开头写上这么一段就能获取到整个状态的变化,虽然看着比较多,但是代码辨识度很高。
其实每一个FSM的写法重点都在于怎么把方法传进状态机,并且调用起来非常简单,除了这一种写法之外,还有一种写法是在各个函数的的构造函数中传入FSM,当时相比于那种方式,这种方式的泛型很明显更加自由,我会在下一篇博客写到另一个状态机的写法。