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

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

概述cocos2d-x 游戏开发有限状态机(FSM) (四) 虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作。SMC(http://smc.sourceforge.net/)就是这样的工具。下载地址: http://sourceforge.net/projects/smc/files/latest/download 在bin下面的Smc.jar是用于生成状态类 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%%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.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  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) (四)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1034879.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-24
下一篇 2022-05-24

发表评论

登录后才能评论

评论列表(0条)

保存