Unity中状态机模式的简单封装
发表于2018-10-22
游戏中的逻辑需要用到状态机,但是面对复杂的状态(比如战斗角色控制,复杂的UI状态控制等),用状态机模式是最合适不过的了。结合C#的特点,下面就针对状态机模式给大家做些简单介绍。举例如下:
public abstract class FSMManager<T> { public State current { get; protected set; } public abstract void Start(); public class State { private string name; public System.Action OnEnter = FuncVoid; public System.Action OnTick = FuncVoid; public System.Action OnExit = FuncVoid; public System.Action<T, object[]> SetTrigger = FuncVoid2; } public static void FuncVoid() { } public static void FuncVoid2(T type, object[] ps) { } public void SetTrigger(T type, Object[] ps = null) { current.SetTrigger(type, ps); } public void SetState(State state) { current.OnExit(); current = state; current.OnEnter(); } public void OnTick() { current.OnTick(); } }
使用:
public class MyFSM : FSMManager<MyFSM.Type> { public enum Type { Type1, Type2, Typ3 } public int count = 0; public State state1, state2; public MyFSM() { current = state1; } public override void Start() { current = state1; state1.OnEnter(); } }
public string test1= "111", test2 = "222"; public MyFSM fsm; [Test] public void NewEditModeTestSimplePasses() { // Use the Assert class to test conditions. fsm = new MyFSM() { state1 = new FSMManager<MyFSM.Type>.State() { OnEnter = delegate { Debug.Log("===>> " + fsm.count); if (fsm.count++ < 2) { fsm.SetState(fsm.state1); } else { fsm.SetState(fsm.state2); } }, }, state2 = new FSMManager<MyFSM.Type>.State() { OnEnter = delegate { Debug.Log("===>>>" + test2); } }, }; fsm.Start(); }
加深大家对状态机模式的理解,再通过一个例子给大家做讲解。
代码如下:
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public abstract class FSM<T> : MonoBehaviour { static void FuncVoid() { } static void FuncVoid2(T type, object[] ps) { } protected State state; public class State { public System.Action OnEnter = FuncVoid; public System.Action OnTick = FuncVoid; public System.Action OnExit = FuncVoid; public System.Action<T, object[]> SetTrigger = FuncVoid2; public int param; } public void setState(State _state) { state.OnExit(); state = _state; state.OnEnter(); } protected void doStart(State ss) { state = initState(); StartCoroutine(OnTick()); } IEnumerator OnTick() { while (true) { state.OnTick(); yield return null; } } protected abstract State initState(); } public class UILoading : FSM<UILoading.MyEvent> { public enum MyEvent { Trig1, Trig2, Trig3 } State state1, state2; public Animator anim; public Button btnLocal; public Button btnOnline; public Button btnOptions; void printOK(string who) { Debug.LogError("=====OKOKOK!! " + who); } private void Awake() { doStart(state1); btnLocal.onClick.AddListener(delegate { state.SetTrigger(MyEvent.Trig1, null); }); btnOnline.onClick.AddListener(delegate { state.SetTrigger(MyEvent.Trig2, null); }); anim.StopPlayback(); btnOptions.onClick.AddListener(delegate { anim.StartPlayback(); Debug.LogError("======"); }); } protected override State initState() { state1 = new State() { param = 7, OnEnter = delegate { state1.param = 5; printOK("state1"); }, OnTick = delegate { state1.param--; Debug.LogError("State1 tick : " + state1.param); if (state1.param <= 0) { setState(state2); } }, OnExit = delegate { Debug.LogError("<<< State1 exit"); } }; state2 = new State() { OnEnter = delegate { printOK("state2"); }, OnTick = delegate { Debug.LogError("state2 Tick"); }, OnExit = delegate { Debug.LogError("<<< State2 exit"); }, SetTrigger = (e, ps) => { switch (e) { case MyEvent.Trig1: setState(state1); break; case MyEvent.Trig2: printOK("!!!!!"); break; } } }; return state1; } }