Simple FSM-like structure using Coroutines in C# (Unity3D)

The previous post got a funny comment in Reddit: “Yawn. Hang on, inheritance, singletons? Bletch”. So I thought… “I may be getting rusty… let’s give those coroutines a try”. At first, coroutines seemed like a sure way of leaving behind all my (humble) OOP practices.  I though they were some kind of goto statement, probably because I had never given them a try. Ignorance is bold.

So here’s the same Miner from our previous post (yes, the one from Programming Game AI by Examples), going back and forth from the mine to the bank. But this time, each state is implemented using a coroutine. Thanks to the yield statement, coroutines can simulate our three state stages: Enter, Execute and Exit. Even better, we may easily add pauses wherever we need. If the coroutine is used to implement an entity’s AI, it can be updated every x milliseconds (depending, for example, on the entity’s reflexes), instead of every frame.

The trick lies in the FSM coroutine:

 IEnumerator FSM() {
    // Execute the current coroutine (state)
    while (true)
	yield return StartCoroutine(state.ToString());
  }

It constantly calls and waits for the execution of the current state (which is another coroutine). If the executed state changes the current state, the next iteration will launch it properly. I guess some code should be added to change states in external events, stopping any running coroutines.

So here we go! I’ve removed some variables, but it’s mostly the same behaviour:

File: CoMiner.cs

using UnityEngine;
using System.Collections;

public class CoMiner : MonoBehaviour {
  public enum State {
    EnterMineAndDigForNuggets,
    EnterBankAndDepositGold
  }

  public State state;

  public void Awake() {
    state = State.EnterMineAndDigForNuggets;

    // Start the Finite State Machine
    StartCoroutine(FSM());
  }

  IEnumerator FSM() {
    // Execute the current coroutine (state)
    while (true)
	yield return StartCoroutine(state.ToString());
  }

  IEnumerator EnterMineAndDigForNuggets() {
    /* This part works as the Enter function
    of the previous post (it's optional) */

    print("Entering the mine...");
    yield return null;

    /* Now we enter in the Execute part of a state
    which will be usually inside a while - yield block */

    bool dig = true;
    int digged = 0;
    while (dig) {
      print("Digging... " + (digged++) + " " + Time.time);
      if (digged == 2) dig = false;
      yield return new WaitForSeconds(1);
    }

    /* And finally do something before leaving
    the state (optional too) and starting a new one */

    print ("Exiting the mine...");
    state = State.EnterBankAndDepositGold;
  }

  IEnumerator EnterBankAndDepositGold() {
    //Enter
    print ("Entering the bank...");
    yield return null;

    //Execute
    bool queing = true;
    float t = Time.time;
    while (queing) {
      print ("waiting...");
      if (Time.time - t > 5) queing = false;
      yield return new WaitForSeconds(1);
    }

    //Exit
    print ("Leaving the bank a little bit richer...");
    state = State.EnterMineAndDigForNuggets;
  }
}

This way, each class contains it’s own FSM-like structure, though a simple one. No need for multiple files for each state, which can be cumbersome if a project grows (and they always do). And its really easy to follow and understand, once you understand how coroutines work.

It is a simpler solution, but pretty useful indeed! And of course, it can be combined with good OOP practices, not exactly as shown before 🙂