Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
U

UnityHFSM

> 编程语言
Open source

A fast, tried-and-tested hierarchical finite state machine library for Unity, designed to be easy to use yet powerful without compromising performance.

1.6K stars0 likes1 views
WebsiteGitHub

About

A fast, tried-and-tested hierarchical finite state machine library for Unity, designed to be easy to use yet powerful without compromising performance.

A simple yet powerful hierarchical finite state machine for the Unity game engine. It is scalable and customisable by being class-based, but also supports functions (lambdas) for rapid prototyping.

Thanks to overloading, it minimises boilerplate code while still supporting generics.

It has a special focus on the temporal aspects of state transitions, making it ideal for timing and synchronisation sensitive problems.


Why use UnityHFSM?

  • State machines are an amazingly easy way to write and organise game logic. (As soon as you have states, e.g. Walk, Run, Sneak, Jump, you can use a state machine)

  • It's easy and straightforward to use

  • It helps you tame complex behaviour (e.g. weapon handling -> cooling, ammo, reload, fire) or write AI for NPCs

  • Helps you write self documenting code, that is maintainable and readable

  • Reduces the boilerplate code required to write a state machine

  • UnityHFSM is lightweight and efficient, making it perfect for solving small and big problems

  • It is especially designed for Unity, and supports coroutines, which would otherwise be difficult to integrate in a state machine

  • No GC Allocations for state changes / updates / ... after setting up the state machine (-> No unwanted GC related lag spikes because of the state machine)

  • The code is well documented

  • It is not a component (MonoBehaviour) and therefore has a low overhead

  • By being hierarchical, it can reduce the amount of duplicate code between states


In the wiki:

  • Full overview over features

  • How to use UnityHFSM outside of Unity

Table of contents:

  • Fast prototyping

  • Hierarchical features

  • Timing of state changes

  • Hierarchical timing

  • Multiple state change patterns

  • Control flow of OnLogic

  • Unity coroutines

  • Scalable (class-based)

  • Generics

  • Debugging Tips

Installation

Unity Package

To get started, download the latest version of UnityHFSM from the Releases page. Simply extract the zip file and put the folder anywhere in your Assets folder. Et voilà, you're ready to go!

UPM Package

Add from OpenUPM | via scoped registry

To add OpenUPM to your project:

  • Open Edit/Project Settings/Package Manager

  • Add a new Scoped Registry:

    Name: OpenUPM
    URL:  https://package.openupm.com/
    Scope(s): com.inspiaaa.unityhfsm
  • Click Save

  • Open Package Manager

  • Select My Registries in dropdown top left

  • Select UnityHFSM and click Install

Add from GitHub | no updates through PackMan

You can also add it directly from GitHub on Unity 2019.4+. Note that you won't be able to receive updates through Package Manager this way, you'll have to update manually.

  • Open Package Manager (Window > Package Manager)
  • Click +
  • Select Add from Git URL
  • Paste
    • https://github.com/Inspiaaa/UnityHFSM.git#upm for the latest stable release (recommended)
    • https://github.com/Inspiaaa/UnityHFSM.git#release for the development version
    • https://github.com/Inspiaaa/UnityHFSM.git#v1.8.0 for a specific version (v1.8.0 here)
  • Click Add
  • Tip: If you're using VSCode, and you're not getting any IntelliSense, you may have to regenerate the .csproj project files (Edit > Preferences > External Tools > Regenerate project files)

Example

Simple State Machine

Here's a simple state machine for an enemy spy in a game.

As you can see, the enemy will try to stay outside of the player's viewing range while extracting intel. When the player goes too far away, it will follow the player again.

The Idea

  • Create the state machine:

    csharp
    fsm = new StateMachine();
  • Add states: Each state is represented by a StateBase object. You can either use one of the built-in state classes (e.g. the State class) to define the state's logic or write a custom class that inherits from StateBase.

    csharp
    fsm.AddState(
        name,
        new State(
            onEnter,
            onLogic,
            onExit
        )
    );
  • Add transitions: Transitions can be defined using TransitionBase objects. They determine when and under which conditions the state machine should switch to another state. As with the states, the simplest option is to use one of the builtin transition types (e.g. the Transition class). If you instead choose to create a custom transition class by inheriting from TransitionBase, see the class-based architecture section for more information.

    csharp
    fsm.AddTransition( new Transition(
        from,
        to,
        condition
    ));
  • Initialize the state machine

    csharp
    fsm.SetStartState(id);
    fsm.Init();
  • Run the state machine:

    csharp
    void Update() {
        fsm.OnLogic()
    }

The Implementation

Creating the state machine

csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityHFSM;  // Import the required classes for the state machine.

public class EnemyController : MonoBehaviour
{
    private StateMachine fsm;

    public float playerScanningRange = 4f;
    public float ownScanningRange = 6f;

    void Start()
    {
        fsm = new StateMachine();
    }
}

Adding states

To be able to define the states' logic concisely, we'll need to create some helper methods and properties first. Their implementation is just an example and may differ for your scene setup.

