I once came across an article that solves your problem quite elegantly. It is a basic FSM implementation, that is called in your main loop. I have outlined the basic rundown of the article in the rest of this answer.
Your basic game state looks like this:
class CGameState { public: // Setup and destroy the state void Init(); void Cleanup(); // Used when temporarily transitioning to another state void Pause(); void Resume(); // The three important actions within a game loop void HandleEvents(); void Update(); void Draw(); };
Each game state is represented by an implementation of this interface. For your Battlechess example, this could mean these states:
- intro animation
- main menu
- chess board setup animation
- player move input
- player move animation
- opponent move animation
- pause menu
- endgame screen
States are managed in your state engine:
class CGameEngine { public: // Creating and destroying the state machine void Init(); void Cleanup(); // Transit between states void ChangeState(CGameState* state); void PushState(CGameState* state); void PopState(); // The three important actions within a game loop // (these will be handled by the top state in the stack) void HandleEvents(); void Update(); void Draw(); // ... };
Note that each state needs a pointer to the CGameEngine at some point, so the state itself can decide whether a new state should be entered. The article suggest passing in the CGameEngine as a parameter for HandleEvents, Update and Draw.
In the end, your main loop only deals with the state engine:
int main ( int argc, char *argv[] ) { CGameEngine game; // initialize the engine game.Init( "Engine Test v1.0" ); // load the intro game.ChangeState( CIntroState::Instance() ); // main loop while ( game.Running() ) { game.HandleEvents(); game.Update(); game.Draw(); } // cleanup the engine game.Cleanup(); return 0; }