Design In-game Entities. Object Composition Strategies. Part 2 – The State Pattern

In this part I will try to explain how to design easily extensible and maintainable game elements that control their own internal state and behaviours.
An internal state is best described as being the soul and mind of the entity. In the first part I described why composition is better than inheritance. In a nutshell composition provides the means to interchange the algorithms associated with their behaviours. State on the other hand helps objects to control their own behaviours.

If you are not familiar with the behaviours and strategies, I strongly suggest to go and check out the previous article as I will be picking up those droids and make them utterly clever during the next articles. But first we need to take a closer look to how I design less clever entities, like weapons.

Let’s design an old fashioned rifle and learn from the process how to design the next gen weapons to fend off the invading droid army.

Breaking it down, what can one do with a rifle? Pull the trigger of course and reload (insert, eject the ammo clip).
Now think of all the scenarios. What happens if I pull the trigger and there is no clip? Or when there is one but it’s empty? Apparently a simple thing became a bit more complicated. Let’s see it on paper:

Initial Rifle State Diagram

Let’s examine the diagram and figure out what it is and what is that we want.
The above diagram is called a State Diagram.
Each of those circles is a State and each of those arrows is a State Transition.
Each state is just a different configuration of the rifle. The rifle behaves in certain ways depending in which state it is in and some action is needed to take it to another state. So, to go to another state, you will need to do something like pull the trigger or insert clip. See the arrows on the diagram.

We identify the following states:

  • No Clip
  • Has Clip
  • Ammo fired
  • Out of Ammo

and actions (transitions):

  • inserts clip
  • ejects clip
  • pulls trigger
  • fire ammo

Note: I used third person for 3 of the actions. It is because the user of the weapon will trigger these actions while fire ammo is more of an internal action.

The whole thing described above is also called a Finite State Machine. It is nothing more than an object that holds a finite number of states that govern behaviour and the object can be in only one state at any given time.

Our First Implementation

Knowing all this, what would be our first choice for the implementation? A class that has all the possible states and actions, right? It should also hold the current state. Simple.

Create the Rifle.java class.

public class Rifle {

	// defining the states
	final static int NO_CLIP		= 0;
	final static int HAS_CLIP		= 1;
	final static int AMMO_FIRED		= 2;
	final static int OUT_OF_AMMO	= 3;
	
	int state = NO_CLIP;	// instance variable holding the current state
	int ammoCount = 0;		// we count the ammo
}

Great! We created the structure of the rifle. We also want to know when we are out of ammo, so we added the ammoCount variable. They are set to default values. The rifle holds no clip thus the ammo is 0 when it is created.

Now let’s add the actions. But beware! Exposing all the actions to someone handling the weapon is dangerous. What will happen when someone tries to pull out the clip while firing? We need to take these into consideration when triggering the actions.

	// **********************
	// Creating the actions
	// **********************

	public void insertClip() {
		// We check each possible state and act according to them
		if (state == HAS_CLIP) {
			System.out.println("There is already a clip loaded.");
		} else if (state == AMMO_FIRED) {
			System.out.println("You'll hurt yourself!!!");
		} else if (state == OUT_OF_AMMO) {
			System.out.println("You need to take out the empty clip first.");
		} else if (state == NO_CLIP) {
			state = HAS_CLIP;
			ammoCount = 10;
			System.out.println("You have loaded a clip with " + ammoCount + " bulletts.");
		}
	}

	public void ejectClip() {
		if (state == NO_CLIP) {
			System.out.println("The magazine is empty.");
		} else if (state == AMMO_FIRED) {
			System.out.println("You'll hurt yourself!!!");
		} else if (state == HAS_CLIP) {
			// You could still eject it if you want but for the sake of
			// simplicity let's use up the ammo first
			System.out.println("Use up all your ammo first.");
		} else if (state == OUT_OF_AMMO) {
			state = NO_CLIP;
			System.out.println("You have unloaded a clip.");
		}
	}

	public void pullTrigger() {
		if (state == NO_CLIP) {
			System.out.println("Empty Click!");
		} else if (state == AMMO_FIRED) {
			System.out.println("Jammed!");
		} else if (state == OUT_OF_AMMO) {
			System.out.println("Click! Out of ammo.");
		} else if (state == HAS_CLIP) {
			System.out.println("BANG!!!");
			state = AMMO_FIRED;
			fireAmmo();
		}
	}

	public void fireAmmo() {
		if (state == NO_CLIP) {
			System.out.println("Empty magazine.");
		} else if (state == AMMO_FIRED) {
			System.out.println("Bullet already on its way to kill someone!");
		} else if (state == OUT_OF_AMMO) {
			System.out.println("Out of ammo.");
		} else if (state == HAS_CLIP) {
			state = AMMO_FIRED;
			ammoCount--;
			System.out.println("Bullet on its way!");
			// we check if the clip is empty
			if (ammoCount == 0) {
				// yes, it's empty
				System.out.println("Darn! Out of ammo");
				state = OUT_OF_AMMO;
			} else {
				state = HAS_CLIP;
			}
		}
	}

