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

1 状态模式

State是状态基类。它其实是一个接口,它有3个实现类,分别对应每个状态。Monkey类只需要维护State类,而具体的行为通过3个实现类完成。这就是多态。下面是完整的代码:

2 状态基类

// State.h
//
#ifndef STATE_H_
#define STATE_H_

class Monkey;

struct State
{
   virtual void execute(Monkey *mk) = 0;
};

#endif // STATE_H_

3 实现类

3.1 StopState

// StopState.h
//
#ifndef STOP_STATE_H_
#define STOP_STATE_H_

#include "State.h"
#include "Monkey.h"

class StopState
    : public State
{
public:
    virtual void execute(Monkey *mk);
};

#endif // STOP_STATE_H_

// StopState.cpp
//
#include "StopState.h"
#include "WalkState.h"

void StopState::execute(Monkey *mk)
{
    if (mk->isStopTimeout()) {
        mk->changeState(new WalkState());
        mk->walk();
    }
}

3.2 WalkState

// WalkState.h
//
#ifndef WALK_STATE_H_
#define WALK_STATE_H_

#include "State.h"
#include "Monkey.h"

class WalkState
    : public State
{
public:
    virtual void execute(Monkey *mk);
};

#endif // WALK_STATE_H_

// WalkState.cpp
//
#include "WalkState.h"
#include "TurnState.h"
#include "StopState.h"

void WalkState::execute(Monkey *mk)
{
    mk->walk();

    if (mk->isWalkOutBorder()) {
        mk->changeState(new TurnState());
        mk->turn();
    } else if (mk->isWalkTimeout()) {
        mk->changeState(new StopState());
        mk->stop();
    }
}

3.3 TurnState

// TurnState.h
//
#ifndef TURN_STATE_H_
#define TURN_STATE_H_

#include "State.h"
#include "Monkey.h"

class TurnState
    : public State
{
public:
    virtual void execute(Monkey *mk);
};

#endif // TURN_STATE_H_

// TurnState.cpp
//
#include "TurnState.h"
#include "WalkState.h"

void TurnState::execute(Monkey *mk)
{
    mk->changeState((State*) new WalkState());
    mk->walk();
}

4 Monkey

#ifndef MONKEY_H_
#define MONKEY_H_

#include <time.h>

#include "cocos2d.h"
USING_NS_CC;

#include "State.h"

#define MAX_STOP_TIME  10
#define MAX_WALK_TIME  20

#define MAX_WALK_DIST  100

class Monkey
    : public Node
{
public:
    Monkey()
    {
        log("Monkey()");
    }

    CREATE_FUNC(Monkey);

    virtual bool init()
    {
        _curPos = 0;
        _step = 1;

        _curState = 0;

        this->scheduleUpdate();

        return true;
    }

    void changeState(State * newState)
    {
        State * oldState = _curState;
        _curState = newState;

        if (oldState) {
            delete oldState;
        }
        _curTime = time(0);
    }

    void stop()
    {
        cocos2d::log("stop()");
    }

    void walk()
    {
        _curPos += _step;
        cocos2d::log("walk(): pos=%d", _curPos);
    }

    void turn()
    {
        _step *= -1;
        cocos2d::log("turn(): step=%d", _step);
    }

    void update(float dt)
    {
        if (_curState) {
            _curState->execute(this);
        }
    }

private:
    State * _curState;

    time_t _curTime;

    int      _curPos;
    int      _step;

public:
    bool isStopTimeout()
    {
        return (time(0) - _curTime > MAX_STOP_TIME);
    }

    bool isWalkTimeout()
    {
        return (time(0) - _curTime > MAX_WALK_TIME);
    }

    bool isWalkOutBorder()
    {
        return (_curPos > MAX_WALK_DIST || _curPos < -MAX_WALK_DIST);
    }
};

#endif // MONKEY_H_

5 总结

当我们需要添加了一种新的状态时,不需要去修改长长的条件判断语句了,只需要构造一个新的状态类,修改它的前序和后序状态类就可以了。对于任何一个状态的特有行为,都是独立的,不会混杂在其它状态的代码里。原为决定状态转移逻辑的那个长长的条件语句不见了,而是被分布在State的子类之间。另一方面,从设计的角度看,原先对当前状态的标识,是FSM内部的一个自有变量,状态与状态之间的转换也仅仅是表现为对自有变量的赋值,如果这个自有变量衍生为变量数组时,那极易出现FSM内部状态不一致的情况,而State的引入可以使得这样的情况变得相当简单。对于新版本的FSM来说,状态与状态之间的转换也成了原子化的操作,不需要兼顾多个变量的赋值。

既然所有状态机具有同样的规则和范式,那么状态机应该与具体对象无关,完全可以提炼出纯粹的状态机类来管理任何对象的状态。下节就完成这个任务。

