Unity中状态机模式的简单封装

发表于2018-10-22
评论0 4.7k浏览
游戏中的逻辑需要用到状态机,但是面对复杂的状态(比如战斗角色控制,复杂的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;
    }
}

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引