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);
}
}
}
}