cocos2d-x 游戏开发之有限状态机(FSM) (四)
cocos2d-x 游戏开发之有限状态机(FSM) (四)
虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作。SMC(http://smc.sourceforge.net/)就是这样的工具。下载地址:
http://sourceforge.net/projects/smc/files/latest/download
在bin下面的Smc.jar是用于生成状态类的命令行工具。使用如下命令:
- $ java -jar Smc.jar Monkey.sm
1 真实世界的FSM
首先定义一个状态机纯文本文件:Monkey.sm,内容如下:
- // cheungmine
- // 2015-01-22
- // entity class
- %class Monkey
- // entity class header
- %header Monkey.h
- // inital state
- %start MonkeyMap::STOP
- // entity state map
- %map MonkeyMap
- %%
- STOP
- Entry {
- stop();
- }
- Exit {
- exit();
- }
- {
- walk WALK {}
- }
- WALK
- Entry {
- walk();
- }
- Exit {
- exit();
- }
- {
- stop STOP {}
- turn TURN {}
- }
- TURN
- Entry {
- turn();
- }
- Exit {
- exit();
- }
- {
- walk WALK {}
- }
- %%
其中%class Monkey 说明实体类的名字:Monkey (Monkey.h和Monkey.cpp)
%header 指定头文件:Monkey.h
%map 指明状态图类,这个类包含全部状态。这里是:MonkeyMap
%start 指明其实的状态,这里是STOP,对应的类是:MonkeyMap_STOP
%%...%%之间的部分定义每个状态。格式如下:
- STOP // 状态名
- Entry {
- // 执行这个函数进入该状态
- stop();
- }
- Exit {
- // 执行这个函数退出该状态
- exit();
- }
- {
- // 状态切换逻辑
- walk WALK {}
- }
当运行下面的命令,会自动生成文件:Monkey_sm.h和Monkey_sm.cpp。连同自带的statemap.h一起加入到项目中。
- java -jar Smc.jar Monkey.sm
2 实体类
业务逻辑仍然要我们自己实现,那就是写Monkey.h和Monkey.cpp。不过这次写Monkey类需要按一定的规则,下面是源代码:
- // Monkey.h
- //
- #ifndef MONKEY_H_
- #define MONKEY_H_
- #include "cocos2d.h"
- USING_NS_CC;
- #include "Monkey_sm.h"
- #define MAX_STOP_TIME 3
- #define MAX_WALK_TIME 10
- #define MAX_WALK_DIST 200
- class Monkey : public Node
- {
- public:
- CREATE_FUNC(Monkey);
- virtual bool init();
- void stop();
- void walk();
- void turn();
- void exit();
- private:
- MonkeyContext * _fsm;
- int _step;
- int _curPos;
- time_t _curTime;
- // Sprite * _sprite;
- private:
- void onIdleStop(float dt)
- {
- int d = (int) (time(0) - _curTime);
- if (d > MAX_STOP_TIME) {
- _fsm->walk();
- }
- }
- void onIdleWalk(float dt)
- {
- if (_curPos > MAX_WALK_DIST || _curPos < -MAX_WALK_DIST) {
- _fsm->turn();
- }
- int d = (int) (time(0) - _curTime);
- if (d > MAX_WALK_TIME) {
- _fsm->stop();
- }
- _curPos += _step;
- }
- void onIdleTurn(float dt)
- {
- _fsm->walk();
- }
- };
- #endif // MONKEY_H_
上面的onIdle????是触发状态的回调函数,实体状态改变的业务逻辑在这里实现。
- // Monkey.cpp
- //
- #include "Monkey.h"
- #include <time.h>
- #include <assert.h>
- void Monkey::exit()
- {
- this->unscheduleAllCallbacks();
- cocos2d::log("exit()");
- }
- bool Monkey::init()
- {
- _step = 1;
- _curPos = 0;
- _curTime = time(0);
- // _sprite = Sprite::create("monkey.png");
- // addChild(_sprite);
- _fsm = new MonkeyContext(*this);
- assert(_fsm);
- _fsm->setDebugFlag(true);
- _fsm->enterStartState();
- return true;
- }
- void Monkey::stop()
- {
- _curTime = time(0);
- cocos2d::log("stop(): pos=%d", _curPos);
- this->schedule(schedule_selector(Monkey::onIdleStop), 0.1f);
- }
- void Monkey::walk()
- {
- _curTime = time(0);
- cocos2d::log("walk(): pos=%d", _curPos);
- this->schedule(schedule_selector(Monkey::onIdleWalk), 0.1f);
- }
- void Monkey::turn()
- {
- _step *= -1;
- cocos2d::log("turn(): step=%d", _step);
- this->schedule(schedule_selector(Monkey::onIdleTurn), 0.1f);
- }
3 状态机类
框架代码Smc已经帮我们生成好了:Monkey_sm.h和Monkey_sm.cpp:
- //
- // ex: set ro:
- // DO NOT EDIT.
- // generated by smc (http://smc.sourceforge.net/)
- // from file : Monkey.sm
- //
- #ifndef MONKEY_SM_H
- #define MONKEY_SM_H
- #define SMC_USES_IOSTREAMS
- #include "statemap.h"
- // Forward declarations.
- class MonkeyMap;
- class MonkeyMap_STOP;
- class MonkeyMap_WALK;
- class MonkeyMap_TURN;
- class MonkeyMap_Default;
- class MonkeyState;
- class MonkeyContext;
- class Monkey;
- class MonkeyState :
- public statemap::State
- {
- public:
- MonkeyState(const char * const name, const int stateId)
- : statemap::State(name, stateId)
- {};
- virtual void Entry(MonkeyContext&) {};
- virtual void Exit(MonkeyContext&) {};
- virtual void stop(MonkeyContext& context);
- virtual void turn(MonkeyContext& context);
- virtual void walk(MonkeyContext& context);
- protected:
- virtual void Default(MonkeyContext& context);
- };
- class MonkeyMap
- {
- public:
- static MonkeyMap_STOP STOP;
- static MonkeyMap_WALK WALK;
- static MonkeyMap_TURN TURN;
- };
- class MonkeyMap_Default :
- public MonkeyState
- {
- public:
- MonkeyMap_Default(const char * const name, const int stateId)
- : MonkeyState(name, stateId)
- {};
- };
- class MonkeyMap_STOP :
- public MonkeyMap_Default
- {
- public:
- MonkeyMap_STOP(const char * const name, const int stateId)
- : MonkeyMap_Default(name, stateId)
- {};
- virtual void Entry(MonkeyContext&);
- virtual void Exit(MonkeyContext&);
- virtual void walk(MonkeyContext& context);
- };
- class MonkeyMap_WALK :
- public MonkeyMap_Default
- {
- public:
- MonkeyMap_WALK(const char * const name, const int stateId)
- : MonkeyMap_Default(name, stateId)
- {};
- virtual void Entry(MonkeyContext&);
- virtual void Exit(MonkeyContext&);
- virtual void stop(MonkeyContext& context);
- virtual void turn(MonkeyContext& context);
- };
- class MonkeyMap_TURN :
- public MonkeyMap_Default
- {
- public:
- MonkeyMap_TURN(const char * const name, const int stateId)
- : MonkeyMap_Default(name, stateId)
- {};
- virtual void Entry(MonkeyContext&);
- virtual void Exit(MonkeyContext&);
- virtual void walk(MonkeyContext& context);
- };
- class MonkeyContext :
- public statemap::FSMContext
- {
- public:
- explicit MonkeyContext(Monkey& owner)
- : FSMContext(MonkeyMap::STOP),
- _owner(&owner)
- {};
- MonkeyContext(Monkey& owner, const statemap::State& state)
- : FSMContext(state),
- _owner(&owner)
- {};
- virtual void enterStartState()
- {
- getState().Entry(*this);
- }
- inline Monkey& getOwner()
- {
- return *_owner;
- };
- inline MonkeyState& getState()
- {
- if (_state == NULL)
- {
- throw statemap::StateUndefinedException();
- }
- return dynamic_cast<MonkeyState&>(*_state);
- };
- inline void stop()
- {
- getState().stop(*this);
- };
- inline void turn()
- {
- getState().turn(*this);
- };
- inline void walk()
- {
- getState().walk(*this);
- };
- private:
- Monkey* _owner;
- };
- #endif // MONKEY_SM_H
- //
- // Local variables:
- // buffer-read-only: t
- // End:
- //
- //
- // ex: set ro:
- // DO NOT EDIT.
- // generated by smc (http://smc.sourceforge.net/)
- // from file : Monkey.sm
- //
- #include "Monkey.h"
- #include "Monkey_sm.h"
- using namespace statemap;
- // Static class declarations.
- MonkeyMap_STOP MonkeyMap::STOP("MonkeyMap::STOP", 0);
- MonkeyMap_WALK MonkeyMap::WALK("MonkeyMap::WALK", 1);
- MonkeyMap_TURN MonkeyMap::TURN("MonkeyMap::TURN", 2);
- void MonkeyState::stop(MonkeyContext& context)
- {
- Default(context);
- }
- void MonkeyState::turn(MonkeyContext& context)
- {
- Default(context);
- }
- void MonkeyState::walk(MonkeyContext& context)
- {
- Default(context);
- }
- void MonkeyState::Default(MonkeyContext& context)
- {
- throw (
- TransitionUndefinedException(
- context.getState().getName(),
- context.getTransition()));
- }
- void MonkeyMap_STOP::Entry(MonkeyContext& context)
- {
- Monkey& ctxt = context.getOwner();
- ctxt.stop();
- }
- void MonkeyMap_STOP::Exit(MonkeyContext& context)
- {
- Monkey& ctxt = context.getOwner();
- ctxt.exit();
- }
- void MonkeyMap_STOP::walk(MonkeyContext& context)
- {
- context.getState().Exit(context);
- context.setState(MonkeyMap::WALK);
- context.getState().Entry(context);
- }
- void MonkeyMap_WALK::Entry(MonkeyContext& context)
- {
- Monkey& ctxt = context.getOwner();
- ctxt.walk();
- }
- void MonkeyMap_WALK::Exit(MonkeyContext& context)
- {
- Monkey& ctxt = context.getOwner();
- ctxt.exit();
- }
- void MonkeyMap_WALK::stop(MonkeyContext& context)
- {
- context.getState().Exit(context);
- context.setState(MonkeyMap::STOP);
- context.getState().Entry(context);
- }
- void MonkeyMap_WALK::turn(MonkeyContext& context)
- {
- context.getState().Exit(context);
- context.setState(MonkeyMap::TURN);
- context.getState().Entry(context);
- }
- void MonkeyMap_TURN::Entry(MonkeyContext& context)
- {
- Monkey& ctxt = context.getOwner();
- ctxt.turn();
- }
- void MonkeyMap_TURN::Exit(MonkeyContext& context)
- {
- Monkey& ctxt = context.getOwner();
- ctxt.exit();
- }
- void MonkeyMap_TURN::walk(MonkeyContext& context)
- {
- context.getState().Exit(context);
- context.setState(MonkeyMap::WALK);
- context.getState().Entry(context);
- }
- //
- // Local variables:
- // buffer-read-only: t
- // End:
- //
4 总结
FSM是一种固定的范式,因此采用工具帮我们实现可以减少犯错误的机会。输入的文件就是:实体.sm。我们把重点放在业务逻辑上,所以与状态有关的代码smc都帮我们生成好了。对比一下我们手工创建和smc框架工具自动生成的类:
在cocos2d-x中使用很简单:
- bool HelloWorld::init()
- {
- //////////////////////////////
- // 1. super init first
- if ( !Layer::init() )
- {
- return false;
- }
- auto rootNode = CSLoader::createNode("MainScene.csb");
- addChild(rootNode);
- auto closeItem = static_cast<ui::Button*>(rootNode->getChildByName("Button_1"));
- closeItem->addTouchEventListener(CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
- /////////////////// test ///////////////////////
- Monkey * mk = Monkey::create();
- addChild(mk);
- return true;
- }
就这样了!不明白的地方请仔细阅读:
Cocos2d-x游戏开发之旅(钟迪龙)
cocos2d-x 游戏开发之有限状态机(FSM) (四)的更多相关文章
- cocos2d-x 游戏开发之有限状态机(FSM) (三)
cocos2d-x 游戏开发之有限状态机(FSM) (三) 有限状态机简称FSM,现在我们创建一个专门的FSM类,负责管理对象(Monkey)的状态.然后Monkey类就实现了行为与状态分离.Monk ...
- cocos2d-x 游戏开发之有限状态机(FSM) (一)
cocos2d-x 游戏开发之有限状态机(FSM) (一) 参考:http://blog.csdn.net/mgphuang/article/details/5845252<Cocos2d-x游 ...
- cocos2d-x 游戏开发之有限状态机(FSM) (二)
cocos2d-x 游戏开发之有限状态机(FSM) (二) 1 状态模式
- 《C++游戏开发》笔记十四 平滑过渡的战争迷雾(二) 实现:真正的迷雾来了
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9712321 作者:七十一雾央 新浪微博:http:/ ...
- iOS cocos2d 2游戏开发实战(第3版)书评
2013是游戏爆发的一年,手游用户也是飞速暴增.虽然自己不做游戏,但也是时刻了解手机应用开发的新动向.看到CSDN的"写书评得技术图书赢下载分"活动,就申请了一本<iOS c ...
- java游戏开发杂谈 - 有限状态机
在不同的阶段,游戏所运行的逻辑.所显示的界面,都是不同的. 以五子棋举例,游戏开始.游戏中.胜负已分,对应的界面和逻辑都不同. 在游戏中,又分为:自己下棋.对方下棋.游戏暂停.悔棋等多个状态. 再比如 ...
- Unity3D游戏开发从零单排(四) - 制作一个iOS游戏
提要 此篇是一个国外教程的翻译,尽管有点老,可是适合新手入门. 自己去写代码.debug,布置场景,能够收获到非常多.游戏邦上已经有前面两部分的译文,这里翻译的是游戏的最后一个部分. 欢迎回来 在第一 ...
- DirectX12 3D 游戏开发与实战第四章内容(上)
Direct3D的初始化(上) 学习目标 了解Direct3D在3D编程中相对于硬件所扮演的角色 理解组件对象模型COM在Direct3D中的作用 掌握基础的图像学概念,例如2D图像的存储方式,页面翻 ...
- DirectX12 3D 游戏开发与实战第四章内容(下)
Direct3D的初始化(下) 学习目标 了解Direct3D在3D编程中相对于硬件所扮演的角色 理解组件对象模型COM在Direct3D中的作用 掌握基础的图像学概念,例如2D图像的存储方式,页面翻 ...
随机推荐
- Scala:函数式编程之下划线underscore
http://blog.csdn.net/pipisorry/article/details/52913548 python参考[python函数式编程:apply, map, lambda和偏函数] ...
- Leetcode解题-树(5.0.0)基础类
与第二章类似,LeetCode指定了TreeNode实现.为了方便后续习题的编写和测试,创建一个基础父类,包含TreeNode实现,以及create()和print()创建和打印树的方法.其中crea ...
- Redis集群功能预览
目前Redis Cluster仍处于Beta版本,Redis 3.0将会加入,在此可以先对其主要功能和原理进行一个预览.参考<Redis Cluster - a pragmatic approa ...
- 在Linux上的虚拟机上启动Oracle上报ORA-00845: MEMORY_TARGET not supported on this system的问题解决
解决办法: 1.将当前虚拟机的内容调整大一些(以下转载:http://jingyan.baidu.com/article/414eccf67b8baa6b421f0a60.html) VMware虚拟 ...
- 给定整数a1、a2、a3、...、an,判断是否可以从中选出若干个数,使得它们的和等于k(k任意给定,且满足-10^8 <= k <= 10^8)。
给定整数a1.a2.a3.....an,判断是否可以从中选出若干个数,使得它们的和等于k(k任意给定,且满足-10^8 <= k <= 10^8). 分析:此题相对于本节"寻找满 ...
- Java基本语法-----java运算符
这块的东西比较多 我写了太慢了 于是在word里写好贴出来供大家一起学习 运算符 -赋值运算符 -比较运算符 -逻辑运算符 -位运算符 -移位操作符 -三元运算符 [正在看本人博客的这位童鞋,我看你气 ...
- antlr v4 使用指南连载2——准备环境
antlr v4 开发环境 从上一篇文章的例子中可以知道,antlr有一套自己的语法来声明目标语言的语法,因此它本身就需要编译或者使用antlr提供的api来读取这些语法规则,并使之可 ...
- Android 自定义View-android学习之旅(十四)
自定义View的步骤 当andoid提供的系统组件不满足要求时候,完全可以集成View来派生自定义组件. 首定定义一个继承View的子类,然后重写他一个或几个方法. 重写的方法介绍 构造器:这是定制V ...
- UNIX/LINUX程序设计教程(1)-- 获取系统信息
1.主机标识 每一台机器都有一个主机名,主机名由系统管理员指定,在网络中主机名可能是一个网络域名. 函数 gethostname() 和 sethostname() 可以用来获取和设置主机 ...
- JAVA之旅(三十)——打印流PrintWriter,合并流,切割文件并且合并,对象的序列化Serializable,管道流,RandomAccessFile,IO其他类,字符编码
JAVA之旅(三十)--打印流PrintWriter,合并流,切割文件并且合并,对象的序列化Serializable,管道流,RandomAccessFile,IO其他类,字符编码 三十篇了,又是一个 ...