cocos2d-x 游戏开发之有限状态机(FSM)  (二)

1 状态模式

State是状态基类。它其实是一个接口,它有3个实现类,分别对应每个状态。Monkey类只需要维护State类,而具体的行为通过3个实现类完成。这就是多态。下面是完整的代码:

2 状态基类

  1. // State.h
  2. //
  3. #ifndef STATE_H_
  4. #define STATE_H_
  5.  
  6. class Monkey;
  7.  
  8. struct State
  9. {
  10. virtual void execute(Monkey *mk) = 0;
  11. };
  12.  
  13. #endif // STATE_H_

3 实现类

3.1 StopState

  1. // StopState.h
  2. //
  3. #ifndef STOP_STATE_H_
  4. #define STOP_STATE_H_
  5.  
  6. #include "State.h"
  7. #include "Monkey.h"
  8.  
  9. class StopState
  10. : public State
  11. {
  12. public:
  13. virtual void execute(Monkey *mk);
  14. };
  15.  
  16. #endif // STOP_STATE_H_

  1. // StopState.cpp
  2. //
  3. #include "StopState.h"
  4. #include "WalkState.h"
  5.  
  6. void StopState::execute(Monkey *mk)
  7. {
  8. if (mk->isStopTimeout()) {
  9. mk->changeState(new WalkState());
  10. mk->walk();
  11. }
  12. }

3.2 WalkState

  1. // WalkState.h
  2. //
  3. #ifndef WALK_STATE_H_
  4. #define WALK_STATE_H_
  5.  
  6. #include "State.h"
  7. #include "Monkey.h"
  8.  
  9. class WalkState
  10. : public State
  11. {
  12. public:
  13. virtual void execute(Monkey *mk);
  14. };
  15.  
  16. #endif // WALK_STATE_H_

  1. // WalkState.cpp
  2. //
  3. #include "WalkState.h"
  4. #include "TurnState.h"
  5. #include "StopState.h"
  6.  
  7. void WalkState::execute(Monkey *mk)
  8. {
  9. mk->walk();
  10.  
  11. if (mk->isWalkOutBorder()) {
  12. mk->changeState(new TurnState());
  13. mk->turn();
  14. } else if (mk->isWalkTimeout()) {
  15. mk->changeState(new StopState());
  16. mk->stop();
  17. }
  18. }

3.3 TurnState

  1. // TurnState.h
  2. //
  3. #ifndef TURN_STATE_H_
  4. #define TURN_STATE_H_
  5.  
  6. #include "State.h"
  7. #include "Monkey.h"
  8.  
  9. class TurnState
  10. : public State
  11. {
  12. public:
  13. virtual void execute(Monkey *mk);
  14. };
  15.  
  16. #endif // TURN_STATE_H_

  1. // TurnState.cpp
  2. //
  3. #include "TurnState.h"
  4. #include "WalkState.h"
  5.  
  6. void TurnState::execute(Monkey *mk)
  7. {
  8. mk->changeState((State*) new WalkState());
  9. mk->walk();
  10. }

