前言
眾所周知,Unity在開發(fā)游戲的時候經(jīng)常用到狀態(tài)機,而通常情況下,我們會使用簡單的枚舉類型設(shè)置狀態(tài),然后通過調(diào)整枚舉,來切換狀態(tài),在簡單情況下是可以的,就像是Unity中Animator切換動畫狀態(tài)就是,直接通過動畫片段的名稱切換。而當(dāng)狀態(tài)很多的時候,直接切換就顯得有些很不安全,而且友好性也不是很好,所以根據(jù)Unity中Animator這種通過條件切換狀態(tài)的架構(gòu),我寫了一個簡單的狀態(tài)機,給大家分享。
外部委托定義
/// <summary>
/// 狀態(tài)內(nèi)部事件委托
/// </summary>
public delegate void StateFunctionEventHandler();
/// <summary>
/// 狀態(tài)條件判斷委托
/// </summary>
public delegate bool StateTranslateEventHandler();
狀態(tài)類
/// <summary>
/// 狀態(tài)類
/// </summary>
public class State {
/// <summary>
/// 狀態(tài)內(nèi)部事件
/// </summary>
public event StateFunctionEventHandler stateFunc;
/// <summary>
/// 狀態(tài)轉(zhuǎn)換事件<目標狀態(tài),切換條件>
/// </summary>
public Dictionary<State,StateTranslateEventHandler> stateTrs;
/// <summary>
/// 狀態(tài)名稱
/// </summary>
/// <value>The name of the state.</value>
public string stateName{get;private set;}
/// <summary>
/// 狀態(tài)運行中
/// </summary>
public bool isRun = false;
/// <summary>
/// 狀態(tài)內(nèi)部事件執(zhí)行間隔時間(毫秒)
/// </summary>
/// <value>The state function delta time.</value>
public int stateFunctionDeltaTime{private get; set;}
/// <summary>
/// 狀態(tài)構(gòu)造
/// </summary>
/// <param name="name">Name.</param>
public State(string name)
{
stateName = name;
stateTrs = new Dictionary<State, StateTranslateEventHandler> ();
stateFunctionDeltaTime = 200;
Thread th = new Thread (Update);
th.Start ();
}
/// <summary>
/// 狀態(tài)內(nèi)部事件執(zhí)行
/// </summary>
public void Update()
{
while(true)
{
if(!isRun)
{
continue;
}
Thread.Sleep (stateFunctionDeltaTime);
if(stateFunc != null)
{
stateFunc();
}
}
}
/// <summary>
/// 注冊切換事件.
/// </summary>
/// <param name="target">目標狀態(tài).</param>
/// <param name="conditional">條件事件.</param>
public void RegisterTranslate(State target, StateTranslateEventHandler conditional)
{
try
{
stateTrs.Add (target, conditional);
}
catch(Exception ex)
{
Debug.LogError(ex.ToString());
}
}
}
狀態(tài)管理類
/// <summary>
/// 狀態(tài)管理
/// </summary>
public class StateController : State {
/// <summary>
/// 狀態(tài)管理構(gòu)造
/// </summary>
/// <param name="name">Name.</param>
public StateController(string name) : base(name)
{
states = new Dictionary<string, State> ();
stateparams = new Dictionary<string, object> ();
stateFunc += CheckTranslate;
isRun = true;
Thread mainTh = new Thread (Update);
mainTh.Start ();
}
/// <summary>
/// 狀態(tài)字典
/// </summary>
Dictionary<string,State> states;
/// <summary>
/// 狀態(tài)切換參數(shù)字典
/// </summary>
Dictionary<string,object> stateparams;
/// <summary>
/// 當(dāng)前狀態(tài)
/// </summary>
public State currentState;
/// <summary>
/// 添加狀態(tài)
/// </summary>
/// <returns>The state.</returns>
/// <param name="statename">狀態(tài)名稱.</param>
public State AddState(string statename)
{
State temp = new State (statename);
states.Add (statename, temp);
SetDefault (temp);
return temp;
}
/// <summary>
/// 添加狀態(tài)
/// </summary>
/// <param name="s">狀態(tài).</param>
public void AddState(State s)
{
states.Add (s.stateName, s);
SetDefault (s);
}
/// <summary>
/// 移除狀態(tài)
/// </summary>
/// <param name="statename">狀態(tài)名稱.</param>
public void RemoveState(string statename)
{
states.Remove (statename);
}
/// <summary>
/// 設(shè)置默認狀態(tài)
/// </summary>
/// <param name="s">S.</param>
private void SetDefault (State s)
{
if(states.Count == 1)
{
currentState = s;
s.isRun = true;
}
}
/// <summary>
/// 切換狀態(tài)
/// </summary>
/// <param name="name">狀態(tài)名稱.</param>
public void TranslateState(string name)
{
if(states[name] != null)
{
currentState.isRun = false;
currentState = states [name];
states [name].isRun = true;
}
}
/// <summary>
/// 獲取狀態(tài)
/// </summary>
/// <returns>The state.</returns>
/// <param name="statename">Statename.</param>
public State GetState(string statename)
{
return states [statename];
}
/// <summary>
/// 注冊參數(shù)
/// </summary>
/// <param name="paramName">參數(shù)名稱.</param>
/// <param name="value">參數(shù)值.</param>
public void RegisterParams(string paramName, int value)
{
stateparams.Add (paramName, value);
}
/// <summary>
/// 注冊參數(shù)
/// </summary>
/// <param name="paramName">參數(shù)名稱.</param>
/// <param name="value">參數(shù)值.</param>
public void RegisterParams(string paramName, float value)
{
stateparams.Add (paramName, value);
}
/// <summary>
/// 注冊參數(shù)
/// </summary>
/// <param name="paramName">參數(shù)名稱.</param>
/// <param name="value">參數(shù)值.</param>
public void RegisterParams(string paramName, string value)
{
stateparams.Add (paramName, value);
}
/// <summary>
/// 獲取int類型參數(shù)
/// </summary>
/// <returns>The int parameters.</returns>
/// <param name="paraName">Para name.</param>
public int GetIntParams(string paraName)
{
return (int)stateparams [paraName];
}
/// <summary>
/// 獲取float類型參數(shù)
/// </summary>
/// <returns>The float parameters.</returns>
/// <param name="paraName">Para name.</param>
public float GetFloatParams(string paraName)
{
return (float)stateparams [paraName];
}
/// <summary>
/// 獲取string類型參數(shù)
/// </summary>
/// <returns>The string parameters.</returns>
/// <param name="paraName">Para name.</param>
public string GetStringParams(string paraName)
{
return (string)stateparams [paraName];
}
/// <summary>
/// 設(shè)置int參數(shù)
/// </summary>
/// <param name="paraName">Para name.</param>
/// <param name="value">Value.</param>
public void SetIntParams(string paraName, int value)
{
stateparams[paraName] =value;
}
/// <summary>
/// 設(shè)置float參數(shù)
/// </summary>
/// <param name="paraName">Para name.</param>
/// <param name="value">Value.</param>
public void SetFloatParams(string paraName, float value)
{
stateparams[paraName] =value;
}
/// <summary>
/// 設(shè)置string參數(shù)
/// </summary>
/// <param name="paraName">Para name.</param>
/// <param name="value">Value.</param>
public void SetStringParams(string paraName, string value)
{
stateparams[paraName] =value;
}
/// <summary>
/// 檢查狀態(tài)切換
/// </summary>
private void CheckTranslate()
{
foreach (var item in currentState.stateTrs)
{
if(item.Value())
{
TranslateState(item.Key.stateName);
}
}
}
}
實例應(yīng)用
public class GameController : MonoBehaviour {
//單例
static StateController stateController;
//外部測試
public bool test = false;
void Awake()
{
//1、實例化單例
stateController = new StateController ("MainSc");
}
void Start()
{
//2、注冊狀態(tài)Idle
State idle = stateController.AddState ("Idle");
//2、注冊狀態(tài)Run
State run = stateController.AddState ("Run");
//3、注冊參數(shù)Speed,默認值0
stateController.RegisterParams ("Speed", 0f);
//4、idle內(nèi)部事件
idle.stateFunc += () => {
Debug.Log(idle.stateName);
};
//4、run內(nèi)部事件
run.stateFunc += () => {
Debug.Log(run.stateName);
};
//5、切換事件Idle --> Run
idle.RegisterTranslate (run, () => {
if(stateController.GetFloatParams("Speed") > 0.5f)
{
return true;
}
return false;
});
//5、切換事件Run --> Idle
run.RegisterTranslate (idle, () => {
if(stateController.GetFloatParams("Speed") <= 0.5f)
{
return true;
}
return false;
});
}
void Update()
{
if (test)
{
//6、切換參數(shù),調(diào)整狀態(tài)
stateController.SetFloatParams("Speed",1);
}
else
{
stateController.SetFloatParams("Speed",0);
}
}
}
結(jié)束語
這個工具類中用到了多線程的處理,其中各個狀態(tài)的線程是持續(xù)執(zhí)行的,所以后期還會繼續(xù)改進,如果讀者朋友有哪些更好的建議和意見,歡迎評論。