diff options
Diffstat (limited to 'WorldlineKeepers/Assets/Scripts/Tools/Statemachine/AsyncStatemachine.cs')
-rw-r--r-- | WorldlineKeepers/Assets/Scripts/Tools/Statemachine/AsyncStatemachine.cs | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/AsyncStatemachine.cs b/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/AsyncStatemachine.cs new file mode 100644 index 0000000..605f737 --- /dev/null +++ b/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/AsyncStatemachine.cs @@ -0,0 +1,254 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using MEC; + +namespace WK +{ + + /// <summary> + /// 公共状态机 + /// </summary> + public class AsyncStatemachine + { + + public delegate void LoadStateComplete(); + + public abstract class State + { + public AsyncStatemachine owner; + public int stateID; // stateID可以是string.GetHashCode() 以提供扩展性 + public abstract IEnumerator<float> OnStart(); + public abstract IEnumerator<float> OnEnd(); + public abstract void OnUpdate(float deltaTime); + } + + public const int NULL_STATE_ID = -1; + public const float COROUINT_DELTIME = 0.01f; + + private Dictionary<int/*stateID*/, State> allState = new Dictionary<int, State>(); + private int curStateID = NULL_STATE_ID; + private int stateIDDistributor = 0; + // 在状态切换完成前为false,不能进行update + private bool isUpdateActive = false; + + /// <summary> + /// 添加状态,并返回在状态机中的ID + /// </summary> + /// <param name="newState"></param> + /// <returns></returns> + public int RegisterState(State newState) + { + if (newState == null) + return NULL_STATE_ID; + if (stateIDDistributor + 1 >= int.MaxValue) + { + Debug.LogError("状态机添加状态失败,此状态机中添加的状态过多"); + return NULL_STATE_ID; + } + ++stateIDDistributor; + if (!allState.ContainsKey(stateIDDistributor)) + { + newState.owner = this; + newState.stateID = stateIDDistributor; + allState.Add(stateIDDistributor, newState); + return stateIDDistributor; + } + Debug.LogError("状态机添加状态失败,状态已经存在"); + return NULL_STATE_ID; + } + + public bool RemoveState(State state) + { + if (state != null) + { + return RemoveState(state.stateID); + } + Debug.LogError("状态机删除状态失败,状态为空"); + return false; + } + + public bool RemoveState(int stateID) + { + if (allState.ContainsKey(stateID)) + { + allState.Remove(stateID); + return true; + } + Debug.LogError("状态机删除状态失败,该状态不存在,stateID = " + stateID); + return false; + } + + /// <summary> + /// 开始运行状态机 + /// </summary> + /// <param name="stateID"></param> + /// <returns></returns> + public bool Start(int stateID) + { + if (!HasBegin()) + { + ForceGotoState(stateID); + return true; + } + return false; + } + + /// <summary> + /// 结束状态机 + /// </summary> + /// <returns></returns> + public bool Stop() + { + if (HasBegin()) + { + ForceGotoState(NULL_STATE_ID); + return true; + } + return false; + } + + /// <summary> + /// 更新状态机 + /// </summary> + /// <param name="deltaTime"></param> + public void Update(float deltaTime) + { + if (HasBegin()) + { + UpdateState(curStateID, deltaTime); + } + } + + public bool GotoState(int stateID, bool skipStartFunc = false, bool bForce = false, LoadStateComplete callback = null) + { + if (HasBegin()) + return ForceGotoState(stateID, skipStartFunc, bForce, callback); + return false; + } + + public bool ForceGotoState(int nextStateID, bool skipStartFunc = false, bool bForce = false, LoadStateComplete callback = null) + { + if (curStateID != nextStateID || bForce) + { + Timing.Instance.RunCoroutineOnInstance(AyncForceGotoState(nextStateID, skipStartFunc, callback)); + return true; + } + if (callback != null) + callback(); + return false; + } + + /// <summary> + /// 异步的切换到某个状态 + /// </summary> + /// <returns></returns> + private IEnumerator<float> AyncForceGotoState(int nextStateID, bool skipStartFunc = false, LoadStateComplete callback = null) + { + isUpdateActive = false; + CoroutineHandle handle = Timing.RunCoroutine(EndState(curStateID)); + while (handle.IsValid) + { + yield return Timing.WaitForSeconds(COROUINT_DELTIME); + } + curStateID = nextStateID; + if (!skipStartFunc) + { + CoroutineHandle handle2 = Timing.RunCoroutine(StartState(curStateID)); + while (handle2.IsValid) + { + yield return Timing.WaitForSeconds(COROUINT_DELTIME); + } + } + if (callback != null) + callback(); + isUpdateActive = true; + } + + public int GetCurStateID() + { + return curStateID; + } + + public bool HasBegin() + { + if (curStateID != NULL_STATE_ID && allState.ContainsKey(curStateID)) + return true; + return false; + } + + public bool IsInState(int stateID) + { + if (HasBegin()) + { + return curStateID == stateID; + } + return false; + } + + public State GetState(int stateID) + { + if (allState.ContainsKey(stateID)) + { + return allState[stateID]; + } + return null; + } + + public void Clean() + { + allState.Clear(); + curStateID = NULL_STATE_ID; + stateIDDistributor = 0; + } + + public void ResetCurState() + { + curStateID = NULL_STATE_ID; + } + + private IEnumerator<float> StartState(int stateID) + { + if (HasBegin()) + { + State state = GetState(stateID); + if (state != null) + { + CoroutineHandle handle = Timing.RunCoroutine(state.OnStart()); + while (handle.IsValid) + { + yield return Timing.WaitForSeconds(COROUINT_DELTIME); + } + } + } + } + + private IEnumerator<float> EndState(int stateID) + { + if (HasBegin()) + { + State state = GetState(stateID); + if (state != null) + { + CoroutineHandle handle = Timing.RunCoroutine(state.OnEnd()); + while (handle.IsValid) + { + yield return Timing.WaitForSeconds(COROUINT_DELTIME); + } + } + } + } + + private void UpdateState(int stateID, float deltaTime) + { + if (HasBegin()) + { + State state = GetState(stateID); + if (state != null) + state.OnUpdate(deltaTime); + } + } + + } + +} |