Make a basic FSM in Unity/C#

Let’s design a simple 2 states-FSM for 2D physics-based player movement!

🚀 Find all of my Unity tutorials on Github!

This article is also available on Medium.

This tutorial is available either in video format or in text format – see below 🙂

Download the full code for this project (Parts I — current article — and II) on my Github! 🙂

What are FSMs?

States and transitions

Finite State Machines, or FSMs, are a particular kind of automata that are used to represent and study simple machines. The idea with FSMs is that:

  • you have a given finite set of states that your entity can be in
  • only one of these states can be active at the same time, it’s called the current (or active) state
  • external or internal inputs trigger a transition from the current state to another one
  • and so a state transition makes the state machine switch to a new current state

States themselves should have three important entry points:

  • the Enter() method, for all the initialisation process to do when you transition to this state
  • the Update() method, for the logic that is run continuously while the entity is in this state
  • the Exit() method, for any clean ups required before transition from this state

Deterministic VS stochastic state machines

Also, state machines can be either deterministic or stochastic. Deterministic FSMs, like the one we’ll work on in this tutorial, are made so that when you’re in a given state and you receive a given input, you know exactly which transition will occur and what new active state you’ll end up in. Stochastic state machines, on the other end, have some “randomness” to their transitions; this means that you may transition to different states and ultimately have your entity behave differently even if you repeat the exact same chain of events.

Note however that stochastic rarely means “pure random”; rather, it’s about giving weights to transitions so that several have a chance of happening but that you still retain a control over the overall behaviour of your entity.

Why use state machines?

As each state represents a specific behaviour for your entity and is written in its own class, FSMs are, generally speaking, a nice way of decoupling behaviours to better organise your project. But they’re usually more adapted to simple systems, because this separation isn’t absolute and therefore lots of errors and complexity can creep in as the machine’s behaviour starts to grow.

The nice thing with state machines is that they let you centralise the logic and the impact a state has on your entity in a single place. For example, if your unit is in a “moving” state, you might want to accompany this purely abstract data information with an animation, or a sound. Your state class will encapsulate all of this and, in its Enter() and Exit() methods, it will take care of communicating with the relevant components on your entity to properly “show” the state. Similarly, its Update() logic will have a specific way of handling inputs and transitioning to other states in the state machine, which makes it easy to follow the different evolutions of your entity throughout the game.

The big picture

In Unity, we can implement state machines fairly easily using basic C# classes, inheritance and virtual methods.

In this tutorial, we’ll also see how to use Unity’s 2D physics, and especially the rigidbodies, to apply motion to our player and have it transform the user’s input into an actual horizontal velocity. We’ll have the player go from its “idle” to its “moving” state whenever the user presses the left or right arrow key, and vice-versa.

So – are you ready? Then, let’s dive in! 🙂

Step 1: Setting up the scene

First of all, let’s change the colour of the background in our main camera from its current default blue to a plain white:

Now, we’ll create a little visual representation of the player and the ground it will fall and walk on. Both of these objects will be shown with simple 2D sprites, so just go ahead and add two square sprites to your scene via the “GameObject > 2D Object > Sprites > Square” menu:

For both these objects, set the colour to black so we clearly see them on the white background. You should also rename them to “Player” and “Ground”. Finally, stretch the “Ground” object along its X axis so it goes all across the screen, and place it at the bottom of the camera view:

The next step is to prepare those objects for 2D physics. On the “Player” object, we’ll want both:

  • a collider to be able to receive collisions, block the square when hits something and overall interact with the other objects – we’ll use a simple “Box Collider” because the geometry of our square hero is super-simple
  • and a rigidbody to receive the auto-computed gravity and actually apply velocity on the object, which in turn will make it move

Note: both those components exist in a 2D and a 3D version, so make sure to take the 2D version for our project! 😉

The “Ground” doesn’t need to move, so it will just have a 2D collider component:

Alright! We’re now ready to code up the state machine…

Step 2: Creating the abstract parent classes

Important note: in this section, I use the term “abstract” to say “not directly instantiated”. However, the classes will not be abstract C# classes, since they will have some logic common to all derived classes 😉

In this article, we are going to work on moving our player using 2D physics. But before we actually get to this specific state machine, we are first going to define a more abstract class, that won’t be used directly but instead will be inherited by our custom state machines. Similarly, we are going to define a base class for our states – it won’t be used directly but will serve as parent class for all of our actual states.

