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.
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
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 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().
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.
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
Post a Comment