The State Pattern applied to game development
[ August 31, 2004 ] by Cesar Tardaguila | Javier Tardaguila
Learn how to implement the State pattern as a way to develop complex games, where objects alter their behavior when their internal state changes.


We are going to try to implement the State pattern as a way to develop complex games or games whose entities have a complex or reactive behaviour.

First, we must consider that this implementation is quite lazy, and the example we’re going to explain is simple enough to be explained, but with some complexity, so we can consider to implement this solution. Obviously, as the complexity of the game behaviour, or the complexity of the game entities behaviour grows, this will become a better solution. And also remember that my English is very poor, so, please, be nice :$

So, let’s start. First, let’s see what “state pattern” means. The intent is: allow an object to alter its behavior when its internal state changes. The object will appear to change its class (here you can find a better explanation).

So, this pattern should be a good solution when, for instance:

  1. the behaviour of an object depends of its internal state, and must change at runtime depending of that state;
  2. to describe the object’s behaviour we use long conditional sentences, with multiple branches. We’ll try to put each branch in a different object.

So, in other words, we will try to describe an object’s behaviour as a collection of different states, in a way that the object itself could manage its behaviour moving from one state to another.

Sounds interesting, isn’t it?. Let’s try to build an example.

Now we need some imagination. Imagine we have to develop a game: “Explode the bubble”. There will be a given number of bubbles on the stage that bounce when they hit the ground, but that don’t bounce against the walls (I mean, if a bubble leaves the stage by its right side, it must appear again by the left side, and the opposite). There’s a given time to explode a given number of bubbles (clicking them). When a bubble explodes, another one appears, so there’s always the same number of bubbles on stage. The initial position and velocity (velocity as a vector, not speed) are setted randomly. So, if we explode less than the minimum number of bubbles, we loose, but if we explode more than that minimum number, we are offered to give it another try. Then we can leave the game, or try again, but we’ll have to explode more bubbles in less time. And so on, until we loose, or we leave the game.

At first sight, we can separate our code into two different entities: the game world, and the bubble, so we could write two different classes. The first one will manage the top level logic (putting bubbles on stage, checking if there have been enough exploded bubbles, checking if the time is over…), and the second one will manage the bubble behaviour (bounces, explosions, etc.). Let’s take a closer look at the last one.

Obviously, the graphic representation of the bubble will be a MovieClip. So we could think about the Bubble class as a subclass of MovieClip, where the onEnterFrame method will be responsible of checking if the ball has left the stage, if it must bounce against the floor, that places the ball on the stage depending of those circumstances (in other words, that implements a mechanism to calculate the bubble’s movement equation), that detects when the user has clicked the ball (and tells it to the game world), that manages the explosion animation, etc.

Well, I guess this is not the moment to discuss about inheritance and composition (I hope so, at least). Anyway, I don’t think there’s a right way and a wrong way of doing things (or of writing code). But, in this case the above approach doesn’t seem to be the most appropriate.

First, our Bubble class will have to implement a wide open range of functionalities (from physical behaviours to just graphics presentation). So the cohesion will be very low. And that’s not very good (in other words: keep complexity manageable).

But also, the Bubble behaviour should be implemented using a long switch statement, or a lot of “if” sentences (if it must bounce, make it bounce; if it leaves the stage, put the bubble in it’s new position; if nothing else happens, just calculate it’s new position and place it). And that’s one of the scenarios to implement this pattern. And, not in this case, but if the entity’s behaviour is reactive, everything makes even more sense.

So, we’ll try to manage the object’s behaviour as a collection of related states, so the entity that implements that collection of states (or state machine) will be able to transit from one state to another. So we’ll have a class (bubble) that aggregates a collection of objects (the states) and a graphic to manage its presentation (a movieclip).

We are going to implement a non-hierarchical, non-concurrent state machine. If you want to read a deeper essay about state machines, I strongly recommend to take a look at FlashSim or quantum-leaps (thanks to Jonathan Kaye for the links). We will try to make things as simple as possible for the shale of performance (remember, we are developing a game).

First, here are two UML diagrams (statechart diagrams):

The bubble:

The game world:

