实现思路:

   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