笨木头  2012-12-20 12:57     Cocos2d-x,Cocos2d-x2.0     阅读(7560)     评论(10)
转载请注明,原文地址: http://www.benmutou.com/archives/42
文章来源:笨木头与游戏开发

Cocos2d-x 状态机篇】第03--真正的状态机来了~!

 

笨木头花心贡献,啥?花心?不呢,是用心~

转载请注明,原文地址
http://blog.csdn.net/musicvs/article/details/8348353

 

正文:

 

前面两章介绍了一大堆东西,但似乎一直没有看到状态机这个东东,第02章里面说的那些,看起来也就是普通的状态模式的应用,我们似乎感觉不到状态机的存在啊~(虽然那确实是状态机的应用)。

(旁白:是的,是的~!我光顾着吐槽,都忘了这点了= =

 

那么,现在,我们来创建一个状态机类,它不神秘,它仅仅是用来管理对象的状态相关的东西,让MutouT类得到解脱。

1. 创建MutouTFSM

有限状态机简称FSM,我们现在来创建这样一个类:

/*
    文件名:    MutouTFSM.h
    描 述:    木头对象的状态机,用来管理状态
    创建人:    笨木头 (CSDN博客:http://blog.csdn.net/musicvs)

    创建日期:   2012.12.19
*/
#ifndef __MUTOUT_FSM_H__
#define __MUTOUT_FSM_H__

#include "cocos2d.h"
USING_NS_CC;

class I_State;
class MutouT;

class MutouTFSM : public CCNode {
public:
    static MutouTFSM* createWithMutouT(MutouT* mutou);
    bool initWithMutouT(MutouT* mutou);
    
    virtual void update(float dt);

    void changeState(I_State* state);   /* 切换状态 */

private:
    /* 存放当前状态类 */
    I_State* mCurState;

    /* 木头对象 */
    MutouT* mMutou;
};

#endif

有没有发现这个MutouTFSM和之前的MutouT类有点像?

现在,所有和状态有关的操作都放到MutouTFSM状态机类,MutouT类只要专心地做他该做的事情就好了(休息、写代码、写教程)。

看看MutouTFSM的实现:

#include "MutouTFSM.h"
#include "MutouT.h"
#include "I_State.h"

MutouTFSM* MutouTFSM::createWithMutouT( MutouT* mutou ) {
    MutouTFSM* fsm = new MutouTFSM();

    if(fsm && fsm->initWithMutouT(mutou)) {
        fsm->autorelease();
    }
    else {
        CC_SAFE_DELETE(fsm);
        fsm = NULL;
    }

    return fsm;
}

bool MutouTFSM::initWithMutouT( MutouT* mutou ) {
    this->mCurState = NULL;
    this->mMutou = mutou;
    mMutou->retain();
    return true;
}

void MutouTFSM::changeState( I_State* state ) {
    CC_SAFE_DELETE(mCurState);

    this->mCurState = state;
    
}

void MutouTFSM::update( float dt ) {
    this->mCurState->execute(mMutou);
}


 

很简单,MutouTFSM会保存一份MutouT对象,然后在update函数里执行当前状态的execute函数,简单的说,就是,MutouT类的changeStateupdate函数都放到MutouTFSM里了。

 

2. 被解放的MutouT

我们再来看看新的MutouT类:

#ifndef __MUTOU_T_H__
#define __MUTOU_T_H__

#include "cocos2d.h"
#include "MutouTFSM.h"
USING_NS_CC;

class I_State;
//class MutouTFSM;

class MutouT : public CCNode {
public:
    CREATE_FUNC(MutouT);
    virtual bool init();

    bool isTire();                      /* 判断是否写代码写累了 */
    bool isWantToWriteArticle();        /* 是否想写教程 */
    void writeCode();                   /* 写代码 */
    void writeArticle();                /* 写教程 */
    void rest();                        /* 休息 */

    MutouTFSM* getFSM();                /* 获取状态机对象 */

    virtual void update(float dt);
private:
    /* 木头状态机 */
    MutouTFSM* mFSM;
};
#endif


 

(旁白:你这个骗纸~!这个MutouT不是还有update函数吗?)

 

看到了吧,MutouT类多了一个MutouTFSM状态机变量,changeStateupdate函数已经被去掉了~

(旁白:喂,你假装看不到我吗?那个update函数很明显还在啊喂~!!)

 

然后我们看看MutouT的实现:

#include "MutouT.h"
#include "I_State.h"
#include "MutouTFSM.h"

bool MutouT::init() {
    mFSM = MutouTFSM::createWithMutouT(this);
    mFSM->retain();
    this->scheduleUpdate();
    return true;
}

bool MutouT::isTire() {
    /* 每次问木头累不累,他都会说:累~ */
    return true;
}

bool MutouT::isWantToWriteArticle() {
    /* 有10%的概率想写教程(好懒~!) */
    float ran = CCRANDOM_0_1();
    if(ran < 0.1f) {
        return true;
    }

    return false;
}

void MutouT::writeCode() {
    CCLOG("mutou is wirting Code.");
}

void MutouT::writeArticle() {
    CCLOG("mutou is writing article.");
}


void MutouT::rest() {
    CCLOG("mutou is resting.");
}

MutouTFSM* MutouT::getFSM() {
    return this->mFSM;
}

void MutouT::update( float dt ) {
    this->mFSM->update(dt);
}


 

和以前的实现是一样的,只是少了changeState函数,并且,留意到update函数了吗?

void MutouT::updatefloat dt ) {

    this->mFSM->update(dt);

}

