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

时间:2023-03-08 17:07:00

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

有限状态机简称FSM,现在我们创建一个专门的FSM类,负责管理对象(Monkey)的状态。然后Monkey类就实现了行为与状态分离。Monkey类只负责自己的行为,MonkeyFSM作为Monkey的成员,负责状态调度。MonkeyFSM调用状态模式类的方法,状态模式类调用真实对象Monkey的方法。注意本文例子代码只是为了说明问题,并不能真正用于实际当中。其中Monkey与MonkeyFSM互相保存对方的指针,存在循环引用问题。

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

代码部分:

MonkeyFSM:

// MonkeyFSM.h
//
#ifndef MONKEY_FSM_H_
#define MONKEY_FSM_H_

#include "cocos2d.h"
USING_NS_CC;

#include "State.h"
class Monkey;

class MonkeyFSM
    : public Node
{
public:
    MonkeyFSM()
    {
        _monkey = 0;
        _state = 0;

        log("MonkeyFSM()");
    }

    static MonkeyFSM * createObject(Monkey * mk)
    {
        MonkeyFSM * fsm = new MonkeyFSM();
        fsm->initWithMonkey(mk);
        return fsm;
    }

    bool initWithMonkey(Monkey * mk)
    {
        _monkey = mk;

        return true;
    }

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

        if (oldState) {
            delete oldState;
        }
    }

    virtual void update(float dt)
    {
        if (_state) {
            _state->execute(_monkey);
        }
    }

private:
    State * _state;

    Monkey * _monkey;
};

#endif // MONKEY_FSM_H_

Monkey:

#ifndef MONKEY_H_
#define MONKEY_H_

#include <time.h>

#include "cocos2d.h"
USING_NS_CC;

#include "MonkeyFSM.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;

        _fsm = MonkeyFSM::createObject(this);

        this->scheduleUpdate();

        return true;
    }

    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);
    }

    MonkeyFSM * getFSM()
    {
        return _fsm;
    }

    void update(float dt)
    {
        if (_fsm) {
            _fsm->update(dt);
        }
    }

private:
    MonkeyFSM * _fsm;

    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_

状态模式类,.h文件没有变化:

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

class Monkey;

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

#endif // STATE_H_

// 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->getFSM()->changeState(new TurnState());
        mk->turn();
    } else if (mk->isWalkTimeout()) {
        mk->getFSM()->changeState(new StopState());
        mk->stop();
    }
}