Unity Fsm

MIT
by saltatory

A Simple Finite State Machine for Unity game objects.

( Crawled 27 minutes ago )
+

Simple Unity FSM

Feel free to examine, comment, decry, and use to your heart's content.

Overview

Write a script for a game object that inherits from StateMachine rather than MonoBehaviour.

public class Thingy : StateMachine
{
}

Construct a graph of states.

public class Thingy : StateMachine
{
    // Set of FSM states used in this object
    private State stateFree ;
    private State stateCaptured ;
    private State stateFlushed ;

    void Start () {
        // Create some states
        stateFree = AddState ("Free");
        stateCaptured = AddState ("Captured");
        stateFlushed = AddState ("Flushed");

        // Link the states together
        StartState.AddTransition (stateFree).AddTransition (stateCaptured).AddTransition (stateFlushed);

        // Transition to your initial state
        Transition (stateFree);
    }
}

Handle Transitions

    public override void OnTransition(State from, State to) {
        switch(to.Name){
        case "Free":
            acceptInput = true;
            break;
        // ...
        }
    }

Register other objects to listen for transition events

    private void TransitionedEventHandler(object sender, TransitionArgs args){
        // Stuff that happens over here when a Thingy transitions.
    }

    void SpawnThingys() {
        GameObject spawn = GameObject.Find ("Spawn");

        for (int i=0; i<NumberOfBalls; ++i) {
            GameObject thingy = Instantiate<GameObject>(Resources.Load<GameObject>("Thingy"));
            thingy.transform.position = spawn.transform.position - new Vector3(0,0,5);
            thingy.GetComponent<Thingy>().Transitioned += this.TransitionedEventHandler;
        }
    }

Profit.

Motivation

In working on a 2D game project in Unity, I ran into a problem. I had game objects that would behave differently depending on what had happened to them. The game is a 2D game involving 2D physics and Balls on a tilting table. When the Ball gets captured by a hole, the Ball falls in. While that is happening, the physics change and a series of animations and sounds are played.

Handling the different states of the game objects called for a State Machine.

Unity is awesome as is the Mecanim animation system. I considered using the Mecanim animation system built into Unity. However, I didn't like the fact that the State Machine in that system is a Component attached to a GameObject rather than something that a GameObject could "be". Transitioning between states in the Mecanim system required setting values/triggers on the Animator, requiring that the GameObject knew about all the states. However, the states were setup in the editor. This isn't required but to get the power of the Editor, this is how the tutorials do it. Using the states in the GameObject also required that the GameObject know about the states even though they are created in the Editor. To my way of thinking, this was a weird back-and-forth of dependencies.

A much better design for that system would be if a GameObject could "be" a State Machine and the Mecanim system and the GameObject were both free to use the states and transitions. The Mecanim system would control rendering. The GameObject might control other game-related features like score keeping, object life-cycle, enabled-disabled collision boxes, etc.

Because my game is a relatively simple 2D and the Animations are simple too, it made more sense to handle states right on my GameObjects. Thus this class. The class was inspired by this post. Differences :

  • No reference to a player or NPC. More generic
  • Adds an event handler for non-inheritor objects to be notified
  • No Ids used. State and Transition objects are currently stored in a Set. I saw no compelling reason to include Ids unless they were GameObject InstanceIDs but I also did not want to have to implement MonoBehaviour functions on states and transitions.

Future Work

I implemented a minimum of methods for my own use. There could be more interesting use cases :

  • BeforeTransition()
  • AfterTransition()
  • Some sort of decision system that takes arguments and determines if the transition should happen.