您的位置:首页 > 移动开发 > Cocos引擎

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

2015-01-22 14:44 513 查看

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来说,状态与状态之间的转换也成了原子化的操作,不需要兼顾多个变量的赋值。既然所有状态机具有同样的规则和范式,那么状态机应该与具体对象无关,完全可以提炼出纯粹的状态机类来管理任何对象的状态。下节就完成这个任务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: