This tutorial will teach Finite State Machines (FSM) and implement a Finite State Machine using C# in Unity. We will then illustrate the concept by applying the implemented FSM in multiple scenarios.
Implementing a Finite State Machine Using C#
This is Part 1 of the tutorial, where we will use a class and object-based approach to create an FSM.
This section will briefly introduce Finite State Machines, and then we will implement a generic FSM class that we can reuse across many projects. To use this tutorial to the fullest, you will need to have a basic understanding of object-oriented programming and inheritance.
Read the C++ tutorial on https://faramira.com/reusable-finite-state-machine-using-cpp/.
Read Also: Pathfinding Using C# in Unity In this four-part series of tutorials, I go in-depth to solving the pathfinding problem using C# in Unity.
Introduction
Finite State Machine (or FSM in short) is a computational pattern that defines and models state behaviour. It is abstract.
At any given time, an FSM can exist in only one state out of a set of a possible number of states. This state can change to another in response to some inputs (sometimes called events). The process of switching from one state to another is called a transition.
Thus, an FSM consists of states and a set of transitions between pairs of states.
A transition is labelled as condition/action, which causes the transition to change; and occurs when the transition changes.
Source Wikipedia
When Would You Use a Finite State Machine
We typically use a finite state machine to represent a real or logical object that can exist in a finite number of states and progresses from one state to the next according to a fixed set of rules.
Examples of the real use of FSM exist in computer games development, UI implementation, online ordering system, mobile app development, etc.
How to Implement an FSM Using C#
There are several ways you can implement a finite state machine using C#. The easiest and fastest way probably is to use the enumerator type and the switch-case statement. However, in this tutorial, we are not going to do that. Instead, we will use a slightly sophisticated, more robust, class-based approach that will be reusable across multiple projects. So, let’s get started.
This tutorial requires a basic understanding of object-oriented programming and inheritance.
The Classes
For organization purposes, let’s put the generic reusable codes in the Patterns namespace. You can put it in any namespace you like.
namespace Patterns
{
public class State
{
}
public class FSM
{
}
}
Code language: C# (cs)
The above shows the basic structure of the State and the FSM class. Both of them are empty. We will implement as we move on.
The Constructors
First of all, what do we need? We will need constructors for the FSM class and the State class. To construct the FSM class, we probably won’t need any arguments. At least, not for now. We will proceed with a default constructor.
Below is the default constructor implementation of the FSM class.
public class FSM
{
public FSM()
{
}
}
Code language: C# (cs)
However, for the State class, we might need access to the parent FSM instance. So the constructor of the State class will have an input parameter of the FSM instance.
The Variables
Once we have implemented the default constructor, we move on to implement the core functionalities of the FSM. As described in the previous sections, an FSM consists of a set of states, and at any given time, an FSM can exist in only one State out of these possible sets of states.
Thus, we will need a variable to store the collection of states. This collection will represent a set of states. And then, we will need a variable to keep the current state of the FSM.
public class FSM
{
protected Dictionary<int, State> m_states;
protected State m_currentState;
public FSM()
{
}
}
Code language: C# (cs)
In the above implementation, we have two variables. One is m_states that holds a key-value pair set (dictionary) of State objects. And the other is m_currentState that contains the current state of the FSM.
Why did we use a Dictionary?
Well, we could have used an Array, a List or any other container class. I chose a Dictionary because it will be easier to add and extract a specific State from the set of states using a key. You might decide to use a different implementation.
Add State to the FSM
In the previous section, we created the variable that stores the set of states. Now we will create a method that will fill that set by adding state.
public class FSM
{
***
***
public void Add(int key, State state)
{
m_states.Add(key, state);
}
}
Code language: C# (cs)
The method Add shown above takes in an integer as the key and the State as the state. It then adds this pair to the dictionary.
Get State from the FSM
A method that returns a State based on the key.
public class FSM
{
***
***
public State GetState(int key)
{
return m_states[key];
}
}
Code language: C# (cs)
Note that the method will fail if a State of the same key has not been added previously to the FSM. This method is a convenient function. We are not doing exception handling for now.
Set the current State
Now perhaps the most critical function of the FSM, SetCurrentState. This method will set the current state of the FSM.
What happens when we set a state to the current State? There are two possible code paths to it. The first code path is when the previous-current State is valid, and the second code path is when the previous-current state is invalid (or null).
public class FSM
{
***
***
public void SetCurrentState(State state)
{
if(m_currentState != null)
{
}
m_currentState = state;
}
}
Code language: C# (cs)
The above code implements the SetCurrentState method. If the previous-current State of FSM is invalid, then the implementation directly sets the State to the m_currentState. However, if the previous-current State was not null, then what happens? Can we still overwrite the previous-current state with the new current state?
The answer is probably not. We might want to implement specific functions whenever a state exits and a new state enters. How do we then implement this into our current code?
Enter and Exit
The answer is simple. Create two virtual methods in the State class called Enter and Exit. The base State class implements nothing for both the Enter and Exit methods and instead relies on the application to create concrete implementations of the base State class. Then call these two methods whenever there is a change in the State.
public class State
{
public virtual void Enter() { }
public virtual void Exit() { }
}
public class FSM
{
***
***
public void SetCurrentState(State state)
{
if(m_currentState != null)
{
m_currentState.Exit();
}
m_currentState = state;
if(m_currentState != null)
{
m_currentState.Enter();
}
}
}
Code language: C# (cs)
We will finally put the Unity context to the FSM and the State class by adding two methods called Update and FixedUpdate. These two methods we will call from Unity Monobehavior for every Update and FixedUpdate.
public class State
{
***
***
public virtual void Update() { }
public virtual void FixedUpdate() { }
}
public class FSM
{
***
***
public void Update()
{
if(m_currentState != null)
{
m_currentState.Update();
}
}
public void FixedUpdate()
{
if (m_currentState != null)
{
m_currentState.FixedUpdate();
}
}
}
Code language: C# (cs)
This completes our implementation of an abstract FSM in C#. Read Generic Finite State Machine Using C# to make the above finite state machine implementation generic.
Completed Source Code
using System.Collections;
using System.Collections.Generic;
namespace Patterns
{
public class State
{
protected FSM m_fsm;
public State(FSM fsm)
{
m_fsm = fsm;
}
public virtual void Enter() { }
public virtual void Exit() { }
public virtual void Update() { }
public virtual void FixedUpdate() { }
}
public class FSM
{
protected Dictionary<int, State> m_states = new Dictionary<int, State>();
protected State m_currentState;
public FSM()
{
}
public void Add(int key, State state)
{
m_states.Add(key, state);
}
public State GetState(int key)
{
return m_states[key];
}
public void SetCurrentState(State state)
{
if(m_currentState != null)
{
m_currentState.Exit();
}
m_currentState = state;
if(m_currentState != null)
{
m_currentState.Enter();
}
}
public void Update()
{
if(m_currentState != null)
{
m_currentState.Update();
}
}
public void FixedUpdate()
{
if (m_currentState != null)
{
m_currentState.FixedUpdate();
}
}
}
}
Code language: C# (cs)
Conclusion
This section has implemented a generic reusable Finite State Machine that we can reuse/override and apply based on what is required by our application domain down the stream.
Read My Other Tutorials
- Runtime Depth Sorting of Sprites in a Layer
- Implement Constant Size Sprite in Unity2D
- Implement Camera Pan and Zoom Controls in Unity2D
- Implement Drag and Drop Item in Unity
- Graph-Based Pathfinding Using C# in Unity
- 2D Grid-Based Pathfinding Using C# and Unity
- 8-Puzzle Problem Using A* in C# and Unity
- Create a Jigsaw Puzzle Game in Unity
- Implement a Generic Pathfinder in Unity using C#
- Create a Jigsaw Puzzle Game in Unity
- Generic Finite State Machine Using C#
- Implement Bezier Curve using C# in Unity
- Create a Jigsaw Tile from an Existing Image
- Create a Jigsaw Board from an Existing Image
- Solving 8 puzzle problem using A* star search
- A Configurable Third-Person Camera in Unity
- Player Controls With Finite State Machine Using C# in Unity
- Finite State Machine Using C# Delegates in Unity
- Enemy Behaviour With Finite State Machine Using C# Delegates in Unity
- Augmented Reality – Fire Effect using Vuforia and Unity
- Implementing a Finite State Machine Using C# in Unity
- Solving 8 puzzle problem using A* star search in C++
- What Are C# Delegates And How To Use Them
- How to Generate Mazes Using Depth-First Algorithm
Proceed to Part 2 of this tutorial to see a demo implementation of the FSM in building a Splash Screen in Unity. See the video below to see what we will create in Part 2.
Proceed to Part 3, where we use the FSM and apply it to a complex Unity project which handles multiple animation states of a 3D animated character to create Player Controls. See a video of the example implementation.
Proceed to Part 4, where we will use delegates to create a Finite State Machine. Thereafter we will demonstrate the use of the Finite State Machine by creating a simple key press based application in Unity.
Proceed to Part 5, where we will use the delegate based FSM created in Part 4 to create an enemy NPC behaviour that handles multiple animation states of a 3D animated character.
Read Also: Solving 8 puzzle problems using A* star search
Download the 8 Puzzle Unlimited App from Google Play.
References
- https://en.wikipedia.org/wiki/Finite-state_machine
- https://gameprogrammingpatterns.com/state.html
- https://gamedevelopment.tutsplus.com/tutorials/finite-state-machines-theory-and-implementation–gamedev-11867
A committed and optimistic professional who brings passion and enthusiasm to help motivate, guide and mentor young students into their transition to the Industry and reshape their careers for a fulfilling future. The past is something that you cannot undo. The future is something that you can build.
I enjoy coding, developing games and writing tutorials. Visit my GitHub to see the projects I am working on right now.
Educator | Developer | Mentor
How come fixedupdate in FSM never runs?
Hi. For FixedUpdate to run you will need to implement a FixedUpdate method in the FSM class and then call the FixedUpdate of the State (just like Update).
You will then call the mFSM.FixedUpdate() from your main script where you use the FSM.
Do let me know if this is clear to you. If not then I will write the code and send to you.
This is great, thanks! What’s the license assigned to the source code?
I did not put any license to it. Anyone can use the codes freely as I am just trying to educate and help others understand the concepts. Thank you for your comment.
missed these two in the walk through portion, looking for “Object reference not set to an instance of object”
m_fsm = fsm;
m_states = new Dictionary();
Please find the code from GitHub: https://github.com/shamim-akhtar/fsm-generic
This implementation is a modified version of the original FSM. Do let me know if you still have any problems.