FSM有限状态机

一、设计思路

1.共同的状态父类,提供可重写的进入,保持,退出该状态的生命周期方法;

2.状态机,管理所有状态(增删查改),状态机运行方法(Run);

3.在角色控制器中,实例化状态机,并初始化添加状态;

二、关键类

1.StateBase

给物体所有状态提供的基类,所有状态比较继承这个基类,并且重写生命周期的方法;

泛型T为角色控制类;

字段:

  1. public int stateID; //状态ID,string也可
  2. public T owner; //角色的实例

生命周期:

  1. public abstract void OnEnter(params object[] args); //进入状态调用
  2. public abstract void OnStay(params object[] args); //保持状态调用
  3. public abstract void OnExit(params object[] args); //退出状态调用

完整代码:

  1. public abstract class StateBase<T>
  2. {
  3. //给每个状态设置一个ID
  4. public int stateID;
  5. public T owner; //拥有者(范型)
  6. public StateBase(int id,T o)
  7. {
  8. this.stateID = id;
  9. owner = o;
  10. }
  11. //给子类提供方法
  12. public abstract void OnEnter(params object[] args);
  13. public abstract void OnStay(params object[] args);
  14. public abstract void OnExit(params object[] args);
  15. }

2.StateMachine

  1. private Dictionary<int, StateBase<T>> FSMActDic; //存所有状态的字典
  2. private int curState; //当前状态
  3. public int nextState = 0; //下一个状态

关键方法:

切换状态时,调用当前方法的退出OnExit()后,继续调用下一个方法的进入OnEnter();

其他时候调用当前方法的OnStay();

  1. public void FSMRun()
  2. {
  3. FSMActDic[curState].OnStay();
  4. if (nextState != 0 && nextState != curState)
  5. {
  6. FSMActDic[curState].OnExit();
  7. curState = nextState;
  8. FSMActDic[curState].OnEnter();
  9. nextState = 0;
  10. }
  11. }

完整代码:

  1. public class FSM<T>
  2. {
  3. private Dictionary<int, StateBase<T>> FSMActDic;
  4. private int curState;
  5. public int nextState = 0;
  6. private void SwitchState()
  7. {
  8. if (nextState != 0 && nextState != curState)
  9. {
  10. FSMActDic[curState].OnExit();
  11. curState = nextState;
  12. FSMActDic[curState].OnEnter();
  13. nextState = 0;
  14. }
  15. }
  16. public FSM(int id)
  17. {
  18. curState = id;
  19. FSMActDic = new Dictionary<int, StateBase<T>>();
  20. }
  21. //增
  22. public void AddState(int id, StateBase<T> state)
  23. {
  24. if(FSMActDic.ContainsKey(id))
  25. return;
  26. FSMActDic.Add(id, state);
  27. }
  28. //删
  29. public void RemoveSatate(int id)
  30. {
  31. if (FSMActDic.ContainsKey(id))
  32. FSMActDic.Remove(id);
  33. }
  34. //获取
  35. public StateBase<T> GetState(int id)
  36. {
  37. if (!FSMActDic.ContainsKey(id))
  38. return null;
  39. return FSMActDic[id];
  40. }
  41. public void FSMRun()
  42. {
  43. FSMActDic[curState].OnStay();
  44. SwitchState();
  45. }
  46. }

三、测试类

1.PlayerControl

实例状态机,添加几个状态,测试效果;这里我只做了简单的移动;