cocos2d-x 游戏开发之有限状态机(FSM) (二)的更多相关文章

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

    cocos2d-x 游戏开发之有限状态机(FSM) (四) 虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作.SMC(http://smc.sourceforge ...

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

    cocos2d-x 游戏开发之有限状态机(FSM) (三) 有限状态机简称FSM,现在我们创建一个专门的FSM类,负责管理对象(Monkey)的状态.然后Monkey类就实现了行为与状态分离.Monk ...

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

    cocos2d-x 游戏开发之有限状态机(FSM) (一) 参考:http://blog.csdn.net/mgphuang/article/details/5845252<Cocos2d-x游 ...

  4. 《C++游戏开发》笔记十二 战争迷雾:初步实现

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/9475979 作者:七十一雾央 新浪微博:http:/ ...

  5. iOS cocos2d 2游戏开发实战(第3版)书评

    2013是游戏爆发的一年,手游用户也是飞速暴增.虽然自己不做游戏,但也是时刻了解手机应用开发的新动向.看到CSDN的"写书评得技术图书赢下载分"活动,就申请了一本<iOS c ...

  6. java游戏开发杂谈 - 有限状态机

    在不同的阶段,游戏所运行的逻辑.所显示的界面,都是不同的. 以五子棋举例,游戏开始.游戏中.胜负已分,对应的界面和逻辑都不同. 在游戏中,又分为:自己下棋.对方下棋.游戏暂停.悔棋等多个状态. 再比如 ...

  7. (转载)如何学好iphone游戏开发

    转自:http://www.cnblogs.com/zilongshanren/archive/2011/09/19/2181558.html 自从发布<如何学习iphone游戏开发>到 ...

  8. 整理了一下浅墨大神的Visual C++/DirectX 9.0c的游戏开发手记

    还是非常棒的博客,只是没有一个文件夹.所以自己做了一个山寨文件夹在这里.便于随时查找. 前面31期从略. [Visual C++]游戏开发笔记三十二 浅墨DirectX提高班之中的一个 DirectX ...

  9. HTML5物理游戏开发 - 越野山地自行车(三)粉碎自行车

    自上一章公布到如今已时隔四月,实在对不住大家.让大家久等了~话说不是我不关注我的博客,而是事情一多起来写博客的时间就少了. 待到今日有空了,回头看了看自己曾经写的文章,猛得发现已经四个月不曾写文章了. ...

随机推荐

  1. Matlab to OpenCV Mat

    convert Matlab matrix to OpenCV Mat. Support CV_32FC3 only currently. The Code int matlab2opencv(cv: ...

  2. Redis 学习笔记3:Jedis 连接虚拟机下的Redis 服务

    Jedis 是 Redis 官方首选的 Java 客户端开发包. 虚拟机的IP地址是192.168.8.88. Jedis代码是放在windows上的,启动虚拟机上的Redis服务之后,用Jedis连 ...

  3. 根据ccid取得账户,更改某段值再创建账户,返回新的ccid

    CREATE OR REPLACE PACKAGE cux_cuxaprebate_utl IS * =============================================== * ...

  4. FFmpeg的H.264解码器源代码简单分析:环路滤波(Loop Filter)部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  5. SQL Server 索引维护(1)——如何获取索引使用情况

    前言: 在前面一文中,已经提到了三类常见的索引问题,那么问题来了,当系统出现这些问题时,该如何应对? 简单而言,需要分析现有系统的行为,然后针对性地对索引进行处理: 对于索引不足的情况:检查缺少索引的 ...

  6. javascript之事件处理

    一般事件 onclick                       鼠标点击时触发此事件 ondblclick                  鼠标双击时触发此事件 onmousedown    ...

  7. UNIX网络编程——原始套接字SOCK_RAW

    实际上,我们常用的网络编程都是在应用层的报文的收发操作,也就是大多数程序员接触到的流式套接字(SOCK_STREAM)和数据包式套接字(SOCK_DGRAM).而这些数据包都是由系统提供的协议栈实现, ...

  8. Mahout学习路线图

    转自:http://blog.fens.me/hadoop-mahout-roadmap/ Mahout学习路线图 Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, ...

  9. Java-IO之BufferedWriter(字符缓冲输出流)

    BufferedWriter是字符缓冲输出流,继承于Writer,作用是为其他字符输出流添加一些缓冲功能. BufferedWriter主要的函数列表: BufferedWriter(Writer o ...

  10. Android4.4.2KK竖屏强制更改为横屏的初步简略方案

    点击打开链接 解决方案: 当前是根据当前问题场景即竖屏强制更改为横屏的需求而做的改动,基本是hardcode定义的状态,总共修改有效代码行数5行,如果后续有其他需求或者需要更灵活的配置横屏和竖屏,可以 ...