Posted on 11 Jan 2014

Implementing a basic Finite State Machine in Unity

In this post I am going to show an example of a basic Finite State Machine written in C#, and being used in Unity. Before I get to the code let's give a quick primer on finite state machines.

What is a Finite State Machine

My basic explanation of a Finite State Machine(or Finite State Automaton) is to think of an abstract machine that has a finite set of possible states and ways to get to those states. It can only be in one state at a time, and it changes between states based on some defined criteria. States generally define the behavior of the entity the finite state machine attached to. The changing of states is known as a transition. Events can be triggered when transitions occur, and/or to cause a transition to occur.

When defining the possible transitions for a finite state machine you generally will use either a state transition table or a state diagram. These help to organize and map out how your state machine should work, which you can then translate into your language of choice.

Finite state machines are used for many things spanning many fields of study such as computer science, mathematics, electrical engineering, and more. Of particular interest to me is computer science where they are used for things such as modeling the flow of an application, AI, compilers, etc.

Let's implement this sucker!

There are many methods of implementing finite state machines. As long as you adhere to the rules of what a finite state machine is then there is really no wrong way to write it.

In this example I will be creating a state machine to control the flow of the application with a switch statement. First thing you want to do is lay out the states you want to use. States are commonly represented by enums, classes, or an array of structs. We are going to be using an enum for this example.

public enum State { Initialize, SetupNewGame, Game, GameOver, Restart, Quit }

This overall game state should be in an accessible location. I am going to be using the same code as in my previous blog post on in-game menus as a starting point. Let's put this enum in the GameManager class. We need to keep track of the current state so we'll add that to this class as well. It isn't always needed, but I like to track the previous state too so I am going to be adding that. Here is where we are so far:

public class GameManager : MonoBehaviour {
    public enum State { Initialize, SetupNewGame, Game, GameOver, Restart, Quit }

    State _state = State.Initialize;
    State _prevState;

#region Basic Getters/Setters
    public State CurrentState {
        get { return _state; } 
    }

    public State PrevState {
        get { return _prevState; }
    }
#endregion

    public void SetState(State newState) {
        _prevState = _state;
        _state = newState;
        PrintState();
    }

Alright so pretty straightforward so far! We don't neccessarily need to set a default given how the code is structured, but it's generally a good idea. Notice there are no setters in the properties because we use SetState for that.

Here is a simple little state diagram showing how we want the flow of our application to go:

FSM Example 1

Now let's take a look at how this can be represented in code!

void Awake() {
    // Do any general system initialization stuff here.

    SetState(State.SetupNewGame);
}

// NOTE: Async version of Start.
IEnumerator Start() {
    while(true) {
        switch(_state) {
            case State.Initialize:
                break;
            case State.SetupNewGame:
                SetupNewGame();
                break;
            case State.Game:
                if(Input.GetKeyDown(KeyCode.G)) {
                    SetState(State.GameOver);
                }

                break;
            case State.GameOver:
                break;
            case State.Restart:
                if(Input.GetKeyDown(KeyCode.R)) {
                    SetState(State.SetupNewGame);
                }
                if(Input.GetKeyDown(KeyCode.Q)) {
                    SetState(State.Quit);
                }
                break;
            case State.Quit:
                break;
        }
        yield return null;
    }
}

// This coroutine is really just kinda simulating some sort of inner game logic loop.
IEnumerator InitializeGameLogicStuff() {
    yield return new WaitForSeconds(1);
    while(true) {
        yield return new WaitForSeconds(5);

        if(_state == State.GameOver) {
            SetState(State.Restart);
            break;
        }
    }
}

void SetupNewGame() {
    StartCoroutine(InitializeGameLogicStuff());
    SetState(State.Game);
}

That is a larger block of code than the others, however it isn't too complicated. Notice how the Start method is the asynchronous version. We use this to contain our main game loop. The comments should explain the rest pretty well.

Sub-state machines can be useful!

Now something to think about are sub-state machines. Sure you could always just add all states together in the same enum however that could get pretty cluttered in a larger project. A good example would be State.Game. Let's add a couple sub-states to that which are controlled by it's own state machine.

public class GameManager : MonoBehaviour 
    ...
    public enum GameState { Idle, InGameMenu }

    InGameMenu igm;

    GameState _gameState;
    GameState _prevGameState;

#region Basic Getters/Setters
    ...

    public GameState CurrentGameState {
        get { return _gameState; }
    }

    public GameState PrevGameState {
        get { return _prevGameState; }
    }
#endregion

    void Awake() {

        igm = GetComponent<InGameMenu>();

        ...
    }

    IEnumerator Start() {
        while(true) {
            switch(_state) {
                ...
                case State.Game:
                    if(Input.GetKeyDown(KeyCode.G)) {
                        SetState(State.GameOver);
                    }
                    if(Input.GetKeyDown(KeyCode.M)) {
                        igm.enabled = !igm.enabled;
                    }

                    InGame();
                    break;
                ...
        }
    }

    void InGame() {
        switch(_gameState) {
            case GameState.Idle:
                break;
            case GameState.InGameMenu:
                break;
        }
    }

    public void SetGameState(GameState newState) {
        _prevGameState = _gameState;
        _gameState = newState;
        PrintState();
    }

    ...

So you'll see there is nothing too crazy here. We are adding a new set of states named GameState and member methods/variables to set and track that state. There is also a new switch statement in the InGame method to handle that state. In each of the methods to set the states you may have noticed PrintState which is a lil helper method in GameManager that just prints the current states to the console. Here that is:

void PrintState() {
    Debug.Log("main state: " + _state.ToString() +
              " | game state: " + _gameState.ToString());
}

That should get you started with creating and using a basic finite state machine. There are many ways you can build upon this to make it more extensible. In a future post I will go into one of those ways to go about doing that. You can check out the repository for this project here, and it is also listed on my projects page.