完整代码:

  1. public class PlayerControl : MonoBehaviour
  2. {
  3. public enum PlayerState
  4. {
  5. none = 0,
  6. idle,
  7. move,
  8. jump,
  9. }
  10. private FSM<PlayerControl> mPlayerFSM;
  11. public PlayerState mState;
  12. public Animator mAnimator;
  13. public float mSpeed;
  14. public Vector3 moveDir;
  15. private void InitFSM()
  16. {
  17. mPlayerFSM.AddState((int) PlayerState.idle, new ActIdle((int) PlayerState.idle, this));
  18. mPlayerFSM.AddState((int) PlayerState.move, new ActMove((int) PlayerState.move, this));
  19. mPlayerFSM.AddState((int) PlayerState.jump, new ActScream((int) PlayerState.jump, this));
  20. }
  21. void Start()
  22. {
  23. mAnimator = GetComponentInChildren<Animator>();
  24. mSpeed = 10;
  25. mPlayerFSM = new FSM<PlayerControl>((int) PlayerState.idle);
  26. InitFSM();
  27. mState = PlayerState.idle;
  28. }
  29. void Update()
  30. {
  31. mPlayerFSM.FSMRun();
  32. SwitchState();
  33. mPlayerFSM.nextState = (int)mState;
  34. }
  35. private void SwitchState()
  36. {
  37. if (Input.GetAxis("Horizontal") > 0 && Input.GetAxis("Vertical") == 0)
  38. {
  39. moveDir = transform.right;
  40. mState = PlayerState.move;
  41. }
  42. else if (Input.GetAxis("Horizontal") < 0 && Input.GetAxis("Vertical") == 0)
  43. {
  44. moveDir = -transform.right;
  45. mState = PlayerState.move;
  46. }
  47. else if (Input.GetAxis("Horizontal") > 0 && Input.GetAxis("Vertical") < 0)
  48. {
  49. moveDir = transform.right - transform.forward;
  50. mState = PlayerState.move;
  51. }
  52. else if (Input.GetAxis("Horizontal") < 0 && Input.GetAxis("Vertical") < 0)
  53. {
  54. moveDir = -transform.right - transform.forward;
  55. mState = PlayerState.move;
  56. }
  57. else if (Input.GetAxis("Horizontal") > 0 && Input.GetAxis("Vertical") > 0)
  58. {
  59. moveDir = transform.right + transform.forward;
  60. mState = PlayerState.move;
  61. }
  62. else if (Input.GetAxis("Horizontal") < 0 && Input.GetAxis("Vertical") > 0)
  63. {
  64. moveDir = -transform.right + transform.forward;
  65. mState = PlayerState.move;
  66. }
  67. else if (Input.GetAxis("Horizontal") == 0 && Input.GetAxis("Vertical") < 0)
  68. {
  69. moveDir = -transform.forward;
  70. mState = PlayerState.move;
  71. }
  72. else if (Input.GetAxis("Horizontal") == 0 && Input.GetAxis("Vertical") > 0)
  73. {
  74. moveDir = transform.forward;
  75. mState = PlayerState.move;
  76. }
  77. if (Mathf.Abs(Input.GetAxis("Horizontal")) < 0.1f && Mathf.Abs(Input.GetAxis("Vertical")) < 0.1f)
  78. mState = PlayerControl.PlayerState.idle;
  79. if (Input.GetAxis("Jump") != 0)
  80. {
  81. mState = PlayerState.jump;
  82. }
  83. }
  84. }

2.行为类

设置的移动,待机,吼叫三个行为类;

代码展示:

  1. public class ActMove : StateBase<PlayerControl>
  2. {
  3. public ActMove(int id, PlayerControl t) : base(id, t)
  4. {
  5. }
  6. //给子类提供方法
  7. public override void OnEnter(params object[] args)
  8. {
  9. }
  10. public override void OnStay(params object[] args)
  11. {
  12. owner.mAnimator.Play("Walk");
  13. owner.transform.position += owner.moveDir * Time.deltaTime * owner.mSpeed;
  14. }
  15. public override void OnExit(params object[] args)
  16. {
  17. }
  18. }

四、Demo展示

以上是我对FSM的总结,如果有更好的意见,欢迎给作者评论留言;

