diff options
Diffstat (limited to 'WorldlineKeepers/Assets/Scripts/Tools/Statemachine')
4 files changed, 525 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); + } + } + + } + +} diff --git a/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/AsyncStatemachine.cs.meta b/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/AsyncStatemachine.cs.meta new file mode 100644 index 0000000..e2b8d49 --- /dev/null +++ b/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/AsyncStatemachine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c43b283f086a24140b0e6e6e0e9efbef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/Statemachine.cs b/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/Statemachine.cs new file mode 100644 index 0000000..56dd28b --- /dev/null +++ b/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/Statemachine.cs @@ -0,0 +1,249 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using Newtonsoft.Json.Utilities; + +namespace WK +{ + + public class BaseStateMachine + { + public delegate void StateEvent(); + public delegate bool StateFinishChecker(); + public class State + { + public BaseStateMachine owner; + public int stateId; + + public virtual void BeginState() + { + //reserve function + } + public virtual void EndState() + { + //reserve function + } + //时间单位是毫秒 + public virtual bool UpdateState(int deltaTimeMS) + { + return true; + } + } + + private Dictionary<int/*state id*/, State> stateDic = new Dictionary<int/*state id*/, State>(); + private int currentStateId = -1; + private int stateIdDistributor = 0; + + private int recordLastStateId = -1; + + public int RegisterState(State newState) + { + if (newState != null) + { + if (stateIdDistributor + 1 > int.MaxValue) + { + Debug.LogError("状态机添加状态失败:一个状态机中添加了过多的状态!"); + return -1; + } + + stateIdDistributor++; + if (!stateDic.ContainsKey(stateIdDistributor)) + { + stateDic.Add(stateIdDistributor, newState); + newState.owner = this; + newState.stateId = stateIdDistributor; + return stateIdDistributor; + } + } + Debug.LogError("状态机添加状态失败:无效的新状态或新状态已存在!"); + return -1; + } + + public bool RemoveState(State toBeRemoveState) + { + if (toBeRemoveState != null) + return RemoveState(toBeRemoveState.stateId); + Debug.LogError("状态机删除状态失败:无效的状态!"); + return false; + } + + public bool RemoveState(int stateId) + { + if (stateDic.ContainsKey(stateId)) + { + stateDic.Remove(stateId); + return true; + } + Debug.LogError("状态机删除状态失败:该状态不存在!"); + return false; + } + + public bool Begin(int beginStateId) + { + if (!HasBegin()) + { + ForceGoToState(beginStateId, false); + return true; + } + + return false; + } + + public bool Stop() + { + if (HasBegin()) + { + ForceGoToState(-1); + return true; + } + + return false; + } + + public bool GoToState(int newStateId, bool skipBeginFunc = false, bool forceLoad = false) + { + if (HasBegin()) + { + return ForceGoToState(newStateId, skipBeginFunc, forceLoad); + } + return false; + } + + private bool ForceGoToState(int newStateId) + { + return ForceGoToState(newStateId, false); + } + private bool ForceGoToState(int newStateId, bool skipBeginFunc, bool bForce = false) + { + if (currentStateId != newStateId || bForce) + { + OnStateEnd(currentStateId); + currentStateId = newStateId; + if (!skipBeginFunc) OnStateBegin(currentStateId); + return true; + } + else + { + return false; + } + } + + /// <summary> + /// + /// </summary> + /// <param name="filterState">剔除的state</param> + public void RecordCurrentState(int filterState) + { + if (currentStateId != filterState) + { + recordLastStateId = currentStateId; + } + } + + public void ClearRecordState() + { + recordLastStateId = -1; + } + + public void RevertToRecordState(int fallbackState, bool skipBeginFunc, bool bForce = false) + { + if (recordLastStateId >= 0 && stateDic.ContainsKey(recordLastStateId)) + { + GoToState(recordLastStateId, skipBeginFunc, bForce); + } + else if (fallbackState >= 0 && stateDic.ContainsKey(fallbackState)) + { + GoToState(fallbackState, skipBeginFunc, bForce); + } + } + + + //时间单位是毫秒 + public void OnUpdate(int mSecDeltaTime) + { + if (HasBegin()) + { + UpdateState(currentStateId, mSecDeltaTime); + } + } + + public bool HasBegin() + { + if (currentStateId != -1 && stateDic.ContainsKey(currentStateId)) + return true; + else + return false; + } + + public bool IsInState(int stateId) + { + if (HasBegin()) + { + return currentStateId == stateId; + } + return false; + } + + + public int GetCurrentStateId() + { + return currentStateId; + } + + public State GetState(int stateId) + { + if (stateDic.ContainsKey(stateId)) + { + return stateDic[stateId]; + } + return null; + } + + public void Clean() + { + stateDic.Clear(); + currentStateId = -1; + stateIdDistributor = 0; + recordLastStateId = -1; + } + + /// <summary> + /// 重置当前状态(置为-1) + /// </summary> + public void ResetCurrentState() + { + currentStateId = -1; + } + + private void OnStateBegin(int stateId) + { + if (HasBegin()) + { + State state = GetState(stateId); + if (state != null) + state.BeginState(); + } + } + + private void OnStateEnd(int stateId) + { + if (HasBegin()) + { + State state = GetState(stateId); + if (state != null) + state.EndState(); + } + } + //时间单位是毫秒 + private void UpdateState(int stateId, int mSecDeltaTime) + { + if (HasBegin()) + { + State state = GetState(stateId); + if (state != null) + state.UpdateState(mSecDeltaTime); + } + } + } + +}
\ No newline at end of file diff --git a/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/Statemachine.cs.meta b/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/Statemachine.cs.meta new file mode 100644 index 0000000..1f9dc33 --- /dev/null +++ b/WorldlineKeepers/Assets/Scripts/Tools/Statemachine/Statemachine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 740b9ccdbc7196546acfadecbcbd71f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |