经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 游戏设计 » 查看文章
简述游戏开发中的状态机
来源:cnblogs  作者:White丶纯白  时间:2019/11/6 8:34:39  对本文有异议

为什么我们需要状态机

实行较多状态的角色,把动作全写在一个部分中会导致维护成本高,拓展性低
例如:走路,跳跃,射击,躲避的相互转换,有些可以转换,有些不能,实现逻辑复杂
(满屏幕都是if - else)

状态模式switch实现

  1. //包含着所有的状态
  2. enum class State{StateA, StateB, StateC, ...} activeState;
  3. ...
  4. //通过switch语句切换状态,根据具体情况实现细节
  5. switch (activeState)
  6. {
  7. case State.StateA:
  8. ...
  9. break;
  10. case State.StateB:
  11. ...
  12. break;
  13. .......
  14. }
  15. ...

状态机的原形,用一个枚举表示当前的状态,通过填充完善switch语句实现状态之间的切换,但是依然有维护成本高拓展低的缺点(虽然确实是比用if - else堆好)

Finite State Machine(FSN)有限状态机

最基本的状态机,一般来说其他状态机都是这种状态机的变体
对于状态机的理解,最好就是画个图(如图结构,方框是状态,箭头是状态之间的联系)

有限状态机强调的是状态之间的切换,以及对不同状态的封装,所以实现方法一般可以根据需求调整
以下参考了《游戏人工智能》的实现
首先需要个基类State和基类Translation

  1. //状态基类,所有状态都继承这个类
  2. class State
  3. {
  4. public:
  5. virtual ~State(){}
  6. virtual OnStateEnter(){} //进入此状态执行一次
  7. virtual OnUpdate(){} //每一帧执行一次
  8. virtual OnStateExit(){} //跳出状态时调用一次
  9. list<Translation> translations; //状态迁移列表
  10. };
  11. //状态迁移
  12. class Translation
  13. {
  14. public:
  15. virtual ~Translation(){}
  16. virtual bool isValid() = 0; //用于判定迁移,可切换返回true
  17. virtual State* getNextState() = 0; //进入下一个状态
  18. virtual void onTransition(){} //迁移时调用
  19. };

State是每一个状态都会继承的基类,translations中存着他指向其他状态的Translation,通过每一帧遍历所有Translation的isValid()来判定是否可以跳转,若可以跳转则执行自身的OnStateExit(),并将当前的状态设置为getNextState()获得的状态

然后还有状态机类,用来管理所有状态:

  1. //状态机类
  2. class FiniteStateMachine
  3. {
  4. public:
  5. void Update(); //每一帧运行一次
  6. State* initialState; //初始状态
  7. State* activeState; //正在运行的状态
  8. protected:
  9. list<State> states; //所有状态的实例
  10. };
  11. void FiniteStateMachine::Update()
  12. {
  13. //遍历活动状态的所有迁移,若有可用的,则切换状态
  14. list<Translation>::iterator itr = activeState->translations.begin();
  15. for (int i = 0; i < activeState->translations.size(); ++i, ++itr)
  16. {
  17. if (itr->isValid())
  18. {
  19. activeState->OnStateExit(); //退出调用
  20. activeState = itr->getNextState(); //切换活动状态
  21. itr->onTransition(); //切换调用
  22. activeState->OnStateEnter(); //进入调用
  23. return; //直接返回
  24. }
  25. }
  26. //如果没有状态切换,运行一次update
  27. activeState->OnUpdate();
  28. }

接下来具体的状态细节就要具体继承,具体实现

Hierarchical Finite State Machine (HFSM) 分层状态机

分层状态机相当于对有限状态机的进一步封装,将复数个状态封装成一个大的状态,再用一个“历史状态”记录切出此状态时运行的子状态,就可以在大状态间切换(结构如图)

图中将StateA和StateB加入到一个更高层的状态StateD中,只需退出时记录状态,就可以在CD状态间切换,增加了状态C的复用性(省略了AC,BC间的联系)
主要思想一是包装更高的层次,二是高层的切换放到更高层来觉得以提高复用
分层状态机的实现主要分两种:
一、父状态就是一个状态机,可以往里面添加状态
二、添加一个状态栈储存父子状态,每一个状态都是栈下一个状态的子状态,进入状态时入栈,结束状态时出栈并发送一个消息,新栈顶状态不能处理就再出栈,直到栈顶状态能处理这个消息为止。

并发状态机

并发状态机可以理解为一个对象拥有两个同时运作的状态机,两个状态机相互独立(但可以通过修改对象的状态进行通信),例如我们可以将腿部动作(站立,下蹲,奔跑)和手部动作(持枪,空手,瞄准)分离。

下推状态机

下推状态机的核心是他有一个状态栈(但和层次状态机实现的栈完全不同,层次状态机的栈是为了记录父状态,这个栈是为了纪录上一个状态)。
状态栈主要解决的是状态机无法得到上一轮执行的状态。
实现时,在状态机中加一个栈,在进入状态时将状态入栈,退出状态时将状态出栈,运行时则运行栈顶的状态。
例如,我在做作业的时候饿了,想去吃东西。饿了去吃东西是多数状态都能进入的状态,并且结束“吃东西”的状态后我要回复原来的状态。

在运行时,状态机已经将“做作业“入栈
然后“我饿了”,将“吃东西”入栈
“吃东西”结束,将“吃东西”出栈
继续运行栈顶的“做作业”(事实上不可能)

若有错误,欢迎指出

原文链接:http://www.cnblogs.com/yasoudream/p/11802866.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号