Top

Game State Management

March 1, 2008

gamestate.jpg One of the earliest things you need to think about when developing your game is game state management.

Microsoft has graciously included a terrific game state management example, so let’s take a look at it in more depth.

Note: this article is in progress. Check back here often. When this message disappears, the article will be considered complete.

First things first: download the Game State Management Sample from the XNA Creators Club. You may also want to pick up the Network Game State Management Sample, which extends the first sample to include the screens typical of a network enabled game. We won’t be dealing with that for a while, however.

Now build and run the sample. What do we see? What we have is essentially the same game states that 95% of games (and, in turn, very likely your game) will have.

gamestatescreen.jpg

Basically what you’d expect, isn’t it? When the game loads, the first screen is the main menu, from which you can branch off into the game, review your settings on an options screen, or exit. If you enter the game, you hit a brief loading screen, then the game. And finally, if you hit escape during the game, the game pauses, you are presented with an “are you sure?” screen, from which you can return to the game uninterrupted, or exit back to the main menu.

The key to all this is to take yourself out of the simple XNA game type (where your game pretty much just runs via the Update and Draw methods until it ends), and create a new object to handle the state management.

So if you take a look at your Game.cs file, you’ll see just that. The constructor creates a new ScreenManager object, adds it to the list of Components, and the adds a couple GameScreen objects to it. We’ll talk about all of that in a minute. For now, let’s turn to the Draw and Update methods.

Wait! The Update method is conspicuously absent! All this means is that we’ve chosen not to override the Update method that comes with Microsoft.Xna.Framework.Game. We’ll see in a minute what that implies. Our Draw method does exist. But all it does is clear the screen to black, and then calls the base Draw method. So essentially, ignoring the Clear call, both Draw and Update do nothing — whenever they are called by the system, we just get the default behavior of the Microsoft.Xna.Framework.Game class’ versions of those methods.

So, what do those methods do by default? The key thing for us to know is that they both go through the list of Components and call the respective Update and Draw methods that each Component defines. So base.Update iterates through the list of components and calls each of their Update methods. The base.Draw method iterates through the same components, and calls each of their Draw methods (if they have one… not all of them do!)

We know that our ScreenManager object was added to this list, so let’s open up ScreenManager.cs and take a look. Sure enough, ScreenManager inherits from DrawableGameComponent. There are two kinds of game components, DrawableGameComponent and GameComponent. The difference is that the Drawable version gets its Draw method called. So we’d use the GameComponent version if our object is only used for game logic (for example, if we had an AI component, or a score keeper component).

So now you see we’ve basically dumped all the Update and Draw responsibility on our ScreenManager object. Let’s take a closer look at that object now.

First, notice we’ve got a couple of List objects:

  1. List<gamescreen> screens = new List<gamescreen>();
  2. List<gamescreen> screensToUpdate = new List<gamescreen>();</code>

We are maintaining a list of GameScreen objects, and a separate list of GameScreen objects that need to be updated.

Now take a look at the LoadContent method. You’ll see we are grabbing our content from the Game object. Now that we’re handling everything in the ScreenManager, we probably want access to all of our game content here as well.

// Load content belonging to the screen manager.

ContentManager content = Game.Content;

We also call each of the screens objects’ LoadContent methods from here as well. Each of them may want access to that content themselves.

Zip down to the Update method. It looks like it does a lot, but actually all it is doing is calling the Update method for each of the screens it currently has. Initially, this is just the two screens loaded in the Game object, the BackgroundScreen and the MainMenuScreen. Later on, screens will be added and removed as the player moves around the game interface. For example, when the player moves to the options screen, we’ll want to remove the MainMenuScreen and add the OptionsMenuScreen to the ScreenManager.

The rest of the ScreenManager class should be easy enough for you to parse. It handles transitioning between screens, and allows for two different kinds of screen (popup and non-popup).

The last thing to look at is how an actual screen works. Open up the MenuScreen.cs file. The MenuScreen class is a base class, from which the OptionsMenuScreen, PauseMenuScreen and MainMenuScreen inherit. It allows for the adding of MenuItem objects, and handles the selection of MenuItems. The InputStateManager class is a helper class that allows you to configure what certain buttons and keypresses do, so you may want to keep that file open while looking at MenuScreen.cs as they work together.

Notice that when a menu item is selected, the OnSelectedEntry function is called. This function receives the index of the selected item, and that items OnSelectedEntry function is in turn called. That function fires an event, and an event handler in the menu screen decides what to do.

There you have it, a brief overview of the Game State Management sample. The best way to really understand this sample, as is the case with most sample code, is to dig into it and start changing it. Start by changing the text of a few screens, then add a couple new menu items to the main menu. Make sure you set up the event handlers for those items, so that something will actually happen if they get selected. Finally, start rounding out the GameScreen class to understand how to fit your game logic into there. It will be almost identical to the simple Update/Draw method you are used to, except now you’ll have to handle certain cases like the user pausing the game, or pulling up an options screen.

Comments

Got something to say?





Bottom