Я одного разу натрапив на статтю, яка вирішує вашу проблему досить елегантно. Це основна реалізація FSM, яка викликається у вашому головному циклі. В решті цієї відповіді я окреслив основний перелік статті.
Ваш основний стан гри виглядає так:
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();
};
Кожен ігровий стан представлений реалізацією цього інтерфейсу. Для вашого прикладу Battlechess це може означати такі стани:
- інтро-анімація
- головне меню
- анімація налаштування шахової дошки
- вхід для переміщення гравця
- анімація переміщення гравця
- супротивник рухається анімацією
- меню пауз
- екран гри
Штати керують у вашому штатному двигуні
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();
// ...
};
Зауважте, що кожен стан потребує вказівника на CGameEngine в якийсь момент, тому сам стан може вирішити, чи потрібно вводити новий стан. У статті пропонується передати CGameEngine як параметр для HandleEvents, Update and Draw.
Зрештою, ваш основний цикл має справу лише з двигуном стану:
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;
}