Implementing a Finite State Machine Using C# in Unity – Part 1

Share the Post

In this tutorial, we will learn about Finite State Machines and implement a Finite State Machine using C# in Unity. We will then illustrate the concept by applying the implemented FSM to two different scenarios.

The tutorial is divided into three parts.

Part 1 introduces and implements a generic Finite State Machine in C#.


Part 2 uses the Finite State Machine created in part 1 and applies to a Unity project in a simple straightforward UI implementation of a Splash Screen. See a video of the example implementation.


Part 3 uses the same Finite State Machine and applies to a complex Unity project which handles multiple animation states of a 3D animated character. We will target the build for this implementation for touch screen controlled devices such as Android or iOS (coming soon). See a video of the example implementation.



Read Also: Solving 8 puzzle problem using A* star search

Download the 8 Puzzle Unlimited App from Google Play.


Part 1 – Implementing a Finite State Machine Using C#

In Part 1 we will have a brief introduction to Finite State Machines and then we will implement a generic FSM class that can be reused across many projects. To make use of this tutorial to the fullest you will need to have a basic understanding of Object-Oriented programming and inheritance.

Introduction

Finite State Machine (or FSM in short) is a computational pattern that is used to define and model state behaviour of a system. It is abstract in nature. 

Read Also: Implementing a Command Design Pattern in Unity

Read Also: Solving the 8 puzzle problem using A* (star) algorithm

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 as events). The process of changing from one state to another is called a transition.

https://www.ntu.edu.sg/home/ehchua/programming/java/J8d_Game_Framework.html

Thus, an FSM consists of a set of states and a set of transitions between pairs of states. 

A transition is labelled as condition/action: a condition that causes the transition to happen and an action that is performed when the transition happens. 

Acceptor FSM: parsing the string “nice”.

Source Wikipedia

When Would You Use a Finite State Machine

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 can be found in computer games development, UI implementation, online ordering system, mobile app development and so on.

How to Implement an FSM Using C#

There are a number of 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, a class-based approach that will be reusable across multiple projects. So, let’s get started.

Do note that this tutorial will require you to have 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 in any namespace you like.

namespace Patterns
{
    public class State
    {
    }
 
    public class FSM
    {
    }
}

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 FSM class we probably won’t need any arguments. At least, not for now. We will proceed with a default constructor.

Below shows the default constructor implementation of the FSM class.

    public class FSM
    {
        public FSM()
        {
        }
    }

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 an 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 set of states. 

Thus, we will need a variable to store the collection of States. This will represent the set of states. And then we will need a variable to store the current state that the FSM is in.

    public class FSM
    {
        //!A container object to store the set of states.
        /*!We will use a Dictionary container class to 
         * store the key, value pair of the set of states.
         * The key will be a unique ID for an instantiate
         * application-specific State object.
         */
        protected Dictionary<int, State> m_states;
 
        //!The current state that the FSM is in right now.
        protected State m_currentState;
 
        public FSM()
        {
        }
    }

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 holds the current state of the FSM.

Why did we use a Dictionary?

Well, actually 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 choose to use a different implementation. Let’s move on.

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 states.  

    public class FSM
    {
        ***
        ***
 
        public void Add(int key, State state)
        {
            m_states.Add(key, state);
        }
    }

The method shown above is self explanatory. 

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];
        }
    }

Do 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.

Set the current State

Now perhaps the most important 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 invalid (or null) and the second code path is when the previous current state is valid. 

    public class FSM
    {
        ***
        ***
 
        public void SetCurrentState(State state)
        {
            if(m_currentState != null)
            {
                // This from theory is the second code path. 
                // The first code path is if 
                // m_currentState == null in which case
                // nothing happens. 
            }
            m_currentState = state;
        }
 
    }

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 invalid then what happens? Can we still simply 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 is exited and a new state is entered. How do we then implement this into our current code?

