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

参考:
http://blog.csdn.net/mgphuang/article/details/5845252
《Cocos2d-x游戏开发之旅》(钟迪龙)

基本上所有的软件都是有限状态机(finite-state machine,FSM)。它是一个有向图,由一组节点和一组相应的转移函数组成。通俗点讲,它是一个事件驱动系统的模型,这个模型由有限数目的状态,若干输入和状态与状态之间转换的规则组成。在某一时刻,有一个或一组状态是FSM的当前状态,FSM接收输入事件并根据转换规则,将当前状态转为新的状态。正是由于这三个元素的组合,使得FSM具备了自己的行为特点。在游戏开发中,FSM被用来实现人工智能的决策过程,控制游戏对象的行为。

1 最简单的状态机

可能上面的解释还是有些抽象,绝大多数的文章会举用“门”或“锁”的例子来说明什么是状态机,我想还是举一个新鲜的例子吧:有一个叫做“猴子”的NPC,它会在指定的区域里行走,有时候停留,当行走到区域的边界所时,会自己转向(图1)。我们把状态机的转换规则函数列出表格(图2),并根据列出的规则写出是这个简单状态机的C++实现:

#ifndef MONKEY_H_
#define MONKEY_H_

#include <time.h>

#include "cocos2d.h"

USING_NS_CC;

#define MAX_STOP_TIME  10
#define MAX_WALK_TIME  20

#define MAX_WALK_DIST  100

enum MonkeyState
{
    stSTOP,
    stWALK,
    stTURN
};

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

    CREATE_FUNC(Monkey);

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

        changeState(stSTOP);

        this->scheduleUpdate();

        return true;
    }

    void changeState(MonkeyState newState)
    {
        _curState = newState;
        _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)
    {
        switch (_curState) {
        case stSTOP:
            if (isStopTimeout()) {
                changeState(stWALK);
                walk();
            }
            break;

        case stWALK:
            walk();

            if (isWalkOutBorder()) {
                changeState(stTURN);
                turn();
            } else if (isWalkTimeout()) {
                changeState(stSTOP);
                stop();
            }
            break;

        case stTURN:
            changeState(stWALK);
            walk();
            break;
        }
    }

private:
    MonkeyState _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_

2 坏代码的味道

显然,如果继续将上面的代码写完整的话,它一定能很好的工作。但我似乎已经闻到了传说中“坏代码”的味道,上面长长的条件判断语句,会随着状态的增多变得更长。每增加一个状态,就需要在长长的条件判断语句中小心查找和修改。当这样的条件语句增长到需要多个人合作完成时,那当导致严重的维护与调试方面的问题。另外,对于编译型语言而言,一个具有N个状态的FSM要查找一个正确的状态,平均需要进行N/2次的判断。

在上面的状态机中,其实是让这个对象在不同的状态中表现出了不同的行为特征,那不同的行为特征之间除了有类似的形式化的接口之外,基本上没有任何的联系。那我们很自然地想到状态模式,利用状态模式维护状态,实现对象与维护状态的分离。

最新文章

  1. MYSQL批量修改表前缀与表名sql语句
  2. Window Ghosting
  3. 使用SQL Server Audit记录数据库变更
  4. EasyUI datagrid 行编辑
  5. R语言学习笔记(一)
  6. web storm
  7. 详细解读MySQL中的权限
  8. 适应所有浏览器的cookie
  9. UVALive 6525 Attacking rooks 二分匹配 经典题
  10. 查看实时公网ip
  11. ORACLE查看和更改的最大连接数
  12. Google photos -- reverse thinking
  13. [知了堂学习笔记]_用JS制作《飞机大作战》游戏_第2讲(四大界面之间的跳转与玩家飞机的移动)
  14. 《JAVA程序设计》_第九周学习总结
  15. MT【249】离心率两题
  16. logstash报错401 需要在logstash启动的配置文件中增加es的用户名和密码
  17. 30.SSH配置文件模板和类库.md
  18. poj 1523Tarjan算法的含义——求取割点可以分出的连通分量的个数
  19. 负载均衡(Load Balancing)学习笔记(一)
  20. 关于Eclipse如何加入Gradle文件与Android Studio两个平台一起开发,工作目录不发生变化

热门文章

  1. 【SSH系列】Hibernate映射 -- 继承映射
  2. PGM:部分观测数据
  3. Racket 模拟SICP的流(延时计算)
  4. Maven简介(Maven是什么)
  5. Spring之AOP模块
  6. JAVA面向对象-----extends关键字
  7. JAVA面向对象-----封装
  8. C语言中switch case语句可变参实现方法(case 参数 空格...空格 参数 :)
  9. 18 UI美化自定义主题样式代码
  10. [ExtJS5学习笔记]第十八节 Extjs5的panel的dockeditems属性配置toolbar