前言
众所周知,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);
}
}
}
结束语
这个工具类中用到了多线程的处理,其中各个状态的线程是持续执行的,所以后期还会继续改进,如果读者朋友有哪些更好的建议和意见,欢迎评论。