当前位置: 首页 > news >正文

Unity有限制状态机FSM

我是标题

    • 前言
    • 有限制状态机框架
      • 框架图:
      • 主要代码:

前言

一般的小型游戏的状态机会使用一个枚举类来枚举所有的状态,然后使用一个switch case来处理所有状态的行为逻辑,但是用这种方式会形成大量的冗余,因为所有的行为逻辑都在一个脚本中,所以团队开发来说模块性不足,可扩展性低。所以就有了有限制状态机(FSM),行为逻辑写在别的脚本中,每个行为逻辑之间互相独立,并且通过一个状态控制中心来进行控制,同时有“大脑”BlackBoard来实现整体之间的数据互通和共享,可拓展性和模块性强,耦合度低。

有限制状态机框架

来源:B站打工人小棋 跳转

框架图:

在这里插入图片描述

主要代码:

黑板类:提供全局的数据共享

public class BlackBoard
{
    private Dictionary<string, object> data = new Dictionary<string, object>();

    // 获取数据
    public T GetData<T>(string key)
    {
        if (data.TryGetValue(key, out object value))
        {
            return (T)value;
        }
        return default(T);
    }

    // 设置数据
    public void SetData(string key, object value)
    {
        if (data.ContainsKey(key))
        {
            data[key] = value;
        }
        else
        {
            data.Add(key, value);
        }
    }
}

定义一个接口类作为所有动作的基类

public interface Istate
{
    void OnEnter();
    void OnExit();
    void OnUpdate();
}

状态机类:
容纳键值对查找的字典。
对外公开的Add和Remove和 SwitchState的方法。
全局共享的黑板。
目前的状态。

public class FSM
{
    public enum State
    {
        Idle,
        Move,
        Attack,
    }
   

    public Istate currentState;
    public Dictionary<State, Istate> states;
    public BlackBoard blackBoard;
    public FSM()
    {
        blackBoard = new BlackBoard();
        states = new Dictionary<State, Istate>();
    }

    public void AddState(State stateType, Istate state)
    {
        if(states.ContainsKey(stateType))
        {
            Debug.LogWarning("ISEXIST");
            return;
        }
        states.Add(stateType, state);
    }

    public void RemoveState(State stateType)
    {
        if( states.ContainsKey(stateType))
        {
            states.Remove(stateType);
        }
        else
        {
            Debug.LogWarning("DO NOT EXIST");
        }
    }

    public void SwitchState(State stateType)
    {
        if(!states.ContainsKey(stateType)) 
        {
            Debug.LogWarning("DO NOT EXIST");
            return;
        }
        if(currentState != null)
        {
            currentState.OnExit();
        }
        if(states.TryGetValue(stateType, out Istate theNewState)) currentState = theNewState;
        currentState.OnEnter();
    }

    public void OnUpdate()
    {
        currentState?.OnUpdate();
    }
}

Idle状态定义示例:
需要接受有玩家脚本的一个构造函数,否者无法调用到玩家脚本中的公开的数据。

public class MoveState : Istate
{
    private PlayerController playerController;

    public MoveState(PlayerController playerController)
    {
        this.playerController = playerController;
    }

    public void OnEnter()
    {
        Debug.Log("Enter Move State");
    }

    public void OnExit()
    {
        Debug.Log("Exit Move State");
    }

    public void OnUpdate()
    {
        // 移动逻辑
        float horizontalInput = Input.GetAxis("Horizontal");
        float verticalInput = Input.GetAxis("Vertical");
        Vector3 movement = new Vector3(horizontalInput, 0, verticalInput) * playerController.moveSpeed * Time.deltaTime;
        playerController.transform.Translate(movement);

        // 检测是否停止移动
        if (horizontalInput == 0 && verticalInput == 0)
        {
            playerController.fsm.SwitchState(FSM.State.Idle);
        }
        // 检测是否有攻击输入
        if (Input.GetKeyDown(KeyCode.Space))
        {
        //更换到攻击模式 如果按下空格的话
            playerController.fsm.SwitchState(FSM.State.Attack);
        }
    }
}

使用:

public class PlayerController : MonoBehaviour
{
    public float moveSpeed = 5f;
    public FSM fsm;

    void Start()
    {
        fsm = new FSM();

        // 添加状态
        fsm.AddState(FSM.State.Idle, new IdleState(this));
        fsm.AddState(FSM.State.Move, new MoveState(this));
        fsm.AddState(FSM.State.Attack, new AttackState(this));

        // 初始状态为空闲
        fsm.SwitchState(FSM.State.Idle);
    }

    void Update()
    {
        fsm.OnUpdate();
    }
}
    

相关文章:

  • 【Java编程】【计算机视觉】一种简单的图片加/解密算法
  • 麒麟高级服务器操作系统内核升级
  • Oracle WITH 子句(也称为 公共表表达式,Common Table Expression,CTE)
  • 终止进程kill和killall
  • 智能合约开发中13种最常见的漏洞
  • 队列的各种操作实现(数据结构C语言多文件编写)
  • 从零构建大模型之Transformer公式解读
  • 大联盟(特别版)双端互动平台完整套件分享:含多模块源码+本地部署环境
  • QT Sqlite数据库-教程002 查询数据-上
  • Java集合框架深度解析:核心接口、实现类与应用场景
  • Android基础入门、Android常见界面布局基础练习
  • 回溯-day65
  • Neovim安装及lazy配置
  • ADI的BF561双核DSP怎么做开发,我来说一说(十六)触摸屏的设计
  • QT Sqlite数据库-教程002 查询数据-下
  • 操作系统导论——第19章 分页:快速地址转换(TLB)
  • Vue.js 项目中 vue.config.js 常用配置项解析
  • bash的特性-命令和文件自动补全
  • Linux - 系统服务管理(Systemd)
  • qt中的正则表达式
  • 蚌埠一动物园用染色犬扮熊猫引争议,园方回应:被投诉已撤走
  • 特朗普称或将“大幅降低”对华关税,外交部:打,奉陪到底;谈,大门敞开
  • 体坛联播|曼城击败维拉迎英超三连胜,巴萨遭遇魔鬼赛程
  • 对话地铁读书人|豪宅房产经纪人:读书使我免于抑郁
  • 88岁罗马教皇方济各突然去世,遗嘱内容对外公布
  • 大家聊中国式现代化|权衡:在推进中国式现代化中当好龙头