Frantic Hobbyist Programming

So, we all learn about stacks in programming, but when are they used?

More than you might think, as it turns out. Pick up a video game, and you'll probably see this all happening behind the scenes everywhere. You start with the title screen, that's a state. It renders itself, among other things, and handles its own logic for how input is handled. You press down, you go to the next option in the title menu. The state catches your button press, and handles it internally.

You go to the actual game, a state gets pushed onto the stack, so your stack looks like (Top) Game, Title (Bottom). Thing is, the only state that gets updated now is the one on top - the game state. Press down, and you don't move options in a menu, you move down. Press Start, and... well that's Pause. It pushes another state on the stack that really just waits for you to press Start again. At this point, your stack looks like (Top) Pause, Game, Title (Bottom) Then it pops itself off the stack when you hit Start, and once again, the Game state is on the top of the stack.

This means you have to have something that manages states. All it really does is call the update function on whatever's on the top, and pops/pushes states as necessary.

// C#
public void Update(GameTime Time) {
  UpdateStateStack(); // Pop and push pending stack states.

  // Check if there are any more states remaining.
  if (this.IsEmpty) { return; }

  this.CurrentState.Update(Time);
}

public GameState CurrentState {
  get { return ((m_StateStack.Count > 0) ? m_StateStack.Peek() : null); }
}
public bool IsEmpty {
  get { return m_StateStack.Count <= 0 && m_PendingPushStates.Count <= 0; }
}

In the above code, the StateManager itself is updated first. States might be pushed on the stack, or popped off it, but whatever happens, you cannot push a state onto the stack while you're in the middle of processing another state - otherwise the processing of one state will be cut off in the middle (posing problems when you snap back to it), and the newly pushed state might undergo some processing with inputs that were never intended for it. Remember, pop before you push - you pop old states and push new states, but if you update the stack by pushing new states, then start popping off however many you need... well, those states you just pushed on the stack are now gone.

The next step checks to see if the stack is empty after your updating. If it is, there's really nothing to do. Most games might end when the last state is popped off the stack.

Finally, if you've got a stack with a state, the StateManager looks at the topmost one, and tells it to update itself.

So, that's it in a nutshell. States might be able to draw themselves as well, so you can put in some code that looks like...

public void Draw(GameTime Time) {
  if (this.IsEmpty) { return; }

  this.CurrentState.Draw(Time);
}

Then just define the method Draw in the particular GameState you're working with. I personally make GameState an abstract class, and subclass off it. GameStates can draw themselves and update themselves... I also put in pause and resume whenever execution is taken away from and given back to them (but I did that because of the way that MMDX works, still might be a good idea), as well as including initialization and disposal functions.

public abstract class GameState {
  protected bool m_IsDone;

  protected DrawableManager m_DrawableManager;
  protected InputManager m_InputManager;

  public abstract void Initialize();
  public abstract void LoadContent();
  public abstract void ProcessInput(InputState Input);
  public abstract void Update(GameTime Time);
  public abstract void Draw(GameTime Time);
  public abstract void Dispose();

  public abstract void Pause();
  public abstract void Resume();
}