csharp
Vector2 PlayerPosition => PlayerController.Instance.transform.position;

float DistanceToPlayer => Vector2.Distance(PlayerPosition, transform.position);

void MoveTowardsPlayer(float speed) {
    transform.position = Vector2.MoveTowards(
        transform.position,
        PlayerPosition,
        speed * Time.deltaTime
    );
}

Next, we can define the states in the Start method:

csharp
void Start()
{
    fsm = new StateMachine();

    // Empty state without any logic.
    fsm.AddState("ExtractIntel");

    fsm.AddState("FollowPlayer", new State(
        onLogic: state => MoveTowardsPlayer(1)
    ));

    fsm.AddState("FleeFromPlayer", new State(
        onLogic: state => MoveTowardsPlayer(-1)
    ));

    // This configures the entry point of the state machine.
    fsm.SetStartState("FollowPlayer");
}

Notice the fsm.AddState("ExtractIntel") call. Interestingly, we don't need to pass in a state object here. This is due to one of the many "shortcut" methods that UnityHFSM provides. These are meant to reduce the amount of boilerplate code required for common operations, such as adding blank states. The above line is equivalent to writing:

csharp
fsm.AddState("ExtractIntel", new StateBase<string>(needsExitTime: false));

Furthermore, we can actually shorten the other state definitions even more by using shortcut methods. We can for example write the FollowPlayer state in a more concise way:

csharp
fsm.AddState("FollowPlayer", onLogic: state => MoveTowardsPlayer(1));

Although this example is using lambda expressions for the states' logic, you can of course also just pass normal functions.

Side note: To keep things simple, we're using strings for the state identifiers. Just keep in mind that UnityHFSM is not limited to this, as it allows you to use any custom type (e.g. enums) for the state identifiers. See the generics chapter for more information.

Adding transitions

…

Although the above code snippet is definitely functional, you may notice that it seems a bit overly verbose and repetitive. That's because it is. We can do better!

Firstly, as creating transitions with the Transition class is so common, there are shortcut methods to minimise the amount of boilerplate code. The first transition is equivalent to writing:

csharp
fsm.AddTransition("ExtractIntel", "FollowPlayer",
    transition => DistanceToPlayer > ownScanningRange);

Secondly, it is a common pattern to define a transition in one direction when a condition is true, and in the other direction when it is false. UnityHFSM provides a special feature to implement this in code: two way transitions. Using a combination of this feature and shortcut methods we can reduce the original code snippet to the following:

csharp
fsm.AddTwoWayTransition("ExtractIntel", "FollowPlayer",
    transition => DistanceToPlayer > ownScanningRange);

fsm.AddTwoWayTransition("ExtractIntel", "FleeFromPlayer",
    transition => DistanceToPlayer < playerScanningRange);

Initialising and running the state machine

csharp
void Start()
{
    // ...

    // Initializes the state machine and must be called before OnLogic() 
    // is called.
    fsm.Init();
}

void Update()
{
    fsm.OnLogic();
}

At this point, the basic version of the enemy controller is finished and ready to use :D

By the way, using all of the aforementioned tricks, the entire definition of the state machine can be reduced to remarkably few lines of code:

csharp
void Start()
{
    fsm = new StateMachine();

    fsm.AddState("ExtractIntel");
    fsm.AddState("FollowPlayer", onLogic: state => MoveTowardsPlayer(1));
    fsm.AddState("FleeFromPlayer", onLogic: state => MoveTowardsPlayer(-1));

    fsm.SetStartState("FollowPlayer");

    fsm.AddTwoWayTransition("ExtractIntel", "FollowPlayer",
        transition => DistanceToPlayer > ownScanningRange);
    fsm.AddTwoWayTransition("ExtractIntel", "FleeFromPlayer",
        transition => DistanceToPlayer < playerScanningRange);

    fsm.Init();
}

Hierarchical State Machine

When dealing with more complex behaviour, it is natural to break the problem down into sub-problems. This approach maps beautifully to state machines. First you define the states and then in a later step you can add the logic and behaviour to them. When designing a state, it can sometimes be useful to draw another state diagram just for it and to think about how you can break down its behaviour. The result of this is a hierarchy of states - a hierarchical state machine.

How can we implement this in UnityHFSM?

Because the StateMachine class inherits from StateBase, it can be treated as a normal state. This allows for the nesting of state machines together with states. On top of this, UnityHFSM provides additional features to describe the timing / exit conditions for a state machine (more on this later).

Expanding on the previous example

In the previous example, we left the Extract Intel state empty. Let's change this. When extracting intel, the spy should first collect data and then send it, repeating the process once completed.

So that you can see a visual difference, let's make it that the enemy spins when it enters the Send Data state, like it's sending the data out in all directions.

The Idea

  • Create a separate state machine for the nested states (States in Extract Intel)

  • Add the nested states to the new state

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

C#coroutinescsharpfinite-state-machinefsm

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言