C#设计模式:8.有限状态机模式 u3d学习总结笔记本

有限状态机(Finite-state machine, FSM)—— 简称状态机

所谓有限状态机就是决定我们游戏对象的当前状态和状态间的切换,状态机最终只能指向一个结果,由这个结果指向这个状态的行为,也就是执行的函数。

 一,状态模式是具体的,针对每个需求有一个状态集,并为其实现特有的迁移机制。状态机是抽象的,不是针对特定的需求,而是对各种与相关的问题的进一步抽象,那么用状态机回头去实现状态模式的时候,只需要关注问题本身,而不用去关心如何实现,也就是说你只需要绘制出状态迁移图,状态机就能帮你去实现。

       二,状态模式的是命令式的,我们必须一步一步地去实现状态之间如何迁移,以及迁移过程中需要做一些额外的事情。状态机是声明式的,使用状态机,你只需要声明状态及状态的迁移路线,而不需要去提供执行层面的命令,状态机自动帮你去做。

状态机能通过全局来管理我们的游戏状态/人物状态

使我们的工程逻辑清晰,将游戏/项目各个状态的转换,交由状态机统一管理

极大的避免了当状态过多 / 转换状态过多时,每次都需要调用相应函数来完成转换的麻烦

目录

2020.05.29:


个人当前的理解:

2020.05.29:

理解可能不完全,我看别人写的有限状态机蛮庞大的 。

通过继承状态基类来变成状态类

状态类之间可以互相连接,判断条件进行状态跳转

状态类有自己的生命周期:Start , Update , Exit

状态类需要通过状态机运行

代码:

状态基类

思路为:状态与状态之间可以互相连接,所以连接表就挂在了状态类上

连接表里记录了本状态 要连接的 <其他状态,跳转条件>

跳转条件委托条件,算是外部全局

/// <summary>
/// 状态基类
/// </summary>
public abstract class State_Base
{
    /// <summary>
    /// 转换链接字典
    /// </summary>
    public Dictionary<State_Base, Func<bool>> converter = new Dictionary<State_Base, Func<bool>>();

    public abstract void Start();//状态委托:开始
    public abstract void Update();//状态委托:刷新
    public abstract void Exit();//状态委托:退出

    public State_Base AddState(State_Base state_Base, Func<bool> IF_Event)//链接和新状态添加
    {
        if (converter.ContainsKey(state_Base))
        {
            converter[state_Base] = IF_Event;
        }
        else
        {
            converter.Add(state_Base, IF_Event);
        }
        return this;
    }

    public State_Base RemoveState(State_Base state_Base)//状态链接删除
    {
        converter.Remove(state_Base);
        return this;
    }
}

状态机:

思路为:状态机为动态类,它的生命周期挂在继承mono的脚本上,驱动状态机去运行状态的生命周期

状态机只会储存一个状态,通过遍历当前状态跳转表,来判断要跳转的下一个状态

/// <summary>
/// 状态机
/// </summary>
public class StateMachine
{

    public State_Base CurrentState;//当前状态

    public void Start()
    {
        CurrentState.Start();
    }

    public void Update()
    {

        foreach (var converter in CurrentState.converter)	//变量判断转换条件
        {
            if (converter.Value())	//转换条件成立
            {
                //上一个状态退出
                CurrentState.Exit();

                //状态切换
                CurrentState = converter.Key;

                //新状态启动
                CurrentState.Start();

                break;
            }
        }
        CurrentState.Update();
    }

    public void Exit()
    {
        CurrentState.Exit();
    }

}

结论:类似站点与火车的关系,状态是节点,状态机是火车头,

火车每到一个站点就会拿到当前站点通往下一个站点的路牌,和出发指令

当判断某个出发指令为true,则开往相应的站点

状态实现类:

//等待状态
public class Standby : State_Base
{
    public override void Start()
    {
        Debug.Log("等待进入 ");
    }

    public override void Update()
    {
        Debug.Log("等待刷新 ");
    }

    public override void Exit()
    {
        Debug.Log("等待离开 ");
    }
}

//行走状态
public class Walk : State_Base
{
    public override void Start()
    {
        Debug.Log("行走进入 ");
    }

    public override void Update()
    {
        Debug.Log("行走刷新 ");
    }

    public override void Exit()
    {
        Debug.Log("行走离开 ");
    }
}

//奔跑状态
public class Run : State_Base
{
    public override void Start()
    {
        Debug.Log("奔跑进入 ");
    }

    public override void Update()
    {
        Debug.Log("奔跑刷新 ");
    }

    public override void Exit()
    {
        Debug.Log("奔跑离开 ");
    }
}

运行测试:


public class FiniteStateMachine : MonoBehaviour
{

    //===[状态枚举类]===
    [SerializeField]
    public enum State_Enum
    {
        Standby,
        Walk,
        Run
    }

    public State_Enum state_Enum;

    private StateMachine stateMachine;

    void Start()
    {
        //===[新建状态机]===
        stateMachine = new StateMachine();

        //===[新建状态]===
        State_Base Standby_State = new Standby();
        State_Base Walk_State = new Walk();
        State_Base Run_State = new Run();

        //===[状态机注入初始状态]===
        stateMachine.CurrentState = Standby_State;

        //===[状态与状态之间的条件转换注册]===

        Standby_State
        .AddState(Run_State, () => state_Enum == State_Enum.Run)
        .AddState(Walk_State, () => state_Enum == State_Enum.Walk)
        ;

        Walk_State
        .AddState(Standby_State, () => state_Enum == State_Enum.Standby)
        .AddState(Run_State, () => state_Enum == State_Enum.Run)
        ;

        Run_State
        .AddState(Walk_State, () => state_Enum == State_Enum.Walk)
        .AddState(Standby_State, () => state_Enum == State_Enum.Standby)
        ;

        //===[状态与状态之间的条件转换删除]===
        Run_State.RemoveState(Walk_State);//删除了Run->Walk的链接


        //!===[状态机驱动]============================================

        //===[驱动状态机的Start]===
        stateMachine.Start();
    }

    void Update()
    {
        //===[驱动状态机的Update]===
        stateMachine.Update();
    }

    private void OnApplicationQuit()
    {
        //===[驱动状态机的Exit]===
        stateMachine.Exit();
    }
}

结果:

因为删除了Run->Walk的链接所以Run没有跳回Walk

2020.05.29完

猜你喜欢

转载自blog.csdn.net/qq_40346899/article/details/106424117