Let’s put the rifle to the test.
Create the RifleTest.java class.

public class RifleTest {
	
	public static void main(String[] args) {
		Rifle rifle = new Rifle();
		System.out.println(rifle);
		
		rifle.insertClip();
		rifle.pullTrigger();
		rifle.pullTrigger();
		rifle.pullTrigger();
		rifle.pullTrigger();
		
		System.out.println(rifle);
		
		rifle.insertClip();
		rifle.ejectClip();
		rifle.pullTrigger();
	}
}

It is a very simple scripted scenario which performs some actions on the rifle. Some may be good some bad. As when trying to force in a second clip or pulling the trigger when it’s out of ammo.

Check out the result and examine it carefully. How cool is that? We are the Kalashnikovs of our age.

<< RIFLE [state=Empty Magazine (No Clip), ammo=0] >>
> You have loaded a clip with 3 bulletts.
> BANG!!!
> Bullet on its way!
> BANG!!!
> Bullet on its way!
> BANG!!!
> Bullet on its way!
> Darn! Out of ammo
!* Click! Out of ammo.
<< RIFLE [state=Out of Ammo, ammo=0] >&g;t
!* You need to take out the empty clip first.
> You have unloaded a clip.
!* Empty Click! – No clip!

Note that I have omitted the toString() method for the Rifle.

Well done! We have our first state machine.

But

We can’t do much firing bullet by bullet. We need automatic fire! Oh, and we can’t just let people running around with rifles without the safety ON.

Ah, that’s easy, right? We’ll have a few more states and a few more transitions.
But wait, we will need to rework the Rifle class a bit.
Let’s see what we need to modify just to support automatic and manual fire:

  • we need to add the two states
  • but then we need to modify every single method to handle the states by adding conditional statements
  • pullTrigger() will get complicated as it will need to know what state it is in and check bullets and fire them as such

That is a LOT of work. It must be some other way.

The Solution

What if we give each state a behaviour and put it into its own class? This way each state will implement its own actions only. We will have the rifle class delegating the action to the state object that represents the current state.

Let’s see how does it look?

What you should notice is that the Has Clip is now Manual/Auto and has a switch transition. It basically has a sub-state now. Flipping the switch changes the behaviour. Both states will have the pull trigger action but each state will behave differently. This is easily achieved with interfaces, right?

Let’s start coding then. First, let’s create the state interface. Remember, each state will implement its transition and will provide the dummy implementation for the rest. The interface will contain all the actions. The methods map directly to all the actions that can happen with the Rifle

public interface RifleState {

	public void insertClip();
	public void ejectClip();
	public void swithManualAuto();
	public void pullTrigger();
	public void fireAmmo();
}

The new Rifle class will have none of the implemented actions, but will have all the states and will delegate the actions to its current state.

Rifle.java

public class Rifle {

	// the states of the rifle
	RifleState emptyState;
	RifleState autoFireState;
	RifleState manualFireState;
	RifleState outOfAmmoState;
	RifleState roundFiredState;
	RifleState ammoFiredState;
	
	RifleState state = emptyState;
	int ammoCount = 0;
	
	// constructor
	public Rifle() {
		// creating states
		this.emptyState 		= new NoClipState(this);
		this.autoFireState 		= new AutoFireState(this);
		this.manualFireState	= new ManualFireState(this);
		this.outOfAmmoState		= new OutOfAmmoState(this);
		this.roundFiredState	= new RoundFiredState(this);
		this.ammoFiredState		= new AmmoFiredState(this);
		
		this.state 		= this.emptyState;
		this.ammoCount 	= 0;
	}
	// convenience methods - delegating only
	public void insertClip() {
		this.state.insertClip();
	}
	public void ejectClip() {
		this.state.ejectClip();
	}
	public void switchManualAuto() {
		this.state.switchManualAuto();
	}
	public void pullTrigger() {
		this.state.pullTrigger();
	}
	
	// getters and setters
	// ... omitted
}

You see that the class has changed a bit. It has all the states and a current state. It has a constructor too. The constructor is needed to set up the rifle and pass itself as a reference to all of the states to give them access to the rifle’s properties. In our case just the ammo count and current state need to be accessed.
Also the fireAmmo() is missing as it is a state internal action.

Now let’s map the states to actual classes. These are the same as in the original rifle class.
I will list one full class and for the rest only the methods that change the state. Examine the source code for the complete listings.

OutOfAmmoState.java

public class OutOfAmmoState implements RifleState {

	private Rifle rifle;
	public OutOfAmmoState(Rifle rifle) {
		this.rifle = rifle;
	}
	
	@Override
	public void ejectClip() {
		rifle.setState(rifle.getEmptyState());
		System.out.println("> Clip ejected.");
	}

	@Override
	public void fireAmmo() {
		System.out.println("!* You can't fire with no ammo.");
	}

	@Override
	public void insertClip() {
		System.out.println("!* There is an empty clip inserted already!");
	}

	@Override
	public void pullTrigger() {
		System.out.println("!* Out of ammo!");
	}

	@Override
	public void switchManualAuto() {
		System.out.println("!* Plesea reload first");
	}
}

Notice that the only way out of the OutOfAmmoState is by ejecting the clip.
Every other attempt will do nothing.
Also note the constructor. We are passing the reference to the rifle there.

Check out the other classes too:

AmmoFiredState

public class AmmoFiredState implements RifleState {

	private Rifle rifle;
	public AmmoFiredState(Rifle rifle) {
		this.rifle = rifle;
	}

	@Override
	public void fireAmmo() {
		rifle.setAmmoCount(rifle.getAmmoCount() - 1);
		System.out.println("> Fired 1 bullet.");
		if (rifle.getAmmoCount() == 0) {
			rifle.setState(rifle.getOutOfAmmoState());
		} else {
			rifle.setState(rifle.getManualFireState());
		}
	}
	// ... ommited
}

AutoFireState

public class AutoFireState implements RifleState {

	private Rifle rifle;
	public AutoFireState(Rifle rifle) {
		this.rifle = rifle;
	}

	@Override
	public void ejectClip() {
		rifle.setAmmoCount(0);
		rifle.setState(rifle.getEmptyState());
		System.out.println("> Clip ejected. Please reload.");
	}

	@Override
	public void pullTrigger() {
		System.out.println("> Pulled trigger.");
		rifle.setState(rifle.getRoundFiredState());
		rifle.getState().fireAmmo();
	}

	@Override
	public void switchManualAuto() {
		rifle.setState(rifle.getManualFireState());
		System.out.println("> Switched to manual. Hope they are slow and few!");
	}
	// ... ommited
}

If you follow the diagram then you should be able to figure out the transitions. There is a trick there as the Manual and Auto modes are very similar and I just transition between them. There is a drawback as after a reload, the manual state is the active one even if the auto was set before. But I’m sure you can figure out a quick fix.

ManualFireState


public class ManualFireState implements RifleState {
	
	private Rifle rifle;
	public ManualFireState(Rifle rifle) {
		this.rifle = rifle;
	}

	@Override
	public void ejectClip() {
		rifle.setAmmoCount(0);
		rifle.setState(rifle.getEmptyState());
		System.out.println("> Clip ejected. Please reload.");
	}

