实现思路:
1.创建状态基类BasState,所有具体状态类继承该类。基类有3个方法:进入状态、状态中、离开状态;
2.创建管理类来管理状态机(StateMgr),并实现状态机的各个方法:状态转换、设置默认状态等;
3.创建具体状态类(继承BasState),并实现其3个方法(virtual方法如果没有重载override会默认调用父一级的该方法);
4.初始化管理器(StateMgr)。
注意事项:
1.代码实现为C#语言的具体实现,仅供参考,已在Unity上测试运行成功,(修改StateMgr继承的Singleton为MonoBehaviour并运行Init()方法后即可)请放心食用;
2.“StateMgr : Singleton<StateMgr>”管理器类中继承的Singleton是我框架设计的父类,仅仅为了单例实现;
3.StateMgr我为了能一个管理器管理多个不同状态机而改进了下:多了一个字典保存状态机。所以会比学习链接稍微复杂点;
4.为了增强鲁棒性,代码中存在比较多的数据检测,如果移除可以增加可读性。在第一次使用时(Main方法),将StateMgr中的Init()方法调用即可;
5.(可选)string改为Enum枚举类型,对应字典的string部分改为自己设计的Enum,方便后续开发(代码提示)也易于维护(测试开发时是可行的)。存入数据库中需要创建对应表的类,会更复杂些,不过扩展性会更强,效果会比改为枚举类型会更佳,需要增删改状态时可以直接在外部表中修改,并在对应存储数据表的类修改下代码即可。
不足:
1.状态、状态机没有优化好,暂时是直接指定字符串来存储。不方便开发,后续考虑改为枚举类型或者存入数据库中保存;
2.性能可能不是特别好,有待优化。
代码:
BaseState.cs
基类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BaseState
{
public StateMgr stateMgr;
public virtual void OnEnterState() { }
public virtual BaseState OnStayState() { return null; }
public virtual void OnExitState() { }
}
CtrlState.cs
具体行为类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CtrlState : BaseState
{
public StateMgr stateMgr;
public override void OnEnterState()
{
Debug.Log("Enter CtrlState");
}
public override BaseState OnStayState()
{
Debug.Log("Stay CtrlState");
return this;
}
public override void OnExitState()
{
Debug.Log("Exit CtrlState");
}
}
StateMgr.cs
管理器类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 状态机管理器
/// 说明:
/// </summary>
public class StateMgr : Singleton<StateMgr>
{
//管理所有状态机
private Dictionary<string, Dictionary<string, BaseState>> stateDic;
//一个字典保存各个状态机,需要一个枚举
//...
#region 状态机字典集
//当前焦点状态机
private Dictionary<string, BaseState> stateFocusDic;
#endregion
//"当前"状态字典
private Dictionary<string, BaseState> currentState;
//"前一个"状态字典
private Dictionary<string, BaseState> lastState;
public StateMgr()
{
stateDic = new Dictionary<string, Dictionary<string, BaseState>>();
stateFocusDic = new Dictionary<string, BaseState>();
currentState = new Dictionary<string, BaseState>();
lastState = new Dictionary<string, BaseState>();
}
/// <summary>
/// 初始化状态机
/// </summary>
public void Init()
{
//初始注册当前焦点状态机
RegisterStateMachine("stateFocusDic",stateFocusDic);
//初始焦点状态机数据----设计为更便捷的方法?text读取自动初始化?枚举?
RegisterState("stateFocusDic", "none", new NoneState());
RegisterState("stateFocusDic", "ctrl", new CtrlState());
RegisterState("stateFocusDic", "interactive", new InteractiveState());
//设置默认状态
SetDefaultState("stateFocusDic", "ctrl");
//测试
GotoState("stateFocusDic", "interactive");
}
public void Clear()
{
}
/// <summary>
/// 注册对应状态机字典,同时给"当前"与"之前"状态字典初始化Key
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <param name="newDic">目标状态机字典</param>
public void RegisterStateMachine(string stateMachineName,Dictionary<string,BaseState> newDic)
{
//注册状态机
stateDic.Add(stateMachineName,newDic);
//初始化"当前"与"之前状态"字典
currentState.Add(stateMachineName, null);
lastState.Add(stateMachineName, null);
}
/// <summary>
/// 注册状态机的状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <param name="stateName">目标状态名</param>
/// <param name="state">目标状态类</param>
public void RegisterState(string stateMachineName,string stateName,BaseState state)
{
if (!stateDic.ContainsKey(stateMachineName))
{
Debug.LogError("状态机列表无此状态机" + stateMachineName);
return;
}
//指定状态类的指向对象为此Mgr类
state.stateMgr = this;
//为目标状态机添加状态
stateDic[stateMachineName].Add(stateName,state);
}
/// <summary>
/// 获取目标状态机的"当前"状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <returns></returns>
public BaseState GetCurrentState(string stateMachineName)
{
if (!currentState.ContainsKey(stateMachineName))
{
Debug.LogError("目标状态列表无此状态" + stateMachineName);
return null;
}
return currentState[stateMachineName];
}
/// <summary>
/// 获取目标状态机之前的状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <returns></returns>
public BaseState GetLastState(string stateMachineName)
{
if (!lastState.ContainsKey(stateMachineName))
{
Debug.LogError("目标状态列表无此状态" + stateMachineName);
return null;
}
return lastState[stateMachineName];
}
/// <summary>
/// 设置状态机默认状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <param name="stateName">目标状态名</param>
public void SetDefaultState(string stateMachineName, string stateName)
{
if (!stateDic.ContainsKey(stateMachineName))
{
Debug.LogError("状态机列表无此状态机" + stateMachineName);
return;
}
if (!currentState.ContainsKey(stateMachineName))
{
Debug.LogError("当前状态机列表无此状态机" + stateMachineName);
return;
}
if (!stateDic[stateMachineName].ContainsKey(stateName))
{
Debug.LogError("目标状态机状态列表无此状态" + stateName);
return;
}
//将目标状态机的当前状态设置为stateName
currentState[stateMachineName] = stateDic[stateMachineName][stateName];
}
/// <summary>
/// 改变状态机的当前状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <param name="stateName">目标状态名</param>
public void ChangeState(string stateMachineName, string stateName)
{
if (!stateDic.ContainsKey(stateMachineName))
{
Debug.LogError("状态机列表无此状态机" + stateMachineName);
return;
}
if (!currentState.ContainsKey(stateMachineName))
{
Debug.LogError("当前状态机列表无此状态机" + stateMachineName);
return;
}
if (!stateDic[stateMachineName].ContainsKey(stateName))
{
Debug.LogError("目标状态机状态列表无此状态" + stateName);
if (!lastState.ContainsKey(stateMachineName))
{
Debug.LogError("之前状态机列表无此状态机" + stateMachineName);
return;
}
//改变失败,设置状态为"之前"状态
currentState[stateMachineName] = lastState[stateMachineName];
}
//改变成功,设置状态
currentState[stateMachineName] = stateDic[stateMachineName][stateName];
}
/// <summary>
/// 目标状态机切换到目标状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <param name="stateName">目标状态名</param>
public void GotoState(string stateMachineName, string stateName)
{
if (!stateDic.ContainsKey(stateMachineName))
{
Debug.LogError("状态机列表无此状态机" + stateMachineName);
return;
}
if (!stateDic[stateMachineName].ContainsKey(stateName))
{
Debug.LogError("目标状态机状态列表无此状态" + stateName);
return;
}
//如果"之前"状态与"当前"状态不同,则更新记录
if (currentState[stateMachineName] != lastState[stateMachineName])
{
lastState[stateMachineName] = currentState[stateMachineName];
}
//执行"之前"状态的"状态后"方法(currentState此时未更新)
lastState[stateMachineName].OnExitState();
//改变目标状态机当前状态
ChangeState(stateMachineName,stateName);
//执行当前状态的"状态前",然后执行"状态中"方法
currentState[stateMachineName].OnEnterState();
currentState[stateMachineName].OnStayState();
}//GotoState_end
}//class_end
StateMgr.cs
(枚举升级版本)
多了curState与oldState,用于获取enum State,方便在其他类中的比较判断。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 状态机管理器
/// 说明:
/// 新添状态机:
/// 1.新建一个状态机字典集,并在enum Machine中添加
/// 2.StateMgr进行new
/// 3.Init()进行状态添加,并设置默认状态
/// 新添状态:
/// 1.在enum State中添加枚举
/// 2.Init()中目标状态机进行状态添加
/// </summary>
public class StateMgr : Singleton<StateMgr>
{
//管理所有状态机
private Dictionary<Machine, Dictionary<State, BaseState>> stateDic;
#region 状态机字典集
//当前焦点状态机
private Dictionary<State, BaseState> stateFocusDic;
#endregion
//"当前"状态字典
private Dictionary<Machine, BaseState> currentState;
//"前一个"状态字典
private Dictionary<Machine, BaseState> lastState;
//"当前"状态字典
private Dictionary<Machine, State> curState;
//"前一个"状态字典
private Dictionary<Machine, State> oldState;
/// <summary>
/// 状态机
/// </summary>
public enum Machine
{
FocusMachine,
}
/// <summary>
/// 状态
/// </summary>
public enum State
{
None,
Ctrl,
Interactive,
}
public StateMgr()
{
stateDic = new Dictionary<Machine, Dictionary<State, BaseState>>();
stateFocusDic = new Dictionary<State, BaseState>();
currentState = new Dictionary<Machine, BaseState>();
lastState = new Dictionary<Machine, BaseState>();
curState = new Dictionary<Machine, State>();
oldState = new Dictionary<Machine, State>();
}
/// <summary>
/// 初始化状态机
/// </summary>
public void Init()
{
//初始注册当前焦点状态机
RegisterStateMachine(Machine.FocusMachine,stateFocusDic);
//初始焦点状态机数据----设计为更便捷的方法?text读取自动初始化?
RegisterState(Machine.FocusMachine, State.None, new NoneState());
RegisterState(Machine.FocusMachine, State.Ctrl, new CtrlState());
RegisterState(Machine.FocusMachine, State.Interactive, new InteractiveState());
//设置默认状态
SetDefaultState(Machine.FocusMachine, State.None);
}
public void Clear()
{
}
/// <summary>
/// 注册对应状态机字典,同时给"当前"与"之前"状态字典初始化Key
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <param name="newDic">目标状态机字典</param>
public void RegisterStateMachine(Machine stateMachineName,Dictionary<State, BaseState> newDic)
{
//注册状态机
stateDic.Add(stateMachineName,newDic);
//初始化"当前"与"之前状态"字典
currentState.Add(stateMachineName, null);
lastState.Add(stateMachineName, null);
curState.Add(stateMachineName, State.None);
oldState.Add(stateMachineName, State.None);
}
/// <summary>
/// 注册状态机的状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <param name="stateName">目标状态名</param>
/// <param name="state">目标状态类</param>
public void RegisterState(Machine stateMachineName,State stateName,BaseState state)
{
if (!stateDic.ContainsKey(stateMachineName))
{
Debug.LogError("状态机列表无此状态机" + stateMachineName);
return;
}
//指定状态类的指向对象为此Mgr类
state.stateMgr = this;
//为目标状态机添加状态
stateDic[stateMachineName].Add(stateName,state);
}
/// <summary>
/// 获取目标状态机的"当前"状态BaseState
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <returns></returns>
public BaseState GetCurrentBaseState(Machine stateMachineName)
{
if (!currentState.ContainsKey(stateMachineName))
{
Debug.LogError("目标状态列表无此状态" + stateMachineName);
return null;
}
return currentState[stateMachineName];
}
/// <summary>
/// 获取目标状态机的"当前"状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <returns></returns>
public State GetCurrentState(Machine stateMachineName) {
if (!curState.ContainsKey(stateMachineName)) {
Debug.LogError("目标状态列表无此状态" + stateMachineName);
return State.None;
}
return curState[stateMachineName];
}
/// <summary>
/// 获取目标状态机之前的状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <returns></returns>
public State GetLastState(Machine stateMachineName) {
if (!oldState.ContainsKey(stateMachineName)) {
Debug.LogError("目标状态列表无此状态" + stateMachineName);
return State.None;
}
return oldState[stateMachineName];
}
/// <summary>
/// 获取目标状态机之前的状态BaseState
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <returns></returns>
public BaseState GetLastBaseState(Machine stateMachineName)
{
if (!lastState.ContainsKey(stateMachineName))
{
Debug.LogError("目标状态列表无此状态" + stateMachineName);
return null;
}
return lastState[stateMachineName];
}
/// <summary>
/// 设置状态机默认状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <param name="stateName">目标状态名</param>
public void SetDefaultState(Machine stateMachineName, State stateName)
{
if (!stateDic.ContainsKey(stateMachineName))
{
Debug.LogError("状态机列表无此状态机" + stateMachineName);
return;
}
if (!currentState.ContainsKey(stateMachineName))
{
Debug.LogError("当前状态机列表无此状态机" + stateMachineName);
return;
}
if (!stateDic[stateMachineName].ContainsKey(stateName))
{
Debug.LogError("目标状态机状态列表无此状态" + stateName);
return;
}
//将目标状态机的当前状态设置为stateName
currentState[stateMachineName] = stateDic[stateMachineName][stateName];
curState[stateMachineName] = stateName;
}
/// <summary>
/// 改变状态机的当前状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <param name="stateName">目标状态名</param>
public void ChangeState(Machine stateMachineName, State stateName)
{
if (!stateDic.ContainsKey(stateMachineName))
{
Debug.LogError("状态机列表无此状态机" + stateMachineName);
return;
}
if (!currentState.ContainsKey(stateMachineName))
{
Debug.LogError("当前状态机列表无此状态机" + stateMachineName);
return;
}
if (!stateDic[stateMachineName].ContainsKey(stateName))
{
Debug.LogError("目标状态机状态列表无此状态" + stateName);
if (!lastState.ContainsKey(stateMachineName))
{
Debug.LogError("之前状态机列表无此状态机" + stateMachineName);
return;
}
//改变失败,设置状态为"之前"状态
currentState[stateMachineName] = lastState[stateMachineName];
curState[stateMachineName] = oldState[stateMachineName];
}
//改变成功,设置状态
currentState[stateMachineName] = stateDic[stateMachineName][stateName];
curState[stateMachineName] = stateName;
}
/// <summary>
/// 目标状态机切换到目标状态
/// </summary>
/// <param name="stateMachineName">目标状态机名字</param>
/// <param name="stateName">目标状态名</param>
public void GotoState(Machine stateMachineName, State stateName)
{
if (!stateDic.ContainsKey(stateMachineName))
{
Debug.LogError("状态机列表无此状态机" + stateMachineName);
return;
}
if (!stateDic[stateMachineName].ContainsKey(stateName))
{
Debug.LogError("目标状态机状态列表无此状态" + stateName);
return;
}
//如果"之前"状态与"当前"状态不同,则更新记录
if (currentState[stateMachineName] != lastState[stateMachineName])
{
lastState[stateMachineName] = currentState[stateMachineName];
oldState[stateMachineName] = curState[stateMachineName];
}
//执行"之前"状态的"状态后"方法(currentState此时未更新)
lastState[stateMachineName].OnExitState();
//改变目标状态机当前状态
ChangeState(stateMachineName,stateName);
//执行当前状态的"状态前",然后执行"状态中"方法
currentState[stateMachineName].OnEnterState();
currentState[stateMachineName].OnStayState();
}//GotoState_end
}//class_end