You should think of those two classes as blueprints for the real C# objects we’ll create later on.

Implementing the base state class

Let’s start with this base state class. First, we want it to have the three entry points we discussed before: the Enter(), Update() and Exit() methods. Then, we’ll need a constructor to be able to instantiate new states.

But! The Update() phase is actually a bit too-broad for now. If you’ve every came across the Unity’s components life cycle, you might be aware that there isn’t just the usual void Update(); function we’re so used to having in our MonoBehaviors. Unity’s update loop actually discriminates between the FixedUpdate(), Update() and LateUpdate() entry points.

The FixedUpdate() is usually used for physics because it enforces a fixed time delta, i.e. all frames will have the same length, which is better for physics computations. However, here, we are going to focus on the Update() and LateUpdate() methods, because we want to make sure that we run things in the proper order.

Note: even though we’ll compute physics, we don’t care so much about having a fixed delta time as we do about the state machine not getting lost in its transitions. That’s why I’d rather insure the sequencing is correct and I chose to go for the Update() and LastUpdate() entry points.

We are going to separate our states Update() entry point in two: the UpdateLogic() and UpdatePhysics(). This will allow us to mimic Unity’s Update()/LateUpdate() distinction by calling different entry points of our current state from the state machine script.

The last bit of theory we need to properly understand the code snippet below is the notion of virtual methods. In C#, you can add the keyword virtual to your methods or properties to tell the compiler that they can be overridden by child classes. This is very useful to have some basic behaviour common to all subclasses, and then adapt it with custom behaviour in the child class. This means that contrary to abstract methods that cannot have a default logic and must be implemented in the derived classes, virtual methods can have some base logic that is then either completely replaced or simply extended.

To override a virtual method in a child class, you simply replace the virtual keyword with override in the function’s prototype.

So – here is finally the BaseState class we’ll work with:

Note: by the way, be careful – this class is a basic C# class, it doesn’t inherit from Unity’s MonoBehavior! 😉

As you can see, we have the various entry points to call from the machine state that are virtual functions, and a constructor that takes in the specific name of the state and the state machine object this state instance is a part of.

Implementing the base state machine class

We can now use this BaseState class to create our StateMachine parent class, the one that will implement a “global” FSM. Once again, remember this is not our actual player movement state machine – in particular, we don’t want it to list the exact states related to this 2D movement (like “idle” or “moving”). We just want it to be aware of the fact that it has a list of states, a current state, that it can transition from one state to another and finally that it has to continuously run the update logic of the current state.

Most of this can be coded up directly. We’ll have a currentState variable of the BaseState type; our Update() and LateUpdate() usual Unity methods will run the UpdateLogic() and UpdatePhysics() entry points of the current state; and there will be a ChangeState() function for transitioning from the current state to a new one.

There is, however, one issue. Since we’re not really listing the states for now, we don’t know what our “initial state” should be. In other words, we don’t know how to initialise the currentState variable.

The trick is to again rely on virtual methods: rather than writing down a value by hand for our initial state, what we can do is call a little method in our class, called GetInitialState(). This function won’t return anything by default (it will return a null state), but we’ll override it in our sub-state machines where we will have a proper list of states to pick from.

All this being said, here is our StateMachine class:

A last improvement we can do on this script is to use Unity’s built-in OnGUI() method to show a little label on the screen that shows the name of the current state (if it is not null):

Here, I’m using Unity’s rich text feature (with the little <color> and <font> tags inside the string) to directly customise the display of my label on the screen.

Step 3: Implementing the actual objects (machine & states)

Now that we’ve prepared our blueprints, it’s time to create a real FSM specifically tuned for 2D player movement and its “idle” and “moving” states 🙂

Like before, let’s start by creating our states. Before we do anything too complicated, we’ll make an Idle and a Moving class that will be almost identical – we’ll add the differences later on, but this will allow us to set up the state machine logic. Both those classes inherit from our brand new BaseState class.

First things first, let’s take care of the constructors so each state has the proper name:

Here, I’m simply calling the constructor of the base class, so in our case the BaseState class, and I pass it the parameters it expects: the name of the state and the instance of state machine it is a part of.

For our state machine, the basic idea is to have it inherit from the StateMachine class, add the list of possible states, make sure we initialise them properly by calling their constructor with this state machine instance as reference and finally override the GetInitialState() method to define which one is the initial state. The class is going to be called MovementSM, for “movement state machine”:

Note: I’m using Unity’s custom HideInInspector attribute to make sure the state variables don’t show up in the Inspector even though they’re public.

At that point, we’ve pretty much entangled the MovementSM with the Idle and Moving classes: any of these 3 classes can’t really work without the others. In particular, the Idle and Moving classes should always be receiving a state machine of the MovementSM-subtype. We’ll do two things to properly insure we are working with a MovementSM object:

  1. we’ll force that in the constructor so that we can only create Idle and Moving instances by passing them a MovementSM-typed state machine (remember that since MovementSM is derived from StateMachine we can pass it to the parent BaseState constructor, no worries!)
  2. for now, our parent state class, the BaseState class, provides us a reference to a generic state machine through its stateMachine variable: we’ll cast this to a MovementSM variable and store it in a private variable

Here are the updated scripts:

Lastly, let’s take care of transitioning from “idle” to “moving” state when we press the left or right arrow key (and vice-versa, if we release).

The nice thing is that Unity gives us what we need out-of-the-box: it automatically defines an input axis called “Horizontal” that contains a float value dependent on whether the user is currently pressing the left/right arrow keys or not. Basically, it works as follows:

  • the value is negative if you press the left arrow key
  • the value is positive if you press the right arrow key
  • the value is zero if you don’t press (or release) any of those keys

So, in the UpdateLogic() of our Idle class, we’ll get the value of this input axis and, if it’s not null, we’ll transition to the “moving” state:

I’m also taking into account the possible float approximation errors – that’s why I use the Unity Mathf.Epsilon built-in.

Conversely, in the Moving class, we want to check if our horizontal input is null (or at least very, very small) in which case we’ll transition back to the “idle” state:

Let’s check it’s working properly. Go back to the Unity editor and add the MovementSM script to the “Player” object.

If you run the game now, you’ll see that when you press and release the arrow keys, you indeed transition from “idle” to “moving”, and from “moving” to “idle” – the little label in the top-left corner shows that the state machine did catch the state transition:

But… you’re not actually moving while in the “moving” state! Let’s fix this 🙂

Step 4: Moving the player!

To move the player, we have to use the _horizontalInput value we computed and apply it to the player’s rigidbody velocity. So, before doing anything, let’s add a reference to this 2D rigidbody in our MovementSM class:

Don’t forget to assign it in the Inspector 🙂

While we’re at it, let’s also add a little variable – the speed we want our character to move at when we press an arrow key (you should test different values – I’ve just found that 4f is nice for me…):

Now, we can override the UpdatePhysics() entry point of our Moving class and use the value of the “Horizontal” input and the speed from our custom state machine to update the rigidbody velocity:

If you run the game again, this time, the player will actually slide on the ground whenever it is in the “moving” state!

Bonus: Changing the player colour on state change

A final thing I want to demonstrate is how state machines can actually impact various systems in your game. Here, we don’t have animations, or a sound manager to call up… but we can still interact with a component of the “Player” object: its Sprite Renderer!

What we are going to do is change the colour of the object depending on the state we’re in: for the “idle” state, we’ll stick with the basic black we currently have; but for the “moving” state, we’ll switch to red.

Let’s start by adding a public reference to this Sprite Renderer in our MovementSM class:

Again, remember to assign it in the Inspector 😉

And now, we just have to use the Enter() method of our states to have them automatically “configure” the hero properly whenever it transitions to a new state:

Tadaa! We see that our state machine now impacts another system on our player, and we could add this very easily in our states logic.

Conclusion

State machines are an effective way of adding behaviour to an entity in a readable and controlled manner. By clearly defining the inputs and the transitions, you can accurately predict the states your entity will go through, and FSMs can be coded in neatly separated files so that you decouple the various behaviours of the entity in your project.

But basic FSMs are a bit limited in terms of systems they can represent. In particular, they may create lots of code repetition if you want to handle the same input in multiple states. To avoid that, it’s better to improve the state machine to a hierarchical finite state machine

In part II of this tutorial, we’ll see how to improve our current FSM to add a new jumping state using hierarchical FSMs – so stay tuned for more!

I hope you enjoyed this quick Unity tutorial and the dual video/text versions. Feel free to react in the comments and tell me if you like this new format – and of course, go ahead and share your ideas for future topics you’d like me to make Unity tutorials on! 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *