C# finite state machine (fsm)

Take a look at the following output:

The above output was generated by an Orc entity with an associated finite state machine (FSM). Although a FSM can be used for many things, in game development it’s typically used to model character behaviour. Why? It’s simple and easy to debug.

Let’s have a look at Main to get a high-level feel for using an Orc entity:


static void Main(string[] args)
{
    Orc o = new Orc();

    o.Event = OrcEvent.Wander;
    o.UpdateState();

    o.Event = OrcEvent.Eat;
    o.UpdateState();

    o.Event = null;
    o.UpdateState();

    Console.ReadLine();
}
 

In a real game loop the UpdateState method would be called once per frame. Continuing with a top-down approach, let’s see the components that make up an Orc entity. First, we find a enum to represent simple event identifiers.


enum OrcEvent
{
    Eat,
    Wander
}
 

Events can trigger a change in state. It’s possible to use a table to map events to associated states. For example, the OrcEvent.Eat maps to the EatState and the OrcEvent.Wander maps to the WanderState. However, states don’t always have a 1-to-1 correspondence. For example, an OrcEvent.SeeEnemy could map to an AttackState. Here we see a transition table specific to Orcs:


class OrcTransitionTable : Ai.StateTransitionTable
{
    public OrcTransitionTable()
    {
        base.table.Add(OrcEvent.Eat, new EatState());
        base.table.Add(OrcEvent.Wander, new OrcWanderState());
    }
}
 

The base type StateTransitionTable handles housekeeping chores for the table:


abstract public class StateTransitionTable
{
    protected Dictionary<object, IState> table = new Dictionary<object, IState>();

    public void SetState(object evt, IState state)
    {
        table.Add(evt, state);
    }

    public IState GetState(object evt)
    {
        Ai.IState i = null;

        try
        {
            i = table[evt];

        }
        catch (KeyNotFoundException)
        {
            return null;
        }

        return i;
    }
}

What exactly is IState? It’s an interface with 3 methods for state processing:


public interface IState
{
    void Enter(Entity e);
    void Execute(Entity e);
    void Exit(Entity e);
}
 

Each method takes an entity type as a parameter. When switching states, the Exit method is called for the current state. The new state’s Enter method is then called. The current state is then assigned the new state. Execute is called once per frame to perform state processing.


abstract public class Entity
{
    protected Ai.StateTransitionTable transitionTable = null;
    protected IState currentState = null;

    public void UpdateState()
    {
        if (currentState != null)
            currentState.Execute(this);
        else
            System.Diagnostics.Trace.WriteLine("zero state");
    }

    public object Event
    {
        set
        {
            if (value == null)
            {
                currentState.Exit(this);
                currentState = null;
                return;
            }

            IState i = transitionTable.GetState(value);

            if (i != null)
            {
                if (currentState != null)
                    currentState.Exit(this);

                currentState = i;
                currentState.Enter(this);
            }
        }
    }
}
 

Implementing an Orc entity is trivial:

  • Inherit from Ai.Entity
  • Set the transition table in the constructor
  • Start adding methods for the new character

class Orc : Ai.Entity
{
    static Orc()
    {
        transitionTable = new OrcTransitionTable();
    }

    public void Drool()
    {
        Console.WriteLine("drooling...");
    }
}
 

Of course, an entity will need a variety of states to transition to. To create a new state type implement the IState interface. For example, here are a few Orc-related states:


class EatState : Ai.IState
{
    public void Enter(Ai.Entity e)
    {
        Console.WriteLine("entering eat state");
    }

    public void Execute(Ai.Entity e)
    {
        Console.WriteLine("executing eat state");
    }

    public void Exit(Ai.Entity e)
    {
        Console.WriteLine("exiting eat state");
    }
}

class OrcWanderState : Ai.IState
{
    public void Enter(Ai.Entity e)
    {
        Console.WriteLine("entering wander state");
    }

    public virtual void Execute(Ai.Entity e)
    {
        Console.WriteLine("executing wander state");

        Orc o = e as Orc;

        if (o != null)
            o.Drool();
    }

    public void Exit(Ai.Entity e)
    {
        Console.WriteLine("exiting wander state");
    }
}

class CustomizedOrcWanderState : OrcWanderState
{
    public override void Execute(Ai.Entity e)
    {
        base.Execute(e);

        Console.WriteLine("unique orc personality here...");
    }
}
 

Those are the basics of implementing a finite state machine for character control. You can download the source code here.

game of life

Conway’s ‘Game of Life’ produces some interesting patterns from a few simple rules. This demo utilizes WPF with simple styling and animation.

One day I’ll have to learn how to record, edit, and post videos online. Until then, it’s nothing but a static screenshot for you:

You can download the source here.