美文网首页
unity fsm 有限状态机

unity fsm 有限状态机

作者: Rehma | 来源:发表于2020-02-21 14:48 被阅读0次

FSM 有限状态机


概念

  • 如其名,在有限的状态下,管理状态的转移的一种设计模式

基本思路

pic
  • 状态a 要切换到 状态b,需要通过中介也就是状态管理机进行切换,而不是两种状态直接切换,降低了耦合
  • 另外每种状态可能有不同的特效、动画或音效等...多种逻辑。所以可以把每个状态单独封装成一个 方便管理和维护
  • 每个状态跳转之间有共性,所以可以抽象基类如:
    • 状态进入 OnEnter
    • 状态保持 OnStay
    • 状态退出 OnExit
  • 状态管理机 只需要负责CRUD:
    • 1.状态的注册
    • 2.状态的注销
    • 3.状态的改变
    • 4.状态的查询

代码实现

以下代码在FsmBase.cs脚本 是每个状态的基类

  • 首先定义一个枚举用来标识具体状态
public enum E_state {
    Idle,
    Jump,
    Walk,
    None
}
  • 抽象共同特征
public class FsmBase {
    /// <summary>
    /// 状态的ID 用来标识每一个状态
    /// </summary>
    public E_state e_State { get; }
    //初始化
    public FsmBase (E_state _state) {
        this.e_State = _state;
    }
    
    /// <summary>
    /// 状态进入
    /// </summary>
    /// <param name="args">任意可变参数</param>
    public virtual void OnEnter (params object[] args) { }

    /// <summary>
    /// 状态保持
    /// </summary>
    /// <param name="args">任意可变参数</param>
    public virtual void OnStay (params object[] args) { }

    /// <summary>
    /// 状态退出
    /// </summary>
    /// <param name="args">任意可变参数</param>
    public virtual void OnExit (params object[] args) { }

}
  • 为了更好的通用性,再为FSMBase套个接口,其实就是模板,以后状态只需继承此模板类即可
/// <summary>
/// 状态模板 具体状态只需要继承此类即可
/// </summary>
/// <typeparam name="T">拥有此状态的对象</typeparam>
public class StateTemplates<T> : FsmBase where T : class {
    public T m_owner; //状态的拥有者方便后期调用
    public StateTemplates (E_state _state, T t) : base (_state) {
        this.m_owner = t;
    }
}

以下代码在FIniteStateMachine.cs脚本中 也就是👆的状态管理机

  • 定义属性字段和初始化
//用个字典存所有状态
public Dictionary<E_state, FsmBase> m_allState;

/// <summary>
/// 上一个状态
/// </summary>
private FsmBase m_priousState;

/// <summary>
/// 当前状态
/// </summary>
private FsmBase m_curState;

//构造函数
public FiniteStateMachine () {
    m_priousState = null;
    m_curState = null;
    m_allState = new Dictionary<E_state, FsmBase> ();
}
/// <summary>
/// 状态注册
/// </summary>
/// <param name="_fsmBase">想要被注册的状态</param>
public void RegistState (FsmBase _fsmBase) {
    //没有这个状态就添加
    if (!m_allState.ContainsKey (_fsmBase.e_State))
        m_allState.Add (_fsmBase.e_State, _fsmBase);
}
//注销状态
public void UnRegistState (FsmBase _fsmBase) {
    if (m_allState.ContainsKey (_fsmBase.e_State))
        m_allState.Remove (_fsmBase.e_State);
}
/// <summary>
/// 改变状态
/// </summary>
/// <param name="_state">需要切换的下个状态</param>
/// <param name="args">可选参数</param>
public void ChangeState (E_state _state, params object[] args) {
    //没有这个状态 或 就是当前状态 就退出
    if (!m_allState.ContainsKey (_state) || _state == m_curState.e_State) return;
    if (m_curState == null) return;
    //本次状态退出
    m_curState.OnExit (args);
    //退出后把本次状态设为前一个状态
    m_priousState = m_curState;
    //根据想要更改的状态 去字典找 并设为当前状态
    m_curState = m_allState[_state];

    m_curState.OnEnter (args);
}
public E_state GetPriousState () {
    if (m_priousState != null)
        return m_priousState.e_State;

    return E_state.None;
}

public E_state GetCurState () {
    if (m_curState != null)
        return m_curState.e_State;

    return E_state.None;
}
  • 最后一个更新和启动
public void UpdateState (params object[] args) {
    if (m_curState != null)
        m_curState.OnStay (args);
}

