Unity状态机的使用(含多线程处理)
发表于2018-09-29
众所周知,Unity在开发游戏的时候经常用到状态机,而通常情况下,我们会使用简单的枚举类型设置状态,然后通过调整枚举,来切换状态,在简单情况下是可以的,就像是Unity中Animator切换动画状态就是,直接通过动画片段的名称切换。而当状态很多的时候,直接切换就显得有些很不安全,而且友好性也不是很好,所以根据Unity中Animator这种通过条件切换状态的架构,这才有下面给大家介绍的简单状态机的使用,分享给大家。
外部委托定义
/// <summary> /// 状态内部事件委托 /// </summary> public delegate void StateFunctionEventHandler(); /// <summary> /// 状态条件判断委托 /// </summary> public delegate bool StateTranslateEventHandler();
状态类
/// <summary> /// 状态类 /// </summary> public class State { /// <summary> /// 状态内部事件 /// </summary> public event StateFunctionEventHandler stateFunc; /// <summary> /// 状态转换事件<目标状态,切换条件> /// </summary> public Dictionary<State,StateTranslateEventHandler> stateTrs; /// <summary> /// 状态名称 /// </summary> /// <value>The name of the state.</value> public string stateName{get;private set;} /// <summary> /// 状态运行中 /// </summary> public bool isRun = false; /// <summary> /// 状态内部事件执行间隔时间(毫秒) /// </summary> /// <value>The state function delta time.</value> public int stateFunctionDeltaTime{private get; set;} /// <summary> /// 状态构造 /// </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> /// 状态内部事件执行 /// </summary> public void Update() { while(true) { if(!isRun) { continue; } Thread.Sleep (stateFunctionDeltaTime); if(stateFunc != null) { stateFunc(); } } } /// <summary> /// 注册切换事件. /// </summary> /// <param name="target">目标状态.</param> /// <param name="conditional">条件事件.</param> public void RegisterTranslate(State target, StateTranslateEventHandler conditional) { try { stateTrs.Add (target, conditional); } catch(Exception ex) { Debug.LogError(ex.ToString()); } } }
状态管理类
/// <summary> /// 状态管理 /// </summary> public class StateController : State { /// <summary> /// 状态管理构造 /// </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> /// 状态字典 /// </summary> Dictionary<string,State> states; /// <summary> /// 状态切换参数字典 /// </summary> Dictionary<string,object> stateparams; /// <summary> /// 当前状态 /// </summary> public State currentState; /// <summary> /// 添加状态 /// </summary> /// <returns>The state.</returns> /// <param name="statename">状态名称.</param> public State AddState(string statename) { State temp = new State (statename); states.Add (statename, temp); SetDefault (temp); return temp; } /// <summary> /// 添加状态 /// </summary> /// <param name="s">状态.</param> public void AddState(State s) { states.Add (s.stateName, s); SetDefault (s); } /// <summary> /// 移除状态 /// </summary> /// <param name="statename">状态名称.</param> public void RemoveState(string statename) { states.Remove (statename); } /// <summary> /// 设置默认状态 /// </summary> /// <param name="s">S.</param> private void SetDefault (State s) { if(states.Count == 1) { currentState = s; s.isRun = true; } } /// <summary> /// 切换状态 /// </summary> /// <param name="name">状态名称.</param> public void TranslateState(string name) { if(states[name] != null) { currentState.isRun = false; currentState = states [name]; states [name].isRun = true; } } /// <summary> /// 获取状态 /// </summary> /// <returns>The state.</returns> /// <param name="statename">Statename.</param> public State GetState(string statename) { return states [statename]; } /// <summary> /// 注册参数 /// </summary> /// <param name="paramName">参数名称.</param> /// <param name="value">参数值.</param> public void RegisterParams(string paramName, int value) { stateparams.Add (paramName, value); } /// <summary> /// 注册参数 /// </summary> /// <param name="paramName">参数名称.</param> /// <param name="value">参数值.</param> public void RegisterParams(string paramName, float value) { stateparams.Add (paramName, value); } /// <summary> /// 注册参数 /// </summary> /// <param name="paramName">参数名称.</param> /// <param name="value">参数值.</param> public void RegisterParams(string paramName, string value) { stateparams.Add (paramName, value); } /// <summary> /// 获取int类型参数 /// </summary> /// <returns>The int parameters.</returns> /// <param name="paraName">Para name.</param> public int GetIntParams(string paraName) { return (int)stateparams [paraName]; } /// <summary> /// 获取float类型参数 /// </summary> /// <returns>The float parameters.</returns> /// <param name="paraName">Para name.</param> public float GetFloatParams(string paraName) { return (float)stateparams [paraName]; } /// <summary> /// 获取string类型参数 /// </summary> /// <returns>The string parameters.</returns> /// <param name="paraName">Para name.</param> public string GetStringParams(string paraName) { return (string)stateparams [paraName]; } /// <summary> /// 设置int参数 /// </summary> /// <param name="paraName">Para name.</param> /// <param name="value">Value.</param> public void SetIntParams(string paraName, int value) { stateparams[paraName] =value; } /// <summary> /// 设置float参数 /// </summary> /// <param name="paraName">Para name.</param> /// <param name="value">Value.</param> public void SetFloatParams(string paraName, float value) { stateparams[paraName] =value; } /// <summary> /// 设置string参数 /// </summary> /// <param name="paraName">Para name.</param> /// <param name="value">Value.</param> public void SetStringParams(string paraName, string value) { stateparams[paraName] =value; } /// <summary> /// 检查状态切换 /// </summary> private void CheckTranslate() { foreach (var item in currentState.stateTrs) { if(item.Value()) { TranslateState(item.Key.stateName); } } } }
实例应用
public class GameController : MonoBehaviour { //单例 static StateController stateController; //外部测试 public bool test = false; void Awake() { //1、实例化单例 stateController = new StateController ("MainSc"); } void Start() { //2、注册状态Idle State idle = stateController.AddState ("Idle"); //2、注册状态Run State run = stateController.AddState ("Run"); //3、注册参数Speed,默认值0 stateController.RegisterParams ("Speed", 0f); //4、idle内部事件 idle.stateFunc += () => { Debug.Log(idle.stateName); }; //4、run内部事件 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、切换参数,调整状态 stateController.SetFloatParams("Speed",1); } else { stateController.SetFloatParams("Speed",0); } } }
看完状态机的简单使用之后,相信大家对于多线程的处理也有所掌握了吧。