using System.Collections; using System.Collections.Generic; using UnityEngine; using MovementEffects; namespace WK { /// /// 公共状态机 /// public class AsyncStatemachine { public delegate void LoadStateComplete(); public abstract class State { public AsyncStatemachine owner; public int stateID; // stateID可以是string.GetHashCode() 以提供扩展性 public abstract IEnumerator OnStart(); public abstract IEnumerator OnEnd(); public abstract void OnUpdate(float deltaTime); } public const int NULL_STATE_ID = -1; public const float COROUINT_DELTIME = 0.01f; private Dictionary allState = new Dictionary(); private int curStateID = NULL_STATE_ID; private int stateIDDistributor = 0; // 在状态切换完成前为false,不能进行update private bool isUpdateActive = false; /// /// 添加状态,并返回在状态机中的ID /// /// /// public int RegisterState(State newState) { if (newState == null) return NULL_STATE_ID; if (stateIDDistributor + 1 >= int.MaxValue) { LogHelper.LogError("状态机添加状态失败,此状态机中添加的状态过多"); return NULL_STATE_ID; } ++stateIDDistributor; if (!allState.ContainsKey(stateIDDistributor)) { newState.owner = this; newState.stateID = stateIDDistributor; allState.Add(stateIDDistributor, newState); return stateIDDistributor; } LogHelper.LogError("状态机添加状态失败,状态已经存在"); return NULL_STATE_ID; } public bool RemoveState(State state) { if (state != null) { return RemoveState(state.stateID); } LogHelper.LogError("状态机删除状态失败,状态为空"); return false; } public bool RemoveState(int stateID) { if (allState.ContainsKey(stateID)) { allState.Remove(stateID); return true; } LogHelper.LogError("状态机删除状态失败,该状态不存在,stateID = " + stateID); return false; } /// /// 开始运行状态机 /// /// /// public bool Start(int stateID) { if (!HasBegin()) { ForceGotoState(stateID); return true; } return false; } /// /// 结束状态机 /// /// public bool Stop() { if (HasBegin()) { ForceGotoState(NULL_STATE_ID); return true; } return false; } /// /// 更新状态机 /// /// 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; } /// /// 异步的切换到某个状态 /// /// private IEnumerator AyncForceGotoState(int nextStateID, bool skipStartFunc = false, LoadStateComplete callback = null) { isUpdateActive = false; CoroutineHandle handle = Timing.RunCoroutine(EndState(curStateID)); while (handle.IsRunning) { yield return Timing.WaitForSeconds(COROUINT_DELTIME); } curStateID = nextStateID; if (!skipStartFunc) { CoroutineHandle handle2 = Timing.RunCoroutine(StartState(curStateID)); while (handle2.IsRunning) { 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 StartState(int stateID) { if (HasBegin()) { State state = GetState(stateID); if (state != null) { CoroutineHandle handle = Timing.RunCoroutine(state.OnStart()); while (handle.IsRunning) { yield return Timing.WaitForSeconds(COROUINT_DELTIME); } } } } private IEnumerator EndState(int stateID) { if (HasBegin()) { State state = GetState(stateID); if (state != null) { CoroutineHandle handle = Timing.RunCoroutine(state.OnEnd()); while (handle.IsRunning) { 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); } } } }