/// <summary>
/// 开始运作并进入一个状态
/// </summary>
/// <param name="_fsmBase">想要进入的状态</param>
/// <param name="args">可选参数</param>
public void Go (FsmBase _fsmBase, params object[] args) {
    if (m_curState != null) return;
    m_curState = _fsmBase;
    m_curState.OnEnter (args);
}

接下来添加需要的状态 为了展示就定义两种状态🤭 以下代码在PlayerVariedState.cs脚本

  • 需要控制状态的进出,只需要重写具体函数即可,不需要可不写
  • 👆提供模板的方便之处就体现在这,这里m_owner就代表Player
using UnityEngine;

public class PlayerIdle : StateTemplates<Player> {

    public PlayerIdle (E_state _state, Player _p) : base (_state, _p) { }

    public override void OnEnter (params object[] args) {
    // m_owner.GetComponent<MeshFilter> ()//获取本身组时只需用m_owner对象即可
        Debug.Log ("进入待机状态");
    }
    public override void OnStay (params object[] args) {
        Debug.Log ("保持待机状态");
        //当前状态持续进行 ,
    }
    public override void OnExit (params object[] args) {
        Debug.Log ("离开待机状态");
    }
}
public class PlayerJump : StateTemplates<Player> {

    public PlayerJump (E_state _state, Player _p) : base (_state, _p) { }

    public override void OnEnter (params object[] args) {
        Debug.Log ("进入跳状态");
    }
    public override void OnStay (params object[] args) {
        Debug.Log ("保持跳状态");
    }
    public override void OnExit (params object[] args) {
        Debug.Log ("离开跳状态");
    }
}

最后进行测试😪 以下代码在Player.cs脚本

using UnityEngine;

public class Player : MonoBehaviour {

    public FiniteStateMachine fsm;

    private void Start () {
        //造个状态机
        fsm = new FiniteStateMachine ();
        //实例化状态
        var tmpIdle = new PlayerIdle (E_state.Idle, this);
        var tmpJump = new PlayerJump (E_state.Jump, this);
        //注册
        fsm.RegistState (tmpIdle);
        fsm.RegistState (tmpJump);
        //启动机器
        fsm.Go (tmpIdle);
    }

    private void Update () {
        if (Input.GetKeyDown (KeyCode.Q))
            fsm.ChangeState (E_state.Idle);
       
        if (Input.GetKeyDown (KeyCode.W))
            fsm.ChangeState (E_state.Jump);
        
        fsm.UpdateState ();
    } 
}
  • 将Player挂载一个游戏对象后 运行结果


    pic2

总结

  • 优点:
    • 方便扩展,如果后期需添加新状态,只需继承基类即可
    • 屏蔽了状态之间切换的繁琐性和复杂性(如状态增多之后)
    • 每种状态不需要担心何时被调用,只需负责调用时的逻辑即可
    • 符合开闭原则(对修改关闭对扩展开放)

最后:

鄙人学习笔记,仅供参考,如有不正,欢迎指正👀

【参考1】传送门
【参考2】传送门

相关文章

  • Finite-state Machine 有限状态机

    FSM 有限状态机和Unity的Animator类似,不过FSM除了动画还可以应用在如AI状态等。 FSM框架 S...

  • unity fsm 有限状态机

    FSM 有限状态机 概念 如其名,在有限的状态下,管理状态的转移的一种设计模式 基本思路 如 状态a 要切换到 状...

  • [Unity]有限状态机FSM

    概念 1.有限状态机:状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调...

  • GDGeek使用总结

    FSM(有限状态机) GDGeek的FSM实现了分层状态机,并且整合了任务(Task)和插值动画(Tween),使...

  • 有限状态机FSM的几种简单实现

    『代码github地址』 标签: 有限状态机,Akka fsm,squirrel-foundation,java状...

  • 有限状态机抽取地址

    有限元状态机 什么是有限状态机 有限状态机(英语:finite-state machine,缩写:FSM)又称有限...

  • 状态机

    有限状态机 finite-state machine FSM 有限状态机在设计交易订单系统时,会存在正向状态(待...

  • 运维基础知识-tcp/ip

    有限状态机FSM:Finite State Machine 1、CLOSED 没有任何连接状态 2、LISTEN ...

  • 如何使用有限状态机

    1.背景介绍 有限状态机,(英语:Finite-state machine, FSM),又称为有限状态自动机...

  • 什么是有限状态机

    1.背景介绍 有限状态机,(英语:Finite-state machine, FSM),又称为有限状态自动机,简称...

网友评论

      本文标题:unity fsm 有限状态机

      本文链接:https://www.haomeiwen.com/subject/odpcqhtx.html