Skip to content

Quick Start

Niklas Lindblad edited this page Dec 12, 2025 · 12 revisions

Getting Started

For a step-by-step guide how to build your first state machine, see Creating your first machine.

Adding the package to your Unity project

Add it in package manager with github url: https://github.com/Ryxali/FSMForUnity.git?path=/Packages/com.ryxali.fsmforunity

Configuring Preferences

In Unity preferences, you can personalize your settings in the FSM For Unity tab.

Using FSMForUnity in your code

Using the API is fairly straightforward, and can be broken down in two parts:

Before we get there though, note that the runtime API sits under the FSMForUnity namespace, so don't forget using FSMForUnity;!

Building the machine

First you utilize a builder to construct a machine. The builder is the interface to define which states exist in the machine, and how those states are connected.

// Could be in Awake, Start, or any other part of your code.
FSMMachine MyConstructor()
{
    var builder = FSMMachine.Build();

    var idle = builder.AddState("Idle", new IdleFSMState());
    var patrolling = builder.AddState("Patrolling", new PatrollingFSMState());
    var chasing = builder.AddState("Chasing", new ChasingFSMState());

    builder.AddLambdaTransition("Patrol", () => idleTime > 3f, idle, chasing);
    builder.AddLambdaTransition("Enemy Spotted", () => chaseTarget != null, idle, chasing);
    builder.AddLambdaTransition("Enemy Spotted", () => chaseTarget != null, patrolling, chasing);
    builder.AddLambdaTransition("Enemy Lost", () => chaseTarget == null, chasing, idle);

    return builder.Complete();
}

Running the machine

Second you execute the machine. Usually you do this in Unity's Awake, OnEnable, OnDisable, OnDestroy events, but this choice is left to you and your use case.

FSMMachine fsm = MyConstructor();

// The full life cycle of the machine
fsm.Enable();
fsm.Update(Time.deltaTime);
fsm.Disable();
fsm.Destroy();

You can find a more detailed walk through over at Creating your first machine.

Creating your first machine

In this sample, we'll create a simple state machine. It will alternate between two different states, staying a fixed amount of time in each state. For this, we'll create a new script to act as our host for this machine.

This quick start assumes a basic understanding of Unity and MonoBehaviours.

We'll go through this step by step in this tutorial, with some extra musings sprinkled in. You can find the full script at the end of this tutorial.

The foundation

For the machine to function, it must be wired into the Unity lifecycle. We do this by:

  1. Building the machine in the script's Awake function.
  2. Enabling the machine in the script's OnEnable function.
  3. Disabling the machine in the script's OnDisable function.
  4. Updating the machine in the script's Update function.
  5. Destroying the machine in the script's OnDestroy function.

AlternatingMachine.cs

using UnityEngine;
using FSMForUnity;

public class AlternatingMachine : MonoBehaviour
{
    private FSMMachine fsm;

    private void Awake()
    {
        // Start building the machine
        var builder = FSMMachine.Build();

        // Finish building the machine
        fsm = builder.Complete();
    }

    private void OnEnable()
    {
        fsm.Enable();
    }

    private void OnDisable()
    {
        fsm.Disable();
    }

    private void Update()
    {
        fsm.Update(Time.deltaTime);
    }

    private void OnDestroy()
    {
        fsm.Destroy();
        fsm = null;
    }
}

Now you have an empty machine that does nothing, but it runs!

"This seems like a lot of boilerplate!"

These are the steps required for the machine to mirror Unity's lifecycle of objects, but it's your machine. It is up to you when you want to invoke the lifecycle events of the machine. Just remember the machine has to be enabled before it can be updated, and it should be destroyed when its' lifecycle is supposed to end.

Managing the lifecycle is left to you, the developer. If you wish to wrap this into an abstract class, or utilize some other construct to ease on the writing of this boilerplate, that is your call to make.

What happens if I forget to destroy a machine?

Undestroyed machines will still be visible in the debugger, taking up space and resources and introducing confusion as to what machines are actually relevant. This does not happen in Release builds.

Machines left undestroyed will also not invoke the Destroy method for each of its' underlying states. As such cleanup code and other functionality that you've implemented will not be invoked unless you destroy the machine.

Add our states

Let's add our two states! We'll imaginatively call them stateA and stateB. For this sample, we'll add them as lambda states. This means that we map the states as function calls on our script.

AlternatingMachine.cs

private void Awake()
{
    var builder = FSMMachine.Build();
    
    // Add our states, stateA and stateB.
    var stateA = builder.AddLambdaState(enter: A_Enter, update: A_Update);
    var stateB = builder.AddLambdaState(enter: B_Enter, update: B_Update);

    fsm = builder.Complete();
}

public void A_Enter()
{
    Debug.Log("A!");
}
public void A_Update(float delta) {}
public void B_Enter()
{
    Debug.Log("B!");
}
public void B_Update(float delta) {}

If we run this we can see "A" being printed to console. We can take the to view this machine in the debugger as well. Open Window/Analysis/FSM Debugger and select the machine in the left column of the window. You can see the two states aren't connected yet. Our stateB (named state 2 in the graph) being found way down in the graph.