是的,它实际上是调用了状态机的update函数。

(旁白:我就说它还在嘛。。。)

 

3. 这样抽离一个MutouTFSM状态机类有什么好处?

为嘛这么大费周章地整一个状态机类倒底有什么用?没发现什么新功能啊~

当然有用了,首先,这样做每个类的职责分明,就好比老大让我去做美工的工作,我才不愿意~!我可是一个写代码的人~

(旁白:噗。没事,我就吐吐槽。)

 

然后,万一以后我们想给MutouT类换状态呢?状态类的接口改了呢?(虽然这很不应该)难道我们要打开我们的MutouT类去修改吗?

(旁白:这有什么问题?)

 

其实我也不知道这有什么问题,所以我用了反问语气,希望能骗过读者~

(旁白:你可爱的妹纸的~!)

 

好了,到此为止,我们已经可以很好地使用状态机了...

啊才怪啊~!还不够~

我们不应该用update函数的~!

 

项目源码下载:  http://download.csdn.net/detail/musicvs/4912216

 

下一章,我们将介绍用事件驱动让我们的状态机完成无所不能的事情~!

 

10 条评论
  • musicvs 2012-12-21 08:08:00

    忘了给源代码了, 已补上:
    http://download.csdn.net/detail/musicvs/4912216
    0回复
  • tianshenshangjie 2012-12-29 12:58:00

    允许一个对象在其内部状态改变时改变它的行为,不同的状态下行为也不一样。写教程写代码 休息可以算是3中不同的状态。这三种状态不断的进行切换。如果你现在的状态增加一种新的状态怎么办。又或者你需要先各种状态之间的转换发生改变怎么办。解耦度不够。每个状态都是独立,状态的变迁是由对象的内部条件决定的
    0回复
  • musicvs 2012-12-29 13:04:00

    [reply]tianshenshangjie[/reply]

    嘿嘿,骚年说得对~
    你看看第04章符不符合你的要求?~
    0回复
  • hxq_001 2013-01-08 19:03:00

    写得不错。有一个专门的工具SMC,http://labs.grupow.com/blog/2012/03/27/how-to-integrate-the-finite-state-machine-compiler-with-cocos2d/
    给你介绍一下。
    0回复
  • musicvs 2013-01-09 08:33:00

    [reply]hxq_001[/reply]
    谢谢你,可惜我打不开网页,能不能发一个到我邮箱呢?(musicvs@163.com)
    0回复
  • musicvs 2013-01-09 08:42:00

    [reply]hxq_001[/reply]
    用了某种方式,我打开网页了...(你懂的。。。)
    0回复
  • hxq_001 2013-01-09 09:24:00

    [reply]musicvs[/reply]
    希望这篇文章能将你状态机教程能升华一下
    0回复
  • musicvs 2013-01-09 14:46:00

    [reply]hxq_001[/reply]
    谢谢,很有用,正在用我那糟糕的英文水平去理解
    0回复
  • qq634416025 2013-02-28 19:40:00

    你好 你的那个runrunrun Controler Entity那种 你是怎么想到要那么写呢 我完全想不到 我写代码的时候都把那些全部写在一个类的init里面 呜呜 我该怎么才能有这种思想呢?
    0回复
  • musicvs 2013-02-28 20:02:00

    [reply]qq634416025[/reply]
    呵呵,我之前也回复过你了,最好的办法就是继续全部写在一个init里面。当你发现无法忍受的时候,你自然会写到几个函数里面。
    然后,当你发现函数也太多了(几十个!甚至上百个!),你自然就会想到要写到不同的类里了。
    当你达到这种程度之后,你才要真正开始思考怎么设计代码才比较好,那时候,你可以研究一下设计模式。
    0回复
发表评论
粤ICP备16043700号

本博客基于 BlazorAnt Design Blazor 开发