4 Monkey

  1. #ifndef MONKEY_H_
  2. #define MONKEY_H_
  3.  
  4. #include <time.h>
  5.  
  6. #include "cocos2d.h"
  7. USING_NS_CC;
  8.  
  9. #include "State.h"
  10.  
  11. #define MAX_STOP_TIME 10
  12. #define MAX_WALK_TIME 20
  13.  
  14. #define MAX_WALK_DIST 100
  15.  
  16. class Monkey
  17. : public Node
  18. {
  19. public:
  20. Monkey()
  21. {
  22. log("Monkey()");
  23. }
  24.  
  25. CREATE_FUNC(Monkey);
  26.  
  27. virtual bool init()
  28. {
  29. _curPos = 0;
  30. _step = 1;
  31.  
  32. _curState = 0;
  33.  
  34. this->scheduleUpdate();
  35.  
  36. return true;
  37. }
  38.  
  39. void changeState(State * newState)
  40. {
  41. State * oldState = _curState;
  42. _curState = newState;
  43.  
  44. if (oldState) {
  45. delete oldState;
  46. }
  47. _curTime = time(0);
  48. }
  49.  
  50. void stop()
  51. {
  52. cocos2d::log("stop()");
  53. }
  54.  
  55. void walk()
  56. {
  57. _curPos += _step;
  58. cocos2d::log("walk(): pos=%d", _curPos);
  59. }
  60.  
  61. void turn()
  62. {
  63. _step *= -1;
  64. cocos2d::log("turn(): step=%d", _step);
  65. }
  66.  
  67. void update(float dt)
  68. {
  69. if (_curState) {
  70. _curState->execute(this);
  71. }
  72. }
  73.  
  74. private:
  75. State * _curState;
  76.  
  77. time_t _curTime;
  78.  
  79. int _curPos;
  80. int _step;
  81.  
  82. public:
  83. bool isStopTimeout()
  84. {
  85. return (time(0) - _curTime > MAX_STOP_TIME);
  86. }
  87.  
  88. bool isWalkTimeout()
  89. {
  90. return (time(0) - _curTime > MAX_WALK_TIME);
  91. }
  92.  
  93. bool isWalkOutBorder()
  94. {
  95. return (_curPos > MAX_WALK_DIST || _curPos < -MAX_WALK_DIST);
  96. }
  97. };
  98.  
  99. #endif // MONKEY_H_

5 总结

当我们需要添加了一种新的状态时,不需要去修改长长的条件判断语句了,只需要构造一个新的状态类,修改它的前序和后序状态类就可以了。对于任何一个状态的特有行为,都是独立的,不会混杂在其它状态的代码里。原为决定状态转移逻辑的那个长长的条件语句不见了,而是被分布在State的子类之间。另一方面,从设计的角度看,原先对当前状态的标识,是FSM内部的一个自有变量,状态与状态之间的转换也仅仅是表现为对自有变量的赋值,如果这个自有变量衍生为变量数组时,那极易出现FSM内部状态不一致的情况,而State的引入可以使得这样的情况变得相当简单。对于新版本的FSM来说,状态与状态之间的转换也成了原子化的操作,不需要兼顾多个变量的赋值。

既然所有状态机具有同样的规则和范式,那么状态机应该与具体对象无关,完全可以提炼出纯粹的状态机类来管理任何对象的状态。下节就完成这个任务。