Unity——FSM有限状态机的更多相关文章

  1. Unity FSM 有限状态机

    翻译了一下unity wiki上对于有限状态机的案例,等有空时在详细写一下.在场景中添加两个游戏物体,一个为玩家并修改其Tag为Player,另一个为NPC为其添加NPCControl脚本,并为其将玩 ...

  2. Unity中FSM有限状态机

    什么是FSM FSM 即有限状态机,它是一个状态管理系统,表示一个对象的几种状态在指定条件下转移行为,即随着条件的不断改变内部状态不断地切换. FSM用处或者使用背景 通常使用FSM去实现一些简单的A ...

  3. FSM有限状态机

    1.什么是有限状态机 有限状态机(Finite State Machine),简称FSM,它由一组有限个状态.输入和根据输入及现有状态转换为下一个状态的转换函数组成,当然,通常每个状态机都必须有一个初 ...

  4. Unity 使用有限状态机 完美还原 王者荣耀 虚拟摇杆

    Unity 使用有限状态机 完美还原 王者荣耀 虚拟摇杆 效果如图所示 摇杆的UI组成 如图所示 简单的可以认为摇杆由1.2.3贴图组成 为摇杆的底座 为摇杆的杆 为摇杆的指向 可以理解这就是街机上的 ...

  5. FSM有限状态机 ---C#、Unity

    抽象类State public interface State//定义状态接口 { void Init();//初始化 int GetCurrentStateId();//返回当前状态Id void ...

  6. Unity中有限状态机的用法教程

    Unity开发VR之Vuforia 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...

  7. 使用 Unity 3D 开发游戏的架构设计难点

    Unity 3D 引擎对于开发者来说,入手非常快,因为它采用的是 C# 作为开发语言,这也大大降低了开发者的门槛.但凡只要懂一门编程语言的人都能使用 Unity 3D 引擎开发,另外 Unity 3D ...

  8. Lua中使用状态机FSM简单例子

    FSM 有限状态机: 一个有限状态机是一个设备,或者是一个设备模型,具有有限数量的状态,它可以在任何给定的时间根据输入进行操作,使得一个状态变换到另一个状态,或者是使一个输入或者一种行为的发生.一个有 ...

  9. 新FSM的一些思路

    好久之前写过一篇关于状态机的小例子,可以看这里http://www.cnblogs.com/mawanli/p/5966080.html,这篇博客首先感谢需要感谢当时看到凉鞋的笔记博客, 凉鞋的博客地 ...

随机推荐

  1. C# WCF的POST请求包含Stream及多个参数

    当使用WCF的API的POST请求时,如果参数列表里,除了Stream类型形参,还具有多个形参, 在寄宿过程中会报错: 约定"IService1"中的操作"DoWork& ...

  2. Struts2与Hibernate整合

    时间:2017-1-26 02:00 1.创建一个Web项目2.导入jar包    3.引入配置文件    struts.xml    hibernate.cfg.xml    log4j.prope ...

  3. 超详细教程2021新版oracle官网下载Windows JAVA-jdk11并安装配置(其他版本流程相同)

    异想之旅:本人博客完全手敲,绝对非搬运,全网不可能有重复:本人无团队,仅为技术爱好者进行分享,所有内容不牵扯广告.本人所有文章发布平台为CSDN.博客园.简书和开源中国,后期可能会有个人博客,除此之外 ...

  4. Heartbeat+HAProxy+MySQL半复制高可用架构

    目录 一 基础环境 二 架构设计 三 安装MySQL 3.1 安装MySQL 3.2 初始化MySQL 四 配置MySQL半同步 4.1 加载插件 4.2 配置半同步复制 4.3 master创建账号 ...

  5. Redis实现主从复制以及sentinel的配置

    redis 是一个高性能的 key-value 数据库. redis 的出现,很大程度补偿了 memcached 这类 keyvalue 存储的不足,在部分场合可以对关系数据库起到很 好的补充作用.它 ...

  6. noip模拟39

    \(\color{white}{\mathbb{百般红紫博众爱,正是芳菲斗艳时,名之以:牡丹}}\) %%% szs巨佬AK \(t1\).\(t4\) 都会做,剩下两道好像都不太会,再次扫描到知识盲 ...

  7. SNMP协议之序言

    最近两周公司分配一个任务:使用snmp协议做一个网管,来配置我们的产品.这可以说是我第一次听说这个协议,我问了一下周围的同事这是个什么协议,同事说"简单网络管理协议",其实这个协议 ...

  8. Python使用openpyxl模块操作Excel表格

    ''' Excel文件三个对象 workbook: 工作簿,一个excel文件包含多个sheet. sheet:工作表,一个workbook有多个,表名识别,如"sheet1",& ...

  9. ABP VNext发布遇到的坑

    本地调试没有问题,发布后通过Token调用其他API时,出现返回JSON中提示:Authorization failed! Given policy has not granted. 需要修改apps ...

  10. 手动制作Docker镜像

    手动制作 Docker 镜像 前言 a. 本文主要为 Docker的视频教程 笔记. b. 环境为 CentOS 7.0 云服务器(用来用去感觉 Windows 的 Docker 出各种问题,比如使用 ...