Let’s take a closer look at the last diagram. There can be seen the different states that we’ve defined:

  1. initGame: general game initialization.
  2. initRound: general initialization of each game round. There will be setted the exploded bubbles counter, the time counter, etc.
  3. gamePlay: the user is playing the game.
  4. endOfTime: the time is over. We’ll check if the player has exploded enough bubbles.
  5. defeat: the player has not exploded bubbles enough. Ohhhhhhh.
  6. newChallenge: we offer the player the chance to play again, or to leave the game. If the player chooses to play again, we’ll move to initRound, and if the player chooses to leave the game, we’ll move to endOfGame.
  7. endOfGame: the game is over. We can send the player score to a server side script, etc.


Well, now that the concept has been explained we’ll try to explain how the state machine works.

First of all, when we enter a state an action is executed. In the most common state machine implementation there are three actions for each state, one will be executed when entering the state, another one when the state is executed, and another one when we leave the state. In this example, we’ll try to make everything as simple as possible, for the shake of performance, and we’ll execute just one action for each state.

Each arrow represents a transition. Each state contains a collection of transitions. This transitions can be callbacks that return a Boolean value, so the state machine will move by the transitions that returns a value of true. Usually, these transitions evaluate a given property of the class, and return true or false. Let’s explain it a bit more.

The state machine is closely tightened to a timer. So with every tick of the timer, some logic is executed (all the transitions that start at the actual state are evaluated), and state machine will move using the first transition that evaluates as true. So it will move to another state, where (when the next tick occurs) it will execute that state action. And next, it will evaluate more transitions, and…

Before taking a look at some code, we’ll try to explain it better going back to the Bubble class (and diagram). Let’s remember that this class is not a MovieClip subclass, but a complex entity that aggregates its state machine, and a movieclip.

So, when we create an instance of this class, and we create and start its state machine, will be in the first state: initBall. So, the state action (initBallAction) will be executed, and this action will attach a movieclip, and place it on stage. Then it will set a class flag (isInitFlag, for instance) to true, and it will set another flag to false (isOutOfBoundsFlag). With every timer tick, the transitions associated to this state will be evaluated (here, there’s only one transition, that starts at initBall, and ends at moveBall). So if that transitions returns the value of isInitFlag, it will return true, so the state machine will transit to the next state (moveBall).

This state has three transitions: the first one, that ends at itself, aonther one that ends at outOfBounds, and another one that ends at destroyBall.

So these transitions will evaluate (in order) the following flags: isOutOfBounds == false, isOutOfBounds == true and isClickedFlag == true.

When this state action is executed, first, we’ll calculate the next position of the bubble. Then, we’ll check if that position is out of the stage (that includes bouncing against the floor). If the bubble is out of stage, well set isOutOfBounds to true. So, if the bubble has not gone out of the stage, that flag will still be false. So, the transition that will return true will be the one that moves the state machine to the same state (isOutOfBounds == false), so well enter again the same state, so we’ll calculate the next ball position again, etc.

If the ball goes out of the stage, the transition that ends at outOfBounds will be the one to return true. So, the state machine will move to that state, where we’ll change the ball position or its velocity, and then we’ll return again to the moveBall state.

Later on, we’ll see the code to implement all this, but now, the most important thing is to understand that is the entity itself the one that, just checking the value of some internal flags, changes it’s behaviour. And that that behaviour is separated in a collection of different objects.

(continues on page 2)


           
 
 
Name: Cesar Tardaguila | Javier Tardaguila
Location: Madrid, Spain | Vitoria-Gasteiz, Spain
Age: N/A
Flash experience: Cesar: started out with Flash in 1999
Javier: started out with Flash in 2002
Job: web/flash/java developer | web/flash/flashcomm developer
Website: http://www.design-nation.net/en
 
 
| Homepage | News | Games | Articles | Multiplayer Central | Reviews | Spotlight | Forums | Info | Links | Contact us | Advertise | Credits |

| www.smartfoxserver.com | www.gotoandplay.biz | www.openspace-engine.com |

gotoAndPlay() v 3.0.0 -- (c)2003-2008 gotoAndPlay() Team -- P.IVA 03121770048