Skip to main content

State Of The Nation

In the last post I wrote a simple state machine to delay some initialisation code until the required resources had loaded. It was quite an ugly hack, so this time I'm going to refactor that and make it a lot nicer. I will be adding a state manager system and three different states: Loading, Title Screen and Game.


What Is A State?

A state is a description of a system in a particular mode of operation. A bit like an object in OOP, a single state encapsulates everything the system needs to know about a single mode of operation. Only one state can be active at any one time. Transitions (think: events) move the system from one state to the another.

In our case we will start off with just three states:
  • Loading - The system will remain in this state until resource are loaded, then it will transition to..
  • Title Screen - This state will show some simple instructions on the screen. When the user presses the ENTER key the system will transition to..
  • Game - This is the main game state that I've been working on in the previous posts. For the time being our system will stay in this state forever, but in a later post I'll make it transition out of here back into the Title Screen state once the game is over
All of our states have update() and render() actions. They also have enter() and exit() actions. Enter() is called just before the state's first update and allows the state to do any state-specific operations, while exit() is called just before the system transition to the next state. You might use these actions, for example, to start a piece of music on the title screen in enter() and stop it in exit(). There is also one other function, isReadyToExit(), which returns true when the current state is ready to transition to the next one.

The State Manager

A global object called the state manager manages the states. It has a state stack - a FIFO list of the upcoming states. Using a stack is not how a classic state machine works, but it's a good solution for this system. New states are pushed to the manager (with the pushState() function) and then the current state exits when its isReadyToExit() function returns true. The state manager also takes care of calling each state's enter(), exit(), update() and render() functions at the right times.

Let's take a look at the code for the state manager:

The update() and render() functions get called from the main loop. Notice that the state manager logs activity to the console - you can view this by hitting F12 in Chrome (or Firefox) and choosing the console tab in the debugger.

The States

Here's the code for the states:


You'll see the base state object at the start. This state does nothing other than to act as a parent class to the other states. Note that the constructor takes a name - this is used in the debug output to make it easy to follow how and when the state manager changes states.

Next up is LoadingState. This state exits when loading of the font Image resource is complete, and initialises a bunch of other resources in its exit function.

The TitleScreeState shows some instruction text on the screen and waits for the player to press ENTER.

Finally, GameState contains much of the code that used to be in the old init() and mainLoop() functions: I add a bunch of spawners and a player to the object manager, then update and collide them in update() and render them in render().

Wrapping Up

I added a state manager and three different states. Each states encapsulates the system operating in a different mode. Events are used to transition from one state to the next. Each state has optional enter and exit actions that are used a bit like object constructors and destructors.

Game code is here and the online version is here.

Next Time..

Next time I think I'll do a bit of housekeeping by adding a few small improvements all in one post. I'll gather together the game constants in once place to make them easier to manage, add better debugging output and use Python to serve the files from the local machine to make it possible to run the game without having to copy them up to a webserver first.

Comments

Popular posts from this blog

Set The Controls For The Heart Of The Sun

When we last met, I had just started work on a level editor. I'd got as far as adding the ability to select an object and move it around, and then I added an undo/redo system using the command pattern. That was a good start, but dragging items around the level is only fun for so long. What I really want to be doing is.. ..editing the properties of the bullet spawners! And I want to be doing this in realtime as the game plays so that I can immediately see what effect my changes have made to the gameplay of the level.

World In Motion

In the last post I touched on how easy it is to score in this game - you can just camp out on the score bullet spawner and watch the points rack up. I'm going to add a little delay to the score bullets so that they start out in a deactivated and uncollectable state, and then change to active and collectable after a short time - say, half a second. To make it clear what state they are in I'm going to add code to let me change the look of Objects and allow them to be animated.

The Long And Winding Road

I started this blog back in November of last year. My aim was to document the development of a Bullet Hell shoot-em-up, written in JavaScript. Here we are, six months later, and lots has happened. With 20 posts already written, I thought that now would be a good time to take stock of what I've already done, and to look to the future and see what's to come.