我正在编写一个游戏,我想以一种干净的、面向对象的方式对其不同的状态进行建模(我猜 Game Maker 类比是帧)。以前,我是通过以下方式完成的:
class Game
{
enum AppStates
{
APP_STARTING,
APP_TITLE,
APP_NEWGAME,
APP_NEWLEVEL,
APP_PLAYING,
APP_PAUSED,
APP_ENDED
};
typedef AppState(Game::*StateFn)();
typedef std::vector<StateFn> StateFnArray;
void Run()
{
// StateFn's to be registered here
AppState lastState(APP_STARTING);
while(lastState != APP_ENDED)
{
lastState = GetCycle_(lastState);
}
// cleanup
}
protected:
// define StateFn's here
AppState GetCycle_(AppState a)
{
// pick StateFn based on passed variable, call it and return its result.
}
StateFnArray states_;
};
对于一个较小的项目来说,这很难管理。状态使用的所有变量都转储在 Game 类中,但是我希望最大限度地保持面向对象性,只公开由多个状态共享的变量。我还希望能够在切换到新状态时初始化它,而不是在刚刚完成的状态下进行(因为它可能有多个结果 - APP_PLAYING 可以切换到 APP_PAUSED、APP_GAMEOVER、APP_NEWLEVEL 等)。
我想到了这样的事情(注意!模糊的东西!):
struct AppState
{
enum { LAST_STATE = -1; }
typedef int StateID;
typedef std::vector<AppState*> StateArray;
static bool Add(AppState *state, StateID desiredID);
// return false if desiredID is an id already assigned to
static void Execute(StateID state)
{
while(id != LAST_STATE)
{
// bounds check etc.
states_[id]->Execute();
}
}
AppState() {};
virtual ~AppState() {};
virtual StateID Execute() =0; // return the ID for the next state to be executed
protected:
static StageArray stages_;
};
这里的问题是类和实例级别变得混乱(静态与虚拟)。状态需要从 AppState 继承,但是 - 我想如何 - 它们中的大多数将是具有全静态成员的类,或者,至少我不需要来自一个类的多个实例(TitleState、LevelIntroState、PlayingState , GameOverState, EndSequenceState, EditorState... - 暂停将不再是一种状态,而不是在有意义的状态中得到照顾)。
如何优雅高效地完成它?