	@Override
	public void pullTrigger() {
		System.out.println("> Pulled trigger.");
		rifle.setState(rifle.getAmmoFiredState());
		rifle.getState().fireAmmo();
	}

	@Override
	public void switchManualAuto() {
		rifle.setState(rifle.getAutoFireState());
		System.out.println("> Switched to auto. Bring'em on!!!");
	}

	// ... ommited
}

NoClipState

public class NoClipState implements RifleState {
	
	private Rifle rifle;
	public NoClipState(Rifle rifle) {
		this.rifle = rifle;
	}

	@Override
	public void insertClip() {
		rifle.ammoCount = 50;
		rifle.setState(rifle.getManualFireState());
	}

	// ...ommited
}

RoundFiredState

public class RoundFiredState implements RifleState {

	private Rifle rifle;
	public RoundFiredState(Rifle rifle) {
		this.rifle = rifle;
	}

	@Override
	public void fireAmmo() {
		int count = 10;
		while (count > 0 && rifle.getAmmoCount() > 0) {
			System.out.print("> BANG! ");
			rifle.setAmmoCount(rifle.getAmmoCount() - 1);
			count--;
		}
		System.out.println();
		System.out.println("> Fired a round of " + (10 - count) + " bullets. Yeah!");
		if (rifle.getAmmoCount() <= 0) {
			rifle.setAmmoCount(0);
			rifle.setState(rifle.getOutOfAmmoState());
		} else {
			rifle.setState(rifle.getAutoFireState());
		}
	}
	// ...ommited
}

Great! Let’s throw together a test for the new shiny Rifle.

RifleTest

public class RifleTest {

	public static void main(String[] args) {
		Rifle rifle = new Rifle();
		
		rifle.pullTrigger();
		rifle.ejectClip();
		rifle.insertClip();
		rifle.pullTrigger();
		rifle.switchManualAuto();
		rifle.pullTrigger();
		rifle.pullTrigger();
		rifle.switchManualAuto();
		rifle.pullTrigger();
		rifle.insertClip();
		rifle.switchManualAuto();
		rifle.pullTrigger();
		rifle.pullTrigger();
		rifle.pullTrigger();
		rifle.pullTrigger();
		rifle.pullTrigger();
	}

Examine the output very carefully and go through the source code. You should try adding new features or think of other scenarios.

!* You can’t fire with an empty magazine.
!* The magazine is empty.
> Pulled trigger.
> Fired 1 bullet.
> Switched to auto. Bring’em on!!!
> Pulled trigger.
> BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! > BANG! >BANG! >BANG!
> Fired a round of 10 bullets. Yeah!
> Pulled trigger.
>BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! > BANG! >BANG! >BANG!
> Fired a round of 10 bullets. Yeah!
> Switched to manual. Hope they are slow and few!
> Pulled trigger.
> Fired 1 bullet.
!* Clip is already present!
> Switched to auto. Bring’em on!!!
> Pulled trigger.
> BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! > BANG! >BANG! >BANG!
> Fired a round of 10 bullets. Yeah!
> Pulled trigger.
> BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! > BANG! >BANG! >BANG!
> Fired a round of 10 bullets. Yeah!
> Pulled trigger.
> BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG! >BANG!
> Fired a round of 8 bullets. Yeah!
!* Out of ammo!
!* Out of ammo!

Again, the yellow lines show you when you tried something dodgy.
Voila! We have state machines and easily extensible game elements.
I strongly encourage you to extend it and build your own, as it is a very important element of game design.
You can apply this principle for the whole game and infrastructure. Think of the game as a whole and when you’re on the menu screen (that’s the Menu State), when you’re in the paused screen, that’s the Pause State, or the main screen that’s the Running State. You could create a framework and easily add different game states.

I do hope this gave you a good introduction on how to implement state driven behaviours. Note that I used normal Java practices to write the code for clarity. Meaning that when writing a game, especially for Android, you might not need to overload your classes with getters and setters and you should adhere to the optimized ways. You could use public attributes and access them directly for example. But it was not the scope of this article.

Also understanding this is crucial to make a step towards autonomous agents (automatons). Next time I will introduce event and/or message driven behaviours. We will return to our beloved droids to give them wits to outrun you.

Download the source code and project here (obviam.states.tgz).

Note that the first attempt was renamed to RifleOld.java and RifleOldTest.java

LinkedInRedditTumblrDiggTechnorati FavoritesShare

10 Responses - Add Yours+

  1. Alan Bartlett says:

    Hey nice tutorial,
    I was wondering if using enums would be a nice clean way of using a state machine as well instead of integer constants like you have used?

  2. maxha says:

    Great tutorial! But I was wondering wether this doesn’t give you a lot of classes to work with, if you’re having multiple states for each object-type, and then also have different states for the components (from your great components article).

    Am I missing something, or do you just have tons of (cluttered) classes in a project?

    • Impaler says:

      First you will create your models that you will use in the game. This can be a mix of components and inheritance of course. Then you can design the behaviours and states. Depending on how extensible you want your engine, you can design it completely with generic entities or a mix of behaviours and set objects.
      Also Java helps a lot with the packages and classes can be grouped logically. Also you can create inner classes for behaviours under a certain logical group.
      You can also check out Artemis which is really neat.

      You might still end up with tons of classes, but having them grouped, certainly helps. Usually it’s not that big a number if designed well. Don’t have to normalize it to the utter extent.

      And thanks for the appreciation, I’m happy that it is useful.

  3. Deepthi says:

    I am interested in game programming and trying to develop a game i learned basics from your site, however i do not have an idea how to implement different levels of the game please post on this topic or point me to some resources on this, by the way great site and really helpful thank you very much.

  4. [...] First we create the renderer interface. We use this to establish a single way to interact with the renderer and it will make it easy to create more views without affecting the game engine. To read more on why is a good idea check this and this. [...]

  5. Ben says:

    No offence, but this doesn’t seem like a very elegant state machine solution. I base mine from “Programming Game AI By Example”, and use a single State class, where T is the type of entity I want the state to worth with, for example Player. Each State has 3 methods: enter(T entity), execute(T entity), and exit(T entity). enter/exit are called when the state becomes the ‘active’ state or before another state becomes active. execute is called each game loop when the game object’s state is updated.

    There’s also a simple StateMachine class which has basically is responsible for keeping a list of States and switching between them. The game object has an instance of this state machine, for example StateMachine fsm = new StateMachine;

    In my Player class, I create a subclass (either anonymous or inner-class, whatever your preference is) for each state. For this example, lets say something like this: fsm.addState( new State(“running”) {…}); Obviously you’d also implement enter, execute, and exit to suit your needs. I also passed a string as the state’s ID so I can switch to it later.

    To switch states, I just call fsm.changeTo(“running”); The StateMachine.changeTo() method calls the current state’s exit method, changes the current state to the new state, and calls the new state’s enter method.

    Umm, it’s a little hard to understand just from my explanation, so you can see my code from my SVN repository.

    State:
    http://svn.quillaja.net/androidlib/trunk/src/net/quillaja/lib/game/ai/State.java

    StateMachine:
    http://svn.quillaja.net/androidlib/trunk/src/net/quillaja/lib/game/ai/StateMachine.java

    • Impaler says:

      I agree that it is not perfect but it is the purest implementation of the state pattern.
      I do the same as you and I am using a mix of the state and command pattern.
      You introduced an orchestrator as the StateMachine and that has knowledge of the flow.
      I was planning to follow this article up with improvements.

      Thanks for your comments and will follow this up.

      EDIT
      The StateMachine is basically the core AI which based on the current state will act differently.
      For example if my robot is threatened, then the StateMachine will have to change to the corresponding state. That state’s implementation will have a coded sequence of behaviours, like: speeding away from the threat and also firing on the pursuer.
      If a pursue state is active, then that state will have to call upon a few behaviours like attack, reload, pursue.
      The way I implemented it, makes for a more descriptive implementation.
      A mixed approach would be a good compromise though.

  6. Great article! I was just trying to figure out a way to cleanly handle game states: paused, play, game over… I will go for this approach. Thanks.

Leave a Reply

You must be logged in to post a comment.