As stateA was the first state to be added it's the default state the machine starts in. We don't have a path to get to stateB yet. We'll add that next!

AddState vs. AddLambdaState

While AddState is the core function for adding new states to a machine, there exists a number of extension methods for common ways to add specialized kinds of states as well. The lambda state is one such state. Instead of implementing a defined class for the state, one provides methods for the different state methods directly. It's especially useful when you want to compact multiple states within a single class, allowing them all to share and act on the same data. It allows you to move quick at the expense of the file becoming large and obtuse the more states you add.

Add our transitions

With our states done, we can implement our transitions that will go back and forth between our two states. In this sample, we'll implement this using the built-in TriggeredFSMTransition.

AlternatingMachine.cs

// our transition rule
private TriggeredFSMTransition transition = new TriggeredFSMTransition();

private void Awake()
{
    var builder = FSMMachine.Build();
    
    // Add our states, stateA and stateB.
    var stateA = builder.AddLambdaState(enter: A_Enter, update: A_Update);
    var stateB = builder.AddLambdaState(enter: B_Enter, update: B_Update);
    
    // Add a transition, one going from stateA to stateB, and another from stateB to stateA.
    builder.AddTransition(transition, stateA, stateB);
    builder.AddTransition(transition, stateB, stateA);

    fsm = builder.Complete();
}

If we run this we still only see "A" being printed to console. Checking again in the debugger we can see that the states each have two connections, leading around in a cycle.

We have nothing triggering the transition yet, let's get to that next!

TriggeredFSMTransition

This is one of the built-in transitions part of the package. Once triggered, the transition can only be passed through once. Think of it as a door that you can unlock, but when unlocked it will only let one person through before closing and locking again.

"Aren't we using the same transition twice?"

A transition may map between multiple sets of states. The transition is only the set of rules that allows a transition to happen through it. Only the machine knows the context of between which states this rule should apply to.

Building the logic

We now have a machine with two states that does nothing, with two transitions that are never triggered. Let's implement the logic of alternate our states. We do this using a timer variable we'll keep on our script.

AlternatingMachine.cs

private TriggeredFSMTransition transition = new TriggeredFSMTransition();
// our timer
private float timer;

...

private void A_Enter()
{
    Debug.Log("A!");
    // reset our timer
    timer = 0f;
}
private void A_Update(float delta)
{
    // increment our timer
    timer += delta;
    if(timer > 4f) // trigger after 4 seconds have elapsed
    {
        transition.Trigger();
    }
}
private void B_Enter()
{
    Debug.Log("B!");
    // reset our timer
    timer = 0f;
}
private void B_Update(float delta)
{
    if(timer > 8f) // trigger after 8 seconds have elapsed
    {
        transition.Trigger();
    }
}

If we run this we now get it printing first "A" to the console, then "B", then back to "A", etc.

If you check the debugger you can see it alternate between the states there as well!

The finished code

With this you have learned the fundamentals on how to build a state machine with FSMForUnity; adding states, then transitions, then implementing the logic for these states and transitions. You will find the full code for this sample below. It can serve as a template for building your own machines, or just a point of reference as you fashion your own implementation. In other sections, we'll get more in depth about the various components of FSMForUnity, including how to build for optimized scenarios and ease of debugging.

AlternatingMachine.cs

using UnityEngine;
using FSMForUnity;

public class AlternatingMachine : MonoBehaviour
{
    // our transition rule
    private TriggeredFSMTransition transition = new TriggeredFSMTransition();
    // our timer
    private float timer;

    private FSMMachine fsm;

    public void Awake()
    {
        // Start building the machine
        var builder = FSMMachine.Build();

        // Add our states, stateA and stateB.
        var stateA = builder.AddLambdaState(enter: A_Enter, update: A_Update);
        var stateB = builder.AddLambdaState(enter: B_Enter, update: B_Update);

        // Add a transition, one going from stateA to stateB, and another from stateB to stateA.
        builder.AddTransition(transition, stateA, stateB);
        builder.AddTransition(transition, stateB, stateA);

        // Finish building the machine
        fsm = builder.Complete();
    }

    private void A_Enter()
    {
        Debug.Log("A!");
        // reset our timer
        timer = 0f;
    }

    private void A_Update(float delta)
    {
        // increment our timer
        timer += delta;
        if (timer > 4f) // trigger after 4 seconds have elapsed
        {
            transition.Trigger();
        }
    }

    private void B_Enter()
    {
        Debug.Log("B!");
        // reset our timer
        timer = 0f;
    }

    private void B_Update(float delta)
    {
        // increment our timer
        timer += delta;
        if (timer > 8f) // trigger after 8 seconds have elapsed
        {
            transition.Trigger();
        }
    }

    private void OnEnable()
    {
        fsm.Enable();
    }

    private void OnDisable()
    {
        fsm.Disable();
    }

    private void Update()
    {
        fsm.Update(Time.deltaTime);
    }

    private void OnDestroy()
    {
        fsm.Destroy();
        fsm = null;
    }
}