The answer is simple. We 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. We then call these two methods whenever there is a change in the state.

    public class State
    {
        /*!Virtual method for entry to the state.
         * This method is called whenever this 
         * state is entered. Derived classes
         * must implemented this method and 
         * handle appropriately.
         */
        public virtual void Enter() { }
 
        /*!Virtual method for exit from the state.
         * This method is called whenever this 
         * state is exited. Derived classes
         * must implemented this method and 
         * handle appropriately.
         */
        public virtual void Exit() { }
    }
    
    public class FSM
    {
        ***
        ***        
 
        public void SetCurrentState(State state)
        {
            if(m_currentState != null)
            {
                /* This from theory is the second code path. 
                 * The first code path is if the 
                 * m_currentState == null in which case
                 * nothing happens. 
                 * If the previous current state is
                 * valid then we will call the 
                 * Exit method of the previous
                 * current state
                 */
                m_currentState.Exit();
            }
 
            m_currentState = state;
 
            if(m_currentState != null)
            {
                /* We are now entering into a new State
                 * So we will call the Enter method
                 * of the new current state.
                 */
                m_currentState.Enter();
            }
        }
    }

We are almost done with the implementation. 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
    {
        ***
        *** 

        /*!Virtual method that will be 
         * called in every Update call from Unity.
         * The call will be routed via the
         * FSM through the current state.
         */
        public virtual void Update() { }
 
        /*!Virtual method that will be 
         * called in every FixedUpdate call from 
         * Unity. The call will be routed via the
         * FSM through the current state.
         */
        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();
            }
        }
    }

This completes our implementation of an abstract FSM in C#. Of course, we can do a lot of improvement on it. One such improvement could be to add a variable that stores the ID of the state and a method that returns the ID of the State. 

Completed Source Code

using System.Collections;
using System.Collections.Generic;

namespace Patterns
{
    public class State
    {
        protected FSM m_fsm;
        /* The constructor of the State class
         * will require the parent FSM.
         * So we create a constructor 
         * with an instance of the FSM
         */
        public State(FSM fsm)
        {
            m_fsm = fsm;
        }

        /*!Virtual method for entry to the state.
         * This method is called whenever this 
         * state is entered. Derived classes
         * must implement this method and 
         * handle appropriately.
         */
        public virtual void Enter() { }

        /*!Virtual method for exit from the state.
         * This method is called whenever this 
         * state is exited. Derived classes
         * must implement this method and 
         * handle appropriately.
         */
        public virtual void Exit() { }

        /*!Virtual method that will be 
         * called in every Update call from Unity.
         * The call will be routed via the
         * FSM through the current state.
         */
        public virtual void Update() { }

        /*!Virtual method that will be 
         * called in every FixedUpdate call from 
         * Unity. The call will be routed via the
         * FSM through the current state.
         */
        public virtual void FixedUpdate() { }
    }

    public class FSM
    {
        //!A container object to store the set of states.
        /*!We will use a Dictionary container class to 
         * store the key, value pair of the set of states.
         * The key will be a unique ID for an instantiate
         * application-specific State object.
         */
        protected Dictionary<int, State> m_states = new Dictionary<int, State>();

        //!The current state that the FSM is in right now.
        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)
            {
                /* This from theory is the second code path. 
                 * The first code path is if the 
                 * m_currentState == null in which case
                 * nothing happens. 
                 * If the previous current state is
                 * valid then we will call the 
                 * Exit method of the previous
                 * current state
                 */
                m_currentState.Exit();
            }

            m_currentState = state;

            if(m_currentState != null)
            {
                /* We are now entering into a new State
                 * So we will call the Enter method
                 * of the new current state.
                 */
                m_currentState.Enter();
            }
        }

        public void Update()
        {
            if(m_currentState != null)
            {
                m_currentState.Update();
            }
        }

        public void FixedUpdate()
        {
            if (m_currentState != null)
            {
                m_currentState.FixedUpdate();
            }
        }
    }
}

Conclusion

In this section, we have implemented a generic reusable Finite State Machine that we will reuse/override based on what is required by our application domain down the stream.

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.

References

  1. https://en.wikipedia.org/wiki/Finite-state_machine
  2. https://gameprogrammingpatterns.com/state.html
  3. https://gamedevelopment.tutsplus.com/tutorials/finite-state-machines-theory-and-implementation–gamedev-11867

Leave a Reply

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