D Bits

  • entries
    32
  • comments
    46
  • views
    122831

Game Screens

Sign in to follow this  
Aldacron

855 views

The concept of a game screen is a fairly common one in game engines and frameworks these days. Usually it's an interface or base class that defines a lifecycle for what once upon a time was commonly known as a game state. It eliminates the need for those ugly if-else trees, or long switch statements, that used to take up a large portion of the game loop in the good old days. Each game state, or screen, can be encapsulated in its own class and activated as needed. And often there is a manager that handles initialization, shutdown, and calling the tick method (or update/render methods in some implementations) of the screen object at regular intervals. A simple game screen manager might operate on one screen at a time. But you can get a good deal more flexibility if you let it run through a list of screens instead. Or, more conceptually appropriate, a stack of them.

So I've implemented a screen manager in Dolce that does just that -- maintains a stack of game screens, any of which may be active or suspended, and loops through the stack each frame, calling a tick method on the ones that are active. The implementation is based on one by James Boer from Game Programming Gems 5, one that I have implemented so many times I can do it blindfolded now.

First, you register a screen under a unique name of your choosing. When you are ready to activate it, you issue a push command to the screen manager. Internally, when a screen is pushed onto the stack, its init method is called. Then it is eligible to be ticked each time the screen manager's tick runs. It can push other screens on top of itself without interrupting any current tick processing, as all stack commands are delayed until the next time the screen manager ticks. When another screen is pushed onto the stack, the pause method is called on the screen at the top. When a screen is popped, its term method is called. And when a screen becomes the new top as the result of a pop, its resume method is called.

One aspect of the system that gives it flexibility is that whenever a stack command is issued, the name of a particular screen is passed to the lifecycle method being called. A screen's init method is given the name of the screen which it is being pushed on top of, its pause method the name of the screen which is pushed on top of it, its resume method the name of the screen popped off of it, and its term method the name of the screen beneath it. This allows you to do things like use the same instance in multiple places on the stack.

As an example, consider a game's main menu. You will show it once at game start up. Let's say the player selects 'PLAY NOW'. Now, the main menu screen pushes the game play screen, and the screen manager calls the pause method on the main menu, giving it the name of the game play screen as an argument. Since the main menu knows it pushed the game play screen on top of itself, it can check the name to recognize that the game play screen is active. Later, the player presses the escape key to see the main menu again. So, the game play screen issues a push command to the screen manager, giving it the registered name of the main menu. The main menu instance, the same one already on the bottom of the stack, is fetched again from the registry and its init command called with the name of the game play screen. It realizes it is already initialized and was paused. So, instead of pausing, it simply resumes. You obviously don't want to display 'PLAY NOW' when the player is already playing, so you verify that the name given to the init method matches the game play screen's name and change the text on the button, and its corresponding action, to 'RESUME GAME'. Everything else stays the same. When that button is clicked, the main menu pops itself off the stack. When the pop command is executed, its term method is called with the name of the game play screen. By checking the name, the main menu realizes it's not really time to terminate yet, so pauses instead. Game play resumes.

Anyway, it's a really basic system that gives several options for handling game states. You can instantiate as many screen managers as you want. No, it isn't a singleton. I figure there are use-cases for multiple screen managers. Consider an in-game editor. I think it'd be more appropriate to have separate managers going -- one for the game and one for the editor -- than trying to manage everything on one stack. You wouldn't always want to terminate the editor when switching into game mode. Instead, you just switch between the screen managers.
Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now