cocos2d-x 游戏开发之有限状态机(FSM) (二)的更多相关文章

  1. cocos2d-x 游戏开发之有限状态机(FSM) (四)

    cocos2d-x 游戏开发之有限状态机(FSM) (四) 虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作.SMC(http://smc.sourceforge ...

  2. cocos2d-x 游戏开发之有限状态机(FSM) (三)

    cocos2d-x 游戏开发之有限状态机(FSM) (三) 有限状态机简称FSM,现在我们创建一个专门的FSM类,负责管理对象(Monkey)的状态.然后Monkey类就实现了行为与状态分离.Monk ...

  3. cocos2d-x 游戏开发之有限状态机(FSM) (一)

    cocos2d-x 游戏开发之有限状态机(FSM) (一) 参考:http://blog.csdn.net/mgphuang/article/details/5845252<Cocos2d-x游 ...

  4. 《C++游戏开发》笔记十二 战争迷雾:初步实现

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/9475979 作者:七十一雾央 新浪微博:http:/ ...

  5. iOS cocos2d 2游戏开发实战(第3版)书评

    2013是游戏爆发的一年,手游用户也是飞速暴增.虽然自己不做游戏,但也是时刻了解手机应用开发的新动向.看到CSDN的"写书评得技术图书赢下载分"活动,就申请了一本<iOS c ...

  6. java游戏开发杂谈 - 有限状态机

    在不同的阶段,游戏所运行的逻辑.所显示的界面,都是不同的. 以五子棋举例,游戏开始.游戏中.胜负已分,对应的界面和逻辑都不同. 在游戏中,又分为:自己下棋.对方下棋.游戏暂停.悔棋等多个状态. 再比如 ...

  7. (转载)如何学好iphone游戏开发

    转自:http://www.cnblogs.com/zilongshanren/archive/2011/09/19/2181558.html 自从发布<如何学习iphone游戏开发>到 ...

  8. 整理了一下浅墨大神的Visual C++/DirectX 9.0c的游戏开发手记

    还是非常棒的博客,只是没有一个文件夹.所以自己做了一个山寨文件夹在这里.便于随时查找. 前面31期从略. [Visual C++]游戏开发笔记三十二 浅墨DirectX提高班之中的一个 DirectX ...

  9. HTML5物理游戏开发 - 越野山地自行车(三)粉碎自行车

    自上一章公布到如今已时隔四月,实在对不住大家.让大家久等了~话说不是我不关注我的博客,而是事情一多起来写博客的时间就少了. 待到今日有空了,回头看了看自己曾经写的文章,猛得发现已经四个月不曾写文章了. ...

随机推荐

  1. 2016年年终CSDN博客总结

    2015年12月1日,结束了4个月的尚观嵌入式培训生涯,经过了几轮重重面试,最终来到了伟易达集团.经过了长达3个月的试用期,正式成为了伟易达集团的助理工程师. 回顾一年来的学习,工作,生活.各种酸甜苦 ...

  2. Racket 模拟SICP的流(延时计算)

    默认的Racket是要对函数参数进行求值的, 例如(f 1 (+ 1 2))里面,(+ 1 2)要先求值为3,变为(f 1 3)再进行下一步操作.因此, Racket若按照SICP使用define关键 ...

  3. 亲密接触Redis-第二天(Redis Sentinel)

    简介 经过上次轻松搭建了一个Redis的环境并用Java代码调通后,这次我们要来看看Redis的一些坑以及Redis2.8以后带来的一个新的特性即支持高可用特性功能的Sentinel(哨兵). Red ...

  4. [struts2学习笔记] 第五节 编写struts2的action代码

    本文地址:http://blog.csdn.net/sushengmiyan/article/details/40479299 官方文档: http://struts.apache.org/relea ...

  5. 【Netty源码分析】Reactor线程模型

    1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 时间回到十几年前,那时主流的CPU都还是单核(除了商用高性能的小机),CPU的核心频率是机器最重要的指标之一. 在Java领域当时比 ...

  6. 【Netty源码学习】BootStrap

    BootStrap是客户端的启动类,其主要功能就是设置必要的参数然后启动客户端. 实现如下: Bootstrap b = new Bootstrap(); b.group(group) .channe ...

  7. 安卓自定义日期控件(仿QQ,IOS7)

    还记得上篇:高大上的安卓日期时间选择器,本篇是根据上篇修改而来,先看下qq中日期选择的效果: 鉴于目前还没有相似的开源日期控件,因此本人花费了一些时间修改了下之前的日期控件,效果如图: 虽说相似度不是 ...

  8. 01_MyBatis EHCache集成及所需jar包,ehcache.xml配置文件参数配置及mapper中的参数配置

     1 与mybatis集成时需要的jar ehcache-core-2.6.5.jar mybatis-ehcache-1.0.2.jar Mybatis.日志.EHCache所需要的jar包如下 ...

  9. Android开发小问题集

    由于安卓系统比较复杂,开发中会发中会碰见各种小问题,在此做一些记录,只要觉得有必要就会添加进来. 1.触屏鼠标模式和触屏模式 开发android4.3高通400平台时,用atmel_max 640T作 ...

  10. UNIX网络编程——名字与地址转换(gethostbyname,gethostbyaddr,getservbyname,getservbyport,getaddrinfo,getnameinfo函数)

    名字和数值地址间进行转换的函数:gethostbyname和gethostbyaddr在主机名字与IPv4地址之间进行转换.getservbyname和getservbyport在服务器名字和端口号之 ...