RiverMan Media

RiverMan Media 1

Object Oriented Game Programming: The Scene System PDF Print E-mail
Written by Paul Stevens   
Saturday, 05 April 2008 00:59

 Simplify flow between game "screens" using the scene system

 

Problem:

You’re making a game that has a bunch of different screens.  Even in just a small game, you’ve probably got menu screens, a high score screen, a “normal play” screen, maybe a shop screen, and more.  There are four separate issues here, but it turns out that they all are related enough to have a common solution:

  1. How do you manage the loading and unloading of the many screens, assuming you can’t keep the data/graphics all loaded at once (and with full screen background images, it’s not usually a good idea).
  2. How do you switch between screens?  What is the easiest way to organize all of these different sections of game logic?
  3. How do you switch between control schemes?
  4. For ease of testing, how can you jump into a particular screen, assuming that a bunch of stuff has to be loaded for the scene to run correctly?
 

Early ideas:

 

At first I thought, “Let’s keep all the data and control logic in a single static class.  We can divide up the game into states, one representing each different set of control logic, and do a switch statement to decide which data, game logic, etc. to use at any give time.”

 

The problem here was that it isn’t very scalable.  It works fine for a very small number of simple screens/control schemes, but increasing the number or the complexity of the screens/control schemes and things get out of hand very quickly.  Also, what constitutes a game state is pretty vague.  Is it when the screen’s background has an obvious change?  Is it each GUI?  Are there only two states (just the play and menu)?  Is it a new state when only the control logic changes, but nothing new has to be loaded?

 

This is basically how I started coding Cash Cow, and because I was answering all of those previous questions a different way each time, the control structure for the states grew more and more complex.  Things were never consistent, which made adding and changes states very difficult.  It also didn’t address issue number 4 at all, which made testing tedious because we had to navigate through menus to get to any particular part of the game.  By the time I started coding Primate Panic, we had a much better idea.

 

Our Solution:

 

I call it “The Scene System.”  Essentially, you divide the game up into scenes, where a scene is (usually) defined by a change in the background image.  This means that the main menu screen is a scene, the map screen is a scene, the normal gameplay is a scene, etc.  Why divide them up this way?  Because in our current platform, background images take a noticeable amount of time to load (at least enough to cause the cursor to flinch).  The idea is that if you only load a new background between scenes when the entire screen is black, the user won’t notice any delay from loading. 

 

This means that each scene should have a natural way to transition in and transition out, and the unloading/loading takes place after the transition out of one scene and before the transition in of the next.  In Primate Panic, you see the end of a scene when the screen fades to black.  This is when the next scene is being loaded, but on most computers it is fast enough that you don’t notice any load time.

 

There is also a class that manages the scenes, and tells the current scene to update its game logic and redraw everything each frame.

 

How Does It Work In Code?

 

In Java or Slag, you have you have a SceneManager class (which is a singleton for ease of use).  This class contains a static reference to the only instance of Scene Manager, and a reference to the currently running scene.  It needs this scene reference to update and redraw the current scene, as well as change it.  Here is a quick Java example of the idea:

 

class SceneManager

{

  private static SceneManager instance;

  Scene currScene;

 

  public static SceneManager getInstance()

  {

    if (instance == null) instance = SceneManager()

    return instance

  }

 

  public void update() {currScene.update()}

  public void redraw() {currScene.redraw()}

 

  // A simplified way of loading and unloading scenes

  // Notice that the method is static so that anyone can call it.

  public static void changeScene(Scene newScene)

  {

    if (instance.currScene != null) instance.currScene.unload()

    instance.newScene.load()

    instance.currScene = newScene

  }

}

  

The Scene class is abstract and has four abstract methods that each scene must implement.  Overriding these abstract methods is what keeps your scene code clean and avoids those nasty switches.  Scenes can of course have plenty of other methods that you override as well, but these are the essentials.

 

abstract class Scene

{

  abstract void update();  // update logic for this scene

  abstract void redraw();  // redraw everything on screen

  abstract void load();  // load all of the data and graphics that this scene needs to function.

  abstract void unload(); // unload everything that the garbage collector won’t unload, itself, including graphics

}

 

Internally, our Scene implementations also have a transitionIn() and a transitionOut() procedure.  This is where the screen fades happen in Primate Panic.

 

So how does the scene system solve each problem we mentioned earlier?

  •  How do you manage the loading and unloading of the many screens, assuming you can’t keep the data/graphics all loaded at once (and with full screen background images, it’s not usually a good idea).

 

Loading and unloading is done between scenes, when it is going to be unnoticeable by the user.  Typically background changes happen at the same time that other large amount of data and graphics need to be loaded and unloaded, so the scene transition solves this problem naturally.

  • How do you switch between screens?  What is the easiest way to organize all of these different sections of game logic?   

 

SceneManager just runs the currScene and can switch between scenes.  Because of polymorphism, your SceneManager does not have to be aware of the internals of each scene, just that each scene has those four important methods.  To change the scene from anywhere else in your code (this happens a lot in your GUI code), just call SceneManager.changeScene(newScene).

  • How do you switch between control schemes? 

 

Each Scene will handle its own set of controls, regardless of how this data reaches the scene.  The scene might listen to the input data (like the keyboard and mouse) directly, or the data could be passed down by the SceneManager, as long as each scene implements the proper functions.

 

  • For ease of testing, how can you jump into a particular screen, assuming that a bunch of stuff has to be loaded for the scene to run correctly? 

 

Each Scene’s load() method should load all of the data and graphics you need to run that particular scene.  If you wanted to say, jump directly to the PlayScene, you would just instantiate this scene at the start of your game’s initialization and call SceneManager.changeScene() with the play scene as an argument.  If you want to get really fancy, you could create a tiny file to read in during your game’s initialization that tells your game which scene to start with.  That way you don’t have to rebuild your code just to start at a different scene.

 

But what happens when menus are changing but the background isn’t?  Is each menu a new scene since the control is changing (at least a little bit)? 

 

No, GUIs are contained within a scene and are handled separately.  See "The GUI Stack" article for more details.

 

 
Comments (3)
Excellent Explanation!
1 Wednesday, 04 February 2009 00:11
This is a great implementation. I have had a few variations around my own ideas for scene management before, but this one beats it hands down. I feel like a bit of an idiot, since I was quite close to this idea but missed it by the tiniest bit.

Thanks very much!
Very Good!
2 Tuesday, 17 February 2009 16:27
Cool!!

I have created a class in my game framework to control scenes some time ago, and i have done exactly how you have imagined. I think that this is really the best method to control scene transitions. Excellent Tutorial!
Sweet idea
3 Tuesday, 14 April 2009 11:27
Sash
Great work, I have actually been using something similar for a while, it works wonders! The only thing i did differently was have load called after unload was complete, that way if your doing animations they don't overlap.
I really like the way that you have handled the changeScene function (making it static).
Anyway great work! I will be sure to steal some of your ideas.
Thanks heaps.

Add your comment

Your name:
Your website:
Subject:
Comment: