Friday, August 2, 2013

Game state management

So, you need some way to manage your game states, like your menu screen and whatnot.  XNA's official samples include some fancy stuff.  XNA Game Programming Adventures has an excellent tutorial on doing a slightly more advanced state manager that riffs of the original samples.  It's in the first few episodes of their "How to make an RPG" series.  It involves all sorts of useful XNA mojo like XNA Game Components and Drawable Components, and some magic with collection classes like Stacks.

My way is simpler.  Less intrinsically flexible maybe (though I wouldn't put money on that), but you can have it up and running in ten minutes.

Here's how it works:

public abstract class State
{

   public virtual State Update(float s)
   {
       return this;
   }

   public virtual void Draw(float s)
   {
   }

}

Bam!  S is just the seconds elapsed since you last updated (more conscientious coders may want to use GameTime instead of a float).  So here's how you use it.

Suppose you've got a title screen which draws your company logo, then switches to your main menu.  Your title screen and your menu both inherit from State.  Your Title Screen looks like this:

public class TitleScreen : State
{
    float time;
    state next;

    public TitleScreen (State NextState, float Duration)
   {
       time = Duration;
       next = NextState;
   }

   public override State Update(float s)
   {
       time -= s;
       if (time <= 0) return next; else return base.Update(s);
   }

   public override void Draw(float s)
   {
       // Draw the screen here.
       base.Draw(s);
   }
}

Now, in the game class Microsoft so kindly gave us, just declare three objects:

TitleScreen title;
MainMenu menu;
State currentState;

In the Load method, initialize them.

menu = new MainMenu();
title = new TitleScreen(menu, 5);
currentState = title;

In Draw, do this:

currentState.Draw((float)gameTime.ElapsedGameTime.TotalSeconds);

And whichever state is current will draw itself.

In Update, do this:

currentState = currentState.Update((float)gameTime.ElapsedGameTime.TotalSeconds);

And whichever state is current will update, and pass back the state that should be current next.  In this example, the title screen will display for five seconds, then pass control to the menu!

Now, this may be a sloppy way of doing things -- I'm not some sort of super-guru.  But it is very fast to get up and running, and if you are an indie game developer, or even a hobbyist, you need to optimize your program not only for how fast it can run and how much memory it consumes, but also how much of your life it consumes.

No comments:

Post a Comment