The problem

It is very common that an object needs to adapt its behaviour given what happens in its surrounding. Let us take for instance a game where there is a playable character and a Monster. When the playable character is far away, we want the monster to act in a “relaxed” way, maybe just walking around or sleeping. Otherwise, when the player gets closer the monster should start “attacking” the player.

All in all, this translates to the monster having a different set of responses to the same stimuli. For instance, we want the monster to wake up if the player is near and he is asleep, but we want it to be still if the player is near and the monster is actually dead. Similarly, we may want to see the energy bar float over the monster while we are fighting but we do not care about it if the monster is just in the distance.

The classic solution

The classic solution to this problem is to maintain an enumerator in the monster class to keep track of the current state, let’s say

private enum State { Attack, Rest, Dead} private State curState = State.Rest;

Then have a switch statement in the Update() and in all the relevant methods that defines each behaviour. Like so:

private void Update(){ switch ( curState ){ case State.Rest: //do rest break; case State.Attack: //do attack break; case State.Dead: //be dead break; // and so on... } }

This solution works pretty well and minimizes the code complexity for a small project. However

it is easy to see how this could soon get messy and out of hand when the states’ list grows. Then one would have to make changes in all the methods that contain a switch statement.

The More elegant solution

As we said, using the previous solution, our “state” code could grow over the reasonable threshold of manageability. A solution that works better, in this case, is presented in the famous GoF book “Design Patterns: Elements of Reusable OO Software”. In UML language, it is simply the following:



In the following we will explain in details what the above picture means.

The full code found in this section of this tutorial/post is freely available on my github account. I would strongly encourage to clone the project on the local computer to play with it in Unity. The uploaded code is very well commented using Doxygen standards. However in the following snippets, given the space limitations, most comments will be cut.

In the picture we can see that we are are going to define the following objects: Monster class, IState interface and AttackState / RestState that implement the above mentioned interface. The idea is to use polymorphism to change the behaviour of Monster on runtime. Let us start describing the Monster class:

public class Monster : MonoBehaviour { //public methods: public void ChangeState( IState newState ){ m_curState = newState; } //private methods: private void Awake(){ m_curState = new RestState(); } private void Update() { m_curState.Update(this); } private void OnTriggerEnter(){ m_curState.OnTriggerEnter(this); } private void OnTriggerExit(){ m_curState.OnTriggerExit(this); } //private members: private IState m_curState; }

The monster class inherits from Monobehaviour. It keeps a reference to an object of the kind IState in its private members and all the private methods, beside the Awake() function, are just wrappers that redirect to the corresponding methods in m_curState . We note that, in the methods, we are passing the pointer of the current instance of the Monster object ( this ) to the corresponding state’s method. This is not strictly necessary (however probably so) and we can chose to add it or not depending on what we need to accomplish. More on this later.

There is one public method called ChangeState(IState) that is used to update the current state. Finally, the Awake() method sets the initial state to “rest”.

We mentioned that we are going to use polymorphism to implement the different behaviors of the Monster. It is important in fact that the Monster class keeps an instance of the IState interface, not of the state itself. The Monster class can be passed any objects that implements the IState interface and won’t see the difference! Doing so we totally decoupled the monster from its behaviors (aka states) and made it very easy for us to add other states whenever in the future we feel like extending the scope of the game ( we do not need to fiddle in every method with a switch statement anymore!).

Let’s then see the IState interface:

public interface IState { void Update( Monster _monster ); void OnTriggerEnter( Monster _monster ); void OnTriggerExit( Monster _monster ); }

As we can see it is super-simple. It only needs to prototype the methods that we are going to implement in the states. It does not need to inherit from MonoBehaviour.

Then the states are

/** *Rest State */ public class RestState : IState { public virtual void Update( Monster _monster ){ if( !_monster.animation.isPlaying ) _monster.animation.PlayQueued( "Sleep", QueueMode.CompleteOthers ); } public virtual void OnTriggerEnter( Monster _monster ){ _monster.animation.PlayQueued( "GetUp", QueueMode.CompleteOthers ); _monster.ChangeState( new AttackState() ); } public virtual void OnTriggerExit( Monster _monster ){} } /** *Attack State */ public class AttackState : IState { public virtual void Update( Monster _monster ){ if( !_monster.animation.isPlaying ) _monster.animation.PlayQueued( "Attack", QueueMode.CompleteOthers ); } public virtual void OnTriggerEnter( Monster _monster ){ //does nothing } public virtual void OnTriggerExit( Monster _monster ){ _monster.animation.PlayQueued( "GoToSleep", QueueMode.CompleteOthers ); _monster.ChangeState( new RestState() ); } }

Let us discuss first the “RestState”, which is the state that the monster starts in. We see that the class “RestState” implements Update() by playing an animation called “Sleep”. Then when the trigger is crossed it plays the “GetUp” animation and changes state. Similar things happen in “AttackState”, but the animations are “Attack” and “GoToSleep”. We note that some of the methods are left empty, this might seem like a waste of lines at first, however inheriting from an Interface means that we have to implement all the declared methods, even if just as functions that “do nothing”.

A few considerations on the reference to Monster we are passing to the states are in order. We see that in both RestState and AttackState we are using this reference to Monster just to play the animations when appropriate. We could however use this reference to access any public method of monster. In another case, instead, we could decide that we do not need to pass anything to the state; for instance, in this particular case, if we wanted to attach the scripts onto the physical monster gameObject carrying the animations, we could just play them invoking animation.PlayQueued(...) . However, we chose not to attach the script to any game object and therefore we need to pass the reference. We chose not to attach it because we foresee that we will actually need to access easily the public methods of Monster in the real game project.

Below we embed an instance of the project so (with the Unity plugin for the browser) one can see the demo without having to clone the github repository.

The sample project ( aka good sphere and evil cylinder )

Use the arrow keys to get close to the “monster” cylinder.

As you can see, the cylinder is “clearly” sleeping until the sphere gets close. Then it gets up and changes to “attack” mode, which in our case, just means jumping..

As soon as we get far enough though, the cylinder Monster goes back to sleeping.

The needed conclusions and remarks

This implementation of the pattern is supposed to be extremely simple and just for demonstration purposes. For instance we chose to let the state themselves dictate when the state should change to something else. This is far from ideal for two reasons:

The states in theory should not “know” anything about each other. Having the RestState class changing the state of the monster into AttackState not only does not make much sense, but most importantly implies that the state concrete classes are more coupled than they should. This should be avoided.

Second, this implementation changes states invoking a method in the Monster class as in the following ChangeState( new RestState ) . This means that we instantiate a new state object every time we change state, which just means we are in the hands of the garbage collector that will have to take care of this. This too could be avoided having a StateManager class that instantiates all the states once and uses them in ChangeState( myRestState ) . However this would create additional complications and obfuscate the part of the code that is actually relevant for the Finite State Machine pattern, which actually does not specify how to handle the state change.

In a more involved case, where memory and performance are important, one should take this into consideration and add the needed modifications to the code.