Pin Me

Adding a main menu

written by: Matthew Casperson•edited by: Michele McDonough•updated: 6/4/2010

In this article we add some structure to the game by implementing a main menu screen.

  • slide 1 of 3

    Almost every game displays a main menu before the game itself is run. Up until now our JavaScript game has launched right into the game itself. It would be nice if we could display a menu first that gives some information about the game before it is run.

    The first thing we need to do in order to implement a main menu is to enable all the current game objects that are running to be removed all at once. This may seem backwards, but it makes sense when you consider that the main menu will be displayed before the game is played and also when it has ended. Obviously we don’t want to have the player running around on the main menu after the game has finished.

    GameObjectManager.js

    The GameObjectManager class gains a few new functions to facilitate this ability to remove all current game objects: shutdownAll, removeOldGameObjects and addNewGameObjects.

    The shutdownAll function is quite simple. It loops through the current collection of GameObjects and calls their shutdown function. This cleans up their resources and removed them from the game. [code]

    The removeOldGameObjects and addNewGameObjects functions have been added to avoid a situation where the main gameObjects collection is modified while it is being looped over. This can occur because an instance of the GameObject class is created or removed during a call to its update function. As an example, this can happen when a powerup collides with the player. The powerup will eventually call the shutdownGameObject function, which removed the GameObject from the main gameObjects collection. By placing new and removed GameObjects into placeholder collections, and then syncing them to main gameObjects collection outside of any code that loops over the gameObjects collection, we can ensure that we don’t get any of the hard to track down bugs that can occur when you modify a collection while looping over it. The Array.clear function was provided by the prototype javascript framework. [code]

    Finally, a small change needs to be made to the draw function to call the removeOldGameObjects and addNewGameObjects functions, ensuring that the gameObjects collection is kept in sync. [code]

    ApplicationManager.js

    The ApplicationManager is then modified to include two new functions: startLevel and openMainMenu.

    The startLevel function initializes the objects needs to create the game. This code was originally in the startupApplicationManager function. [code]

    The openMainMenu function creates a new instance of the new MainMenu class. Both the startLevel and openMainMenu functions call the GameObjectManager shutdownAll function to ensure the application has a clean slate before creating their respective objects. [code]

  • slide 2 of 3
  • slide 3 of 3

    MainMenu.js

    The MainMenu class is a very simple class that displays an image on the screen, and calls the ApplicationManager startLevel function when a key has been pressed.

    LevelEndPost.js

    The last additional class is the LevelEndPost. This class is very similar to the Powerup class, except that it calls the ApplicationManager openMainMenu function when the player touches it, effectively ending the current level. [code]

    One thing that is worth mentioning here is that each class that extends the GameObject class has two functions to enable them to be cleaned up: shutdown and shutdownClassName. This is because you can not override a parent function, and then still call that parent function.

    In object oriented languages you can normally make a call to super.functionName to call a parent function that has been overridden. JavaScript does not have this facility: if you override a function, you do not have the ability to call the parents function of the same name. We need to be able to do this though, because the GameObjectManager needs to be able to call the shutdown function (so every class extending the GameObject needs to have a shutdown function), and the shutdown function needs to be able to shutdown any base classes (so extending classes need to be able to shutdown their parent classes). By defining a function called shutdown in every class that extends GameObject, the GameObjectManager can safely call the shutdown function and know that all the resources will be cleaned up. But the shutdown functions only call the shutdownClassName function (so the AnimatedGameObjects shutdown function would call shutdownAnimatedGameObject). This shutdownClassName does the work of cleaning up any resources, and then call the parents shutdownParentClassName function (so the AnimatedGameObjects shutdownAnimatedGameObject function would make a call to shutdownVisualGameObject). This does require writing a bit of extra code, but it is an easy way to ensure that a common function like shutdown does actually shutdown the class it is called on, and all of that classes parents as well.

    That was a bit of a mouthful, but the following diagram should make it easier to understand. Take the classes VisualGameObject, AnimatedGameObject and Powerup. See how a call to the shutdown function in each class flows through to the base classes.

    VisualGameObject

    shutdown -> shutdownVisualGameObject -> shutdownGameObject

    AnimatedGameObject

    shutdown -> shutdownAnimatedGameObject -> shutdownVisualGameObject -> shutdownGameObject

    Powerup

    shutdown -> shutdownPowerup -> shutdownAnimatedGameObject -> shutdownVisualGameObject -> shutdownGameObject

    By adding the shutdownAll function to the GameObjectManager, and implementing a system whereby the shutdown function on all classes that extend the GameObject will recursively shutdown parent classes, we have a very easy way to clean up any game objects and swap back and forth between a main menu screen. In future articles we will use this ability to load new levels, and implement high score screens.

    Check out the online demo here, download the source code here, and browse the source code documentation here.