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图像的存储方式,页面翻 ...
随机推荐
- J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP
J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言 搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理. ...
- EJB3基本概念、运行环境、下载安装与运行jboss
EJB3基本概念 什么是EJB: EJB(EnterpriceJavaBeans)是一个用于分布式业务应用的标准服务端组件模型.采用EJB架构编写的应用是可伸的.事务性的.多用户安全的.采用EJB编写 ...
- springmvc注解形式的开发参数接收
springmvc基于注解的开发 注解第一个例子 1. 创建web项目 springmvc-2 2. 在springmvc的配置文件中指定注解驱动,配置扫描器 <!-- sprimgmvc 注解 ...
- Android 在 SElinux下 如何获得对一个内核节点的访问权限
点击打开链接 Android 5.0下,因为采取了SEAndroid/SElinux的安全机制,即使拥有root权限,或者对某内核节点设置为777的权限,仍然无法在JNI层访问. 本文将以用户自定义的 ...
- Java学习之运算符使用注意的问题
运算符使用注意的问题 运算符(掌握) (1)算术运算符 A:+,-,*,/,%,++,-- B:+的用法 a:加法 b:正号 c:字符串连接符 C:/和%的区别 数据做除法操作的时候,/取得是商,%取 ...
- Spring Boot微服务架构入门
概述 还记得在10年毕业实习的时候,当时后台三大框架为主流的后台开发框架成软件行业的标杆,当时对于软件的认识也就是照猫画虎,对于为什么会有这么样的写法,以及这种框架的优势或劣势,是不清楚的,Sprin ...
- 【Netty源码学习】ServerBootStrap
上一篇博客[Netty源码学习]BootStrap中我们介绍了客户端使用的启动服务,接下来我们介绍一下服务端使用的启动服务. 总体来说ServerBootStrap有两个主要功能: (1)调用父类Ab ...
- Dynamics CRM2015 非基础语言环境下产品无法新建的问题
该现象出现在2015版本上,之前从没注意过这个问题不知道以前的版本是否存在. 我的安装包的基础语言是中文,第一张图有添加产品的按钮,切换到英文环境下后就没有了,一开始以为是系统做了隐藏处理,但用工具查 ...
- Android初级教程:Android中解析方式之pull解析
在安卓中有很多种解析方式.按照大方向有xml解析和json解析.而,细致的分,xml和json解析各有自己的很多解析方式.今天这一篇主要介绍xml解析中的pull解析.对于xml的解析方式,我之前在j ...
- 海量数据处理算法(top K问题)
举例 有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M.返回频数最高的100个词. 思路 首先把文件分开 针对每个文件hash遍历,统计每个词语的频率 使用堆进 ...