【Cocos2d-x状态机篇】第02章--状态模式之我很胖但我很强!
笨木头花心贡献,啥?花心?不呢,是用心~
转载请注明,原文地址:http://blog.csdn.net/musicvs/article/details/8348323
正文:
状态机的应用当然就少不了状态模式了,因为它们都有“状态”两个字。
(旁白:总感觉这句话十分不可靠==)
本章我们来简单地介绍一下状态模式,并且利用状态模式优化我们的有限状态机的实现。
1.什么是状态模式
说实话,我不知道,但我知道怎么使用...
用一句话来概括,也许是这样:同一件事情,让不同的人去做,每个人都会用自己的方式来做事,但,同一时间,只会让一个人在做这件事情。由老板来决定某一刻由谁来做事。
(旁白:又你可爱的妹纸的,这明明是两句话,两个句话有没有==)
用程序来说,也许是这样:同一个动作,让不同的类去执行,每个类都有自己独特的处理方式,至于由哪个类来执行这个动作,要根据当前的状态来判断。并且,不同的类执行完动作之后,会切换状态。
(旁白:还是没听懂。。。)
OK,我相信大家都明白了什么是状态模式了,接下来我们把第01章的例子稍微改改,很简单的~!
(旁白:等等,我压根儿就没搞懂什么是状态模式啊!)
好吧,我画了一个图,帮助大家理解:
图中有一个对象(蓝色方块),有三个状态处理类。
比如我有一件事情要做,那就是,起床之后要做的事情,但是由哪个类来执行这件事情呢?这要根据我的当前状态来决定(我有三种状态:肚子饿,想看电影,想吐槽),默认的状态是肚子饿。
然后,今天起床,我的状态是“肚子饿”。那我就会自动调用小木厨师来执行事件,执行完之后,状态会切换到“想看电影”。
那么,第二天,我起床的状态就是“想看电影”。那我就会自动调用电影院来执行事件,执行完之后,状态会切换到“想吐槽”。
第三天,我起床的状态就是“想吐槽”。那我就会自动调用吐槽旁白来执行事件,执行完之后,状态会切换到“肚子饿”。
第四天,我起床之后的状态就是“肚子饿”。那我就会自动调用小木厨师来执行事件,执行完之后,状态切换到“想看电影”。
第五天,我起床...(旁白:停~!!!你想说到天亮吗?!)
其实这个例子有点不准确,甚至是十分不准确,但是对于理解状态模式还是有点帮助了。
现在,大家在接着往下看之前,请确认你已经大概了解状态模式(起码去百度过,看过一篇正式介绍状态模式的文章)。因为接下来的代码和上面那张图的差别还是不小的,如果对状态模式不理解,就会产生混乱。
那么,用什么方法实现自动调用哪个类呢?当然是多态了,小木厨师、电影院、吐槽旁白这三个类都继承了同一个父类,它们就是我们要说的状态类了。
2.用状态模式实现有限状态机
还记得上一章的Mutou类吗?兴趣爱好很广泛的那个~(旁白:我不想吐槽了...)大家应该对它的update函数印象很深刻吧?那我就不贴出来了:
void Mutou::update( float dt ) {
/* 判断在每一种状态下应该做什么事情 */
switch(enCurState) {
case enStateWriteCode:
/* 如果累了就休息,并且切换到休息状态 */
if(isTire()) {
rest();
changeState(enStateRest);
}
break;
case enStateWriteArticle:
/* 如果累了就休息,并且切换到休息状态 */
if(isTire()) {
rest();
changeState(enStateRest);
}
break;
case enStateRest:
/* 一定的概率写代码,一定的概率写教程,并且切换到相应的状态 */
if(isWantToWriteArticle()) {
writeArticle();
changeState(enStateWriteArticle);
}
else {
writeCode();
changeState(enStateWriteCode);
}
break;
}
}
update函数会先判断木头当前所在的状态,然后再去执行相对应的逻辑。
(旁白:你刚刚说你不贴的代码的...)
那个旁白什么的,你刚刚也说你不想吐槽啊~!
但是啊,要是木头有好多好多状态,那这个函数也太庞大了~!是的,我们现在就要用到状态模式了,很简单的,别走神咯~!
3.状态基类
首先,我们需要一个状态基类,它只有一个抽象方法execute,表示要执行一件事情。至于执行什么事情,由它的子类来决定。
/*
文件名: State.h
描 述: 状态基类
创建人: 笨木头 (CSDN博客:http://blog.csdn.net/musicvs)
创建日期: 2012.12.17
*/
#ifndef __I_STATE_H__
#define __I_STATE_H__
class MutouT;
class I_State {
public:
virtual void execute(MutouT* mutou) = 0;
};
#endif
4三种状态对应的状态类
接下来,我们要实现最核心的类:状态类。
木头有3种状态:写代码、写教程、休息。
/*
文件名: StateWirteCode.h
描 述: 写代码状态
创建人: 笨木头 (CSDN博客:http://blog.csdn.net/musicvs)
创建日期: 2012.12.17
*/
#ifndef __STATE_WRITE_CODE_H__
#define __STATE_WRITE_CODE_H__
#include "I_State.h"
class MutouT;
class StateWirteCode : public I_State {
public:
virtual void execute( MutouT* mutou );
};
#endif
/* cpp文件 */
#include "StateWirteCode.h"
#include "StateRest.h"
#include "MutouT.h"
void StateWirteCode::execute( MutouT* mutou ) {
/* 如果累了就休息,并且切换到休息状态 */
if(mutou->isTire()) {
mutou->rest();
mutou->changeState(new StateRest());
}
}
上面这个就是写代码状态类,它继承了I_State,拥有一个execute方法,它表示,在写代码状态下执行一个动作。
那么,接下来,另外两种状态的类也是一样的,唯一不同的就是execute的具体实现。
/*
文件名: StateWirteArticle.h
描 述: 写教程状态
创建人: 笨木头 (CSDN博客:http://blog.csdn.net/musicvs)
创建日期: 2012.12.17
*/
#ifndef __STATE_WRITE_ARTICLE_H__
#define __STATE_WRITE_ARTICLE_H__
#include "I_State.h"
class MutouT;
class StateWriteArticle : public I_State {
public:
virtual void execute( MutouT* mutou );
};
#endif
/* cpp文件 */
#include "StateWriteArticle.h"
#include "StateRest.h"
#include "MutouT.h"
void StateWriteArticle::execute( MutouT* mutou ) {
/* 如果累了就休息,并且切换到休息状态 */
if(mutou->isTire()) {
mutou->rest();
mutou->changeState(new StateRest());
}
}
/*
文件名: StateRest.h
描 述: 休息状态
创建人: 笨木头 (CSDN博客:http://blog.csdn.net/musicvs)
创建日期: 2012.12.17
*/
#ifndef __STATE_REST_H__
#define __STATE_REST_H__
#include "I_State.h"
class MutouT;
class StateRest : public I_State {
public:
virtual void execute( MutouT* mutou );
};
#endif
/* cpp文件 */
#include "StateRest.h"
#include "StateWriteArticle.h"
#include "StateWirteCode.h"
#include "MutouT.h"
void StateRest::execute( MutouT* mutou ) {
/* 一定的概率写代码,一定的概率写教程,并且切换到相应的状态 */
if(mutou->isWantToWriteArticle()) {
mutou->writeArticle();
mutou->changeState(new StateWriteArticle());
}
else {
mutou->writeCode();
mutou->changeState(new StateWirteCode());
}
}
5.新的木头类
为了使用状态模式,Mutou类要修改,先看看头文件:
#ifndef __MUTOU_T_H__
#define __MUTOU_T_H__
#include "cocos2d.h"
USING_NS_CC;
class I_State;
class MutouT : public CCNode {
public:
CREATE_FUNC(MutouT);
virtual bool init();
bool isTire(); /* 判断是否写代码写累了 */
bool isWantToWriteArticle(); /* 是否想写教程 */
void writeCode(); /* 写代码 */
void writeArticle(); /* 写教程 */
void rest(); /* 休息 */
void changeState(I_State* state); /* 切换状态 */
virtual void update(float dt);
private:
/* 存放当前状态类 */
I_State* mCurState;
};
#endif
和以前的代码区别并不大,有两处修改:
1.changeState的参数变了,变成了I_State,同时,表示状态的枚举类也删掉了,因为已经有了状态类。
2.多了一个I_State成员变量,表示当前的状态,同时,表示状态的枚举变量删掉了,因为已经有了状态类。
那么,我们之前的逻辑几乎没有什么变化,依旧是在木头的update函数里做文章,只不过,这次的update函数可就简单多了~~~
(旁白:真的吗?倒是有点兴趣~)
#include "MutouT.h"
#include "I_State.h"
bool MutouT::init() {
mCurState = NULL;
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.");
}
void MutouT::changeState( I_State* state ) {
CC_SAFE_DELETE(mCurState);
mCurState = state;
}
void MutouT::update( float dt ) {
mCurState->execute(this);
}
前面几乎没有变,看看最后那个:
voidMutouT::update(floatdt){
mCurState->execute(this);
}
这个就是新的update函数的处理了,是不是很简单?
先看看效果再解释,修改HelloWorld的init函数:
bool HelloWorld::init()
{
bool bRet = false;
do
{
CC_BREAK_IF(! CCLayer::init());
/* 新建木头2角色 */
mMutou = MutouT::create();
/* 初始化木头的状态为休息 */
mMutou->changeState(new StateRest());
this->addChild(mMutou);
bRet = true;
} while (0);
return bRet;
}
和以前差不多,只是把Mutou类换成新的MutouT类。
(旁白:MutouT?就是MutouTow的意思?也就是Mutou2?噗,是的,木头是挺2的~)
然后用调试模式运行项目,将看到以下输出:
mutouiswirtingCode.
mutouisresting.
mutouiswritingarticle.
mutouisresting.
mutouiswritingarticle.
mutouisresting.
mutouiswirtingCode.
mutouisresting.
mutouiswirtingCode.
mutouisresting.
mutouiswirtingCode.
OK,和以前一样的效果。
稍微解释一下,其实这就是简单地利用了多态。神奇的地方就在execute这个函数,这个函数里面会根据不同的情况切换MutouT的当前状态,比如写教程状态的execute函数:
void StateWriteArticle::execute( MutouT* mutou ) {
/* 如果累了就休息,并且切换到休息状态 */
if(mutou->isTire()) {
mutou->rest();
mutou->changeState(new StateRest());
}
}
如果累了,就切换到休息状态,那么,执行完这个函数之后,MutouT的状态其实就已经改变了,变成了休息状态,那么下一次的update函数就会调用休息状态的execute函数。以此类推。
看一个图,会不会好理解一些?
好吧,我承认我解释得有点糟糕,希望大家能看明白...
(旁白:我已经晕了。。。)
分享到:
相关推荐
资源名称:Cocos2d-x实战:JS卷——Cocos2d-JS开发内容简介:本书是介绍Cocos2d-x游戏编程和开发技术书籍,介绍了使用...基础篇包括第2章~第8章,Cocos2d- 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。
cocos2d-x-2.1.5
Cocos2d-x游戏编程——C++篇(电子工业出版社,徐飞 著)书本配套的光盘代码,
在使用cocos2d-x开发游戏的过程中,为了实现逻辑和显示相分离。 在下通宵了一个晚上,写出了该事件类。 谨记,该事件只能用于cocos2d-x中。 事件发送者需要继承EventDispatcher类 事件接收者需要继承EventHandle类...
Cocos2d-x是移动跨平台开发最流行的游戏引擎,而本书是一本很全面的、比较‘接地气’的游戏开发教程。书中汇聚了热门手机游戏《捕鱼达人》开发的实战经验,作者从最基础的内容开始,逐步深入地介绍了Cocos2d-x的相关...
cocos2d-x实战项目 01.cocos2d-x原理及环境配置.rar 03.cocostudio使用方法及UI控制.rar 04.XML文件读取与骨骼动画.rarcocos2d-x实战项目 01.cocos2d-x原理及环境配置.rar 03.cocostudio使用方法及UI控制.rar 04.XML...
资源名称:大富翁手机游戏开发实战基于Cocos2d-x3.2引擎内容简介:李德国编著的《大富翁手机游戏开发实战(基于 Cocos2d-x3.2引擎)》使用Cocos2d-x游戏引擎技术,带领读者一步一步从零开始进行大富翁移动游戏的开发...
cocos2d-x-3.2下载,不多说。或者可以下载另一个资源 cocos引擎老版本集合(cocos2d-x-2.2.1 - 3.5) http://download.csdn.net/download/crazymagicdc/9982656
【Cocos2d-x 状态机篇】第03章--真正的状态机来了~! .教程源代码 教程地址:http://blog.csdn.net/musicvs/article/details/8348353
资源名称:Cocos2D-X游戏开发技术精解内容简介:Cocos2D-X是一款支持多平台的 2D手机游戏引擎,支持iOS、Android、BlackBerry等众多平台。当前,很多移动平台流行的游戏,都是基于Cocos2D-X开发的。 《Cocos2D-X...
这是我重新弄的cocos2d-x-3.0的类图.之前别人兄台弄的,有些不全面,有些地方错误.我这个可以说是最新的了.每个类添加了中文的详细注解,同时也添加了中文的类名称翻译.这样对cocos2d-x-3.0的框架比较好上手. 有兴趣的...
精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发
cocos2d-x 3.0 人物行走 . 包里有代码和 图片资源.
经典版本 方便下载 源码 旧版本 3.8 官网找不到了 cocos2d-x-3.8.zip
《Cocos2D-X游戏开发技术精解》详细介绍如何使用Cocos2D-X引擎开发自己的移动平台游戏。全书共15章,主要内容包括:Cocos2D-X引擎简介;如何建立跨平台的开发环境;引擎的核心模块——渲染框架;如何实现动态画面和...
Cocos2d-x-3.x游戏开发之旅-钟迪龙著 全新pdf版和附书代码(代码为工程文件,可复制) 附带目录标签
cocos2d-x 动画工具 Flash2Cocos2d-x 1.3
Cocos2d-x windows vs2010 配置图文详解
Cocos2d-x 3.x游戏开发实战pdf含目录,内容详细,强烈推荐给大家。
Cocos2d-x实战 JS卷 Cocos2d-JS开发 PDF 电子书完整版本