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图像的存储方式,页面翻 ...
随机推荐
- [boost] build boost with intel compiler 16.0.XXX
Introduction There are few information about how to compile boost with Intel compiler. This article ...
- Android图表库MPAndroidChart(九)——神神秘秘的散点图
Android图表库MPAndroidChart(九)--神神秘秘的散点图 今天所的散点图可能用的人不多,但是也算是图表界的一股清流,我们来看下实际的效果 添加的数据有点少,但是足以表示散点图了,我们 ...
- Scala actor的使用
Actor 为什么需要Actor? Actor的本质即万物皆Actor, Actor之间只有发送消息这一种通信方式.例如,无论是管理员让工作者干活,还是工作者把成果交还给管理员,它们之间也要通过发送消 ...
- 【ShaderToy】边栏的小雨伞
写在前面 我在9月份的时候对博客的主页换了个模板,一些童鞋可能会发现边栏多了个小雨伞的动画,再细心的同学可能会发现如果一直开着我的博客电脑耗电更快了--当然啦,也有可能你看到的是一团黑,这说明你该换更 ...
- 多线程之Java线程阻塞与唤醒
线程的阻塞和唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题.如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢复,这些都需要仔细考虑的细节.在Java ...
- Android初级教程:屏幕分辨率
在app编码中经常需要获取手机的屏幕分辨率(宽*高),原来我直接上网拷贝代码,但在使用过程中却发现诸多不便. 不便一:下面代码中的getWidth和getHeight在adt上提示deprecated ...
- Error处理:Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack tra
[2014-04-20 20:59:23 - MyDetectActivity] Dx trouble writing output: already prepared [2014-04-20 20 ...
- Java 学习之反射机制“解刨”分解类,并获取内容!
正常情况下,单纯的做开发是接触不到反射机制的(额,当然并不排除例外的情况了).下面我就对我学到的反射方面的知识做一个小小的总结,旨在复习和以后的查看. 原理分析: 所谓反射就是将一个类当做我们研究的对 ...
- python 内存数据库与远程服务
python 内存数据库与远程服务 需要import的python 内存数据库代码参考下面的链接: http://blog.csdn.net/ubuntu64fan/article/details/5 ...
- ffplay播放器移植VC的工程:ffplay for MFC
本文介绍一个自己做的FFPLAY移植到VC下的开源工程:ffplayfor MFC.本工程将ffmpeg项目中的ffplay播放器(ffplay.c)移植到了VC的环境下.并且使用MFC做了一套简单的 ...