Unity中狀態機模式的簡單封裝
阿新 • • 發佈:2019-02-18
遊戲中的邏輯少不了用狀態機。但是面對複雜的狀態(比如戰鬥角色控制,複雜的UI狀態控制等),用狀態機模式是最合適不過的了。結合C#的特點,我對狀態機模式進行了簡化。
完善的fsm:
public abstract class FSM<T> : MonoBehaviour { static System.Action FuncVoid = () => {}; protected static System.Action<T, object> DefaultTrigger = (t, p) => { }; public State state { get; private set; } public string Name; public void SetDefaultTrigger(System.Action<T, object> _SetTrigger) { DefaultTrigger = _SetTrigger; } public class State { public System.Action OnEnter = FuncVoid; public System.Action OnTick = FuncVoid; public System.Action OnExit = FuncVoid; public System.Action<T, object> SetTrigger = DefaultTrigger; public string Name { get; private set; } public State(string name) { Name = name; } } public void setState(State _state) { state.OnExit(); state = _state; Name = state.Name; state.OnEnter(); } protected void doStart() { if (state == null) { state = initState(); state.OnEnter(); StartCoroutine(OnTick()); } } IEnumerator OnTick() { while (true) { state.OnTick(); yield return null; } } protected abstract State initState(); }
下面是個例子:
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;
}
}