虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作。SMC(http://smc.sourceforge.net/)就是这样的工具。下载地址:
http://sourceforge.net/projects/smc/files/latest/download
在bin下面的Smc.jar是用于生成状态类的命令行工具。使用如下命令:
$ java -jar Smc.jar Monkey.sm1 真实世界的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%%StopEntry { stop();}Exit { exit();}{ walk WALK {}}WALKEntry { walk();}Exit { exit();}{ stop Stop {} turn TURN {}}TURNEntry { 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.sm2 实体类
业务逻辑仍然要我们自己实现,那就是写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 200class 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,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,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) (四)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)