Handling Gamestates

Every game has a few gamestates; the most simple version may be ‘Title’, ‘Gameplay’ and ‘Game Over’. In this simple version one might declare an enum like this:

This leads to a switch statement in the Update() and Draw() sections of your code. However, what if the player can access an ‘options’ screen from the title and gameplay states? Or switch between inventory or map modes? Soon you’ll be adding substates and trying to remember what the previous state was…

Let’s start with a clean slate, rid ourselves of the Gamestate enum… how can we handle this in a more elegant way? Read on …

Introducing the GameState Stack

Stacks are a common concept in computing. It is a collection type where the elements are handled in a LIFO (Last In, First Out) fashion. The stack has three basic operations:

  • Push. Add something to the top of the stack.
  • Pop. Remove the top element from the stack.
  • Peek. Read the top element of the stack- without modifying the stack itself.

This is a great concept for our gamestates! Let’s take a look:

  1. The game starts, we push the TitleScreenState to our stack.
    We peek the stack, top state is the titlescreen.
  2. The player starts a game. we push the GameplayState to the stack.
    The stack now contains [0]TitleScreenState, [1] GameplayState.
    We peek the top of the stack; and the GameplayState is returned.
  3. The player opens the optionsscreen. The OptionsState is pushed onto the stack.
    The stack now looks like this: [0]TitleScreenState, [1] GameplayState, [2] OptionsState.
    As we peek the stack, the OptionsState is returned.
  4. The player closes the optionsscreen; now the OptionsState is popped from the stack.
    The stack now has the elements: [0]TitleScreenState, [1] GameplayState.
    peek would now continue the game!

Implementing the GameState Stack

The gamestate stack has two components; the Gamestate manager and the Gamestates. The gamestates need to follow some rules, so let’s start by creating an Interface like this:

Quite simple so far; since our gamestates will contain the gameplay and draw logic for that particular state. As an example let’s create a simple state:

This is a simple class that will show a rectangle that increases over time.

 

Now we have our interface, let’s move on to the Gamestate manager:

This doesn’t look so complex right? The manager allows us to push and pop states.  The best part is in line #25 in the Update() method:

So the code peeks the stack, and calls the update on the state that is returned! So this means our main game loop (the one in the autogenerated Game1 class) looks like this:

A ”Gameplay’ object is created and pushed onto the stack (lines 11-12).  …and in the Update() and Draw() methods? No more switch statements! Just a GamestateManager updating and drawing whichever state is on the top of the stack (lines 28 and 39)!

In the next part I’ll add some interesting tweaks and features to the gamestates. So stay tuned: to be continued!

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Verplichte velden zijn gemarkeerd met *