我在我的应用程序中遇到了状态机的实施问题。
所以我有我的状态机:
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与状态机之间进行通信,告诉它进入游戏状态?菜单和游戏中是否需要一个变量,然后状态机才会切换到状态?
答案 0 :(得分:1)
通常你会尽量避免双向耦合。这是在Menu类中引用了StateMachine。
然而,有多种方法可以解决这个问题。
C ++习惯用法是一个包含StateMachine实现的虚函数的接口,然后在Menu和Game构造函数中传递this
。这减少了耦合,但还有其它缺点,例如限制对单个对象的处理。
但你也可以使用简单的函数指针(回调),事件,信号等。
答案 1 :(得分:1)
菜单和游戏类都需要知道StateMachine是否可以更新它。
最好的方法是在Game和Menu类中保持对状态机的引用,以更新当前状态。您可以进一步将其封装在一个接口中,这两个接口都可以使事情更加清晰。
// 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);
}
// ...
};