私はゲームを書いていて、そのさまざまな状態 (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 から継承する必要がありますが、私が想像するに、それらのほとんどはすべて静的メンバーを持つクラスになるか、少なくとも 1 つのクラス (TitleState、LevelIntroState、PlayingState) から複数のインスタンスは必要ありません。 、GameOverState、EndSequenceState、EditorState... - 一時停止は、意味のある状態で処理されるのではなく、状態ではなくなります)。
どうすればそれをエレガントかつ効率的に行うことができますか?