J'écris un jeu, et je veux modéliser ses différents états (l'analogie Game Maker serait des cadres, je suppose) d'une manière propre, orientée objet. Auparavant, je l'ai fait de la façon suivante:Comment modélisez-vous les états d'application?
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_;
};
Ce fut à peine manageble pour un petit projet. Toutes les variables que les états utilisaient ont été déversées dans la classe Game, mais je voudrais que l'orientation des objets soit maximale, exposant uniquement les variables partagées par plusieurs états. Je veux également être en mesure d'initialiser un nouvel état lors de la commutation plutôt que d'avoir à le faire dans l'état qui vient de finir (car il pourrait avoir plusieurs résultats - APP_PLAYING peut passer à APP_PAUSED, APP_GAMEOVER, APP_NEWLEVEL, etc.).
Je pensais que quelque chose comme ça (ATTENTION FUZZY STUFF!):
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_;
};
Le problème ici est que les niveaux de classe et d'instance sont pêle-mêle se (statique vs virtuel). Les états doivent hériter de AppState, mais - comme j'imagine - la plupart d'entre eux seraient des classes avec des membres tout statiques, ou, au moins, je n'aurai pas besoin de plus d'une instance d'une classe (TitleState, LevelIntroState, PlayingState , GameOverState, EndSequenceState, EditorState ... - la pause ne serait plus un état, plutôt que d'être prise en charge dans les états où cela a du sens).
Comment cela peut-il être fait avec élégance et efficacité?