我正在编写一个游戏,我想以一种干净的、面向对象的方式对其不同的状态进行建模(我猜,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... - 暂停将不再是一种状态,而不是在有意义的状态中得到处理)。
怎样才能优雅又高效地完成呢?