Virtually all programs have this, a central ‘game’ loop that grabs user input, updates game logic, redraws the screen. At it’s simplest possible level, it usually looks something like this:

until Quit;

The problem mainly comes in that middle section, Update. For any game, there are a variety of different states you can be in (main menu, options screen, credits, playing game) and for most games, “playing game” breaks down into a whole lot more states by itself. For my simple 500 Card Game, I had states “bidding”, “dealing”, “choosing kitty”, as well as playing. If you’re not careful, your Update procedure can end up looking like this:

Procedure Update;
   case State of
         // wait for a menu click
         // handle user input
         // roll some credits
         case GameState of
               // handle user input
               // update some monsters
            // etc
      // STATE_ even more stuff:

So far, so big and clunky. It gets worse when you have to handle nested state transitions: in my card game, someone could be playing, then go to the Menu and come back. So I had to have a variable ‘LastState’ that remembered where they were, so they could go back to it. But it’s worse than that, because they might go to the Menu, then go to the Options screen: and when they came back, they’d still want their current game to not be lost! My card game was simple, so I managed this as simply as I could: when entering the ‘menu’ state, the menu grabbed it’s own copy of LastState, and it restored this value when the other screens (Options, Credits etc) returned to it, so there was always a way back to the game. This was the simplest case, because every state had exactly one other state that it could be transitioned from (you couldn’t get to Options from Game without going through Menu).

For Icefall though, the stakes were raised. I wanted the Options screen accessible from in-game, as well as in the initial menu. And there are many more states that the game can be in, and some of them should not be returned to (e.g the “create character” screen), so rather than a gigantic and ugly Update loop, I went back to good old OOP and implemented a class-based state stack.

Icefall has a central “State Engine” that looks after the current state stack, handles transitions between them, and calls whichever state is ‘on top’ during the main loop. The State class looks something like this:

TIceState = class (TIceClass)
   constructor Create
      (StateEngine: TIceStateEngine; 
       Transition: TStateTransition);
   procedure OnEnter; virtual;
   procedure OnLeave; virtual;
   procedure Update; virtual;
   procedure Redraw;
   // other useful state methods
   destructor Destroy; override;

Essentially, for every state the game can be in, I have a corresponding class that defines it’s specific behaviour in Update. I can also do other ‘maintenence’ (e.g. ensure the right music is playing) by overriding the OnEnter and OnLeave procedures. The game can change states by constructing a new TIceState instance, passing it a reference to the state engine and describing the type of transition to use (e.g. whether to nest the state [for a trip to a Menu] or just progress to the new state with no way back [like a character create screen]). You can also leave a state just by destructing the class instance: the state engine will pop back to the next highest state on the state stack, or quit the game if there are no states left (e.g., you just hit ‘Exit’ from the Main Menu). 

The state engine takes care of nested states and transitions, and someone’s exact state in the game can be saved (if needed) by storing the entire state stack: while I’m unlikely to want the game to be saved while on the Character Create screen, it’s good to know I can safely save the game while in shops, or at any other point, without even worrying about special handling code to cover all the situations.

Another interesting thing I have done is move the game’s “loader” (the part that loads textures, sounds, music, fonts, databases) into it’s own state, and just made it the very first state that’s pushed onto the stack, and it takes a parameter to the state to transition to when it’s done. It takes the whole ‘loading’ step out of the main game code, which makes that much simpler, and I can make the loader just load the resources I’m going to need right now: some other state (like the credits) can always call it again later to load specific credit-y images.

I can also use the the same game engine to build other tools like the Map Editor: the only difference between the map editor and the game itself is that it compiles in a different set of states: when the map editor has loaded, it launches itself into a TMapEditorState instead of a TMainMenuState.

Overall, having a state stack is very flexible, quite simple to use and maintain, and overall a vast improvement from the ‘giant case statement’ I was using previously.