状态机状态之间的通信

Communication between state machine states

本文关键字:通信 之间 状态 状态机      更新时间:2023-10-16

我在应用程序中磕磕绊绊地实现了状态机。

所以我有我的状态机:

class StateMachine
{
public:
enum State { MENU, GAME };
    StateMachine();
    void Update();
    void Render();
private:
    Menu* mMenu;
    Game* mGame;
    State mState;
};
StateMachine::StateMachine()
{
    mState = MENU;
}
void StateMachine::Update()
{
    switch(mState)
    {
        case MENU:
        mMenu -> Update(); break;
        case GAME:
        mGame -> Update(); break;
    }
}
void StateMachine::Render()
{
    switch(mState)
    {
        case MENU:
        mMenu -> Render(); break;
        case GAME:
        mGame -> Render(); break;
    }
}

我的菜单和游戏类封装了键盘输入的更新、渲染、处理等。

所以我的问题是,如果状态在 MENU 中,我如何在对象 mMenu 与状态机之间进行通信以告诉它进入游戏状态?我是否需要在菜单和游戏中添加一个变量,状态机会拾取该变量以切换状态?

如果 Menu 和 Game 类要更新状态机,它们都需要知道状态机。

最好的方法是在游戏和菜单类中保留对状态机的引用,以更新当前状态。您可以将其进一步封装在两个实现的接口中,以使事情更加清晰。

// State.hpp
class State {
    public:
        virtual Handle() = 0;
};
// Cotext.hpp
#include "State.hpp"
class Context {
private:
    State* currentState;
public:
    void Update() {
        currentState->handle():
    }
    void setState(State* state) {
        currentState = state;
    }
};
class ContextSwitcher {
    virtual void SetContext(Context* context) = 0;
};
// Game.hpp
#include "Context.hpp"
class Game : public State, ContextSwitcher {
    Context* context_;
    State* menu_;
public:
    virtual void SetContext(Context* context) {
        context_ = context;
    }
    virtual void SetMenu(State* menu) {
        menu_ = menu;
    }
    virtual void Handle() {
        // Do update stuff
        if (shouldGoToMenu) {
            context_->setState(menu_);
        }
    }
}
// Menu.hpp
class Menu : public State, ContextSwitcher {
    Context* context_;
    State* game_;
public:
    virtual void SetContext(Context* context) {
        context_ = context;
    }
    void SetGame(State* game) {
        game_ = game;
    }
    virtual void Handle() {
        // Do update stuff
        if (shouldGoToGame) {
            context_->setState(game_);
        }
    }
}
// GameContext.hpp
#include "Context.hpp"
#include "Menu.hpp"
#include "Game.hpp"
class GameContext : public Context {
private:
    Menu menu;
    Game game;
public:
    void Init() {
        menu->SetContext(this);
        menu->SetGame(&game);
        game->SetContext(this);
        game->SetMenu(&menu);
    }
    // ...
};

通常,您尽量避免双向耦合。这是在 Menu 类中引用状态机。

但是,有多种方法可以解决此问题。

C++习语是带有虚拟函数的接口,您的 StateMachine 实现该接口,然后在菜单和游戏构造函数中传递this。这减少了耦合,但也有其他缺点,例如它将处理限制在单个对象上。

但你也可以使用简单的函数指针(回调)、事件、信号等。