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 🙂

14 thoughts on “Simple FSM-like structure using Coroutines in C# (Unity3D)

  1. Great stuff, but any chance you can give a more working example like you did in the last post finite state machine post – I’m not sure I understand how this all comes together… I assume I can’t just drop CoMiner.cs in as is and expect it to work. Do I need to modify FSMState.cs or FinateStateMachine.cs?

  2. Thanks Walter. Well, yes, it should work right as is. It doesn’t need FSMState.cs nor FiniteStateMachine.cs anymore, because all states are contained in CoMiner’s methods (no inheritance, no singletons… although it would look much better with a Miner interface, or something similar).

    Just create an empty GameObject, attach CoMiner and run. When it awakes, it starts the FSM coroutine, which launches the appropriate state (EnterMineAndDigForNuggets). When EnterMineAndDigForNuggets is called, it simply prints “Entering the mine…” and returns (yield). The next time it’s called, in FSM’s while loop, the execution continues after the yield statement, so it enters in EnterMineAndDigForNugget’s while loop.

    Try it! : )

  3. Excellent – I personally (now that I’ve played around with both) like the singleton/abstract class as presented in the last post a bit more due to its being more reusable. I had some fun with your other class implementing the “Thirst” and “Fatigue” portion by adding “GoToHome” and “GoToBar” classes. Currently if you didn’t change your logic, the above could get messy pretty quickly with the additional states without some form of oo wrapper.

    In any case, this was incredibly helpful and I appreciate you putting it out there!

  4. I also prefer the ‘old OOP’ way, and I guess things could be more organized if CoMiner implemented some Miner Interface, forcing the class to define a function for each pre-defined state. It may not be useful for the miner, but it would be for a ‘monster’ class or something like that, more generic. Nevertheless, I don’t really understand what’s the problem with inheritance (when properly used), and I guess it would be quite useful in this case. That Reddit user never explained why he didn’t like it 🙁

    It’s true, however, that coroutines allow an easy control of AI updates.

    I’m adding some steering behaviors to this model (the one with coroutines), but I’m having some problems when dealing with physics. They must be handled in a LateUpdate function while the FSM runs its coroutines to deal with AI decisions. The LateUpdate function thus becomes some kind of low level ‘motor skill’ handler, but that’s a different problem : )

  5. So, after much playing around I hit a snag using the OOP/Template version –

    I was “trying” to incorporate the best of both worlds – A templated class hierarchy that was still inheriting from MonoBehavior so I could use Coroutines (simply for the delays) and hit a brick wall… If I didn’t include MonoBehavior as FiniteStateMachines.cs base class i would get this error:

    Assets/Scripts/FiniteStateMachine.cs(40,17): error CS0103: The name `StartCoroutine’ does not exist in the current context

    If I included it I would get this warning which in effect (if I tried to call a coroutine would crap out)

    You are trying to create a MonoBehaviour using the ‘new’ keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all
    UnityEngine.MonoBehaviour:.ctor()
    FiniteStateMachine`1:.ctor()
    Miner:Awake() (at Assets/Scripts/Miner/Miner.cs:72)

    – That related to this line in Miner.cs
    FSM = new FiniteStateMachine();

    Anyway to get the best of both worlds? I can send you what I have so far, but I would really much prefer to keep the segmented class structure (with the Enter / Execute / Exit form).

    —–

    Added:

    FSMState.cs – abstract public IEnumerator Test(T entity);

    EnterMindAndDigForNuggets.cs –
    public override IEnumerator Test (Miner m) {
    Debug.Log(“Test”);
    yield return new WaitForSeconds(1);
    }

    FiniteStateMachine.cs – StartCoroutine (CurrentState.Test(Owner));

    Pretty basic stuff, but I can’t figure how to use AddComponent to compensate for the “FSM = new FiniteStateMachine();” or even if that will work when i did figure it out.

    If you figure a way to combine them both, please post it as I will be eager to see how it would test drive.

  6. I’m not sure if this solution is what you were looking for. I’ve changed two things. First, in Miner.cs, I removed the Update method. You won’t need it anymore unless you have to update physics. Then add FSM.StartRunning(); in the last line of the Awake method.

    Open FiniteStateMachine.cs and change the imports and class definition to

    using UnityEngine;
    using System.Collections;
    public class FiniteStateMachine : MonoBehaviour {

    Add this method, which launches the coroutine when called:

    public void StartRunning() {
      StartCoroutine(UpdateState());
    }
    

    Remove the Update method, and add this one instead:

    public IEnumerator UpdateState()
    {
    bool FSMRunning = true;
      while (FSMRunning) {
        if (GlobalState != null)  
          GlobalState.Execute(Owner);
        if (CurrentState != null) 
          CurrentState.Execute(Owner);
        yield return new WaitForSeconds(1);
      }
    }
    

    And that’s all! Now the FSM updates once every second, or once every frame if you return null.

    As I said, I’m not sure if that’s what you were looking for, neither if it’s a proper solution (what if ChangeState is called while UpdateState is running? I guess you should stop the coroutine, change the state and restart the coroutine) But you may find it useful!

  7. I’m looking for a way to have more than one state at a time.

    The main issue is that a code like this cause the current state to be stucked in the while loop and does not give control back to a central scheduler.

    while (somethingIsTrue)
    {
    // do something
    yield return new WaitForFixedUpdate();
    }

    What I would like to have is a way to execute two states during the same frame, without the state to know each other.

  8. If someone stumbles across these posts – maybe this will come in useful –

    In your posts above you say : “I guess some code should be added to change states in external events, stopping any running coroutines.”

    This may help –

    http://www.youtube.com/watch?v=lo80BOomaU4

    “In this video I show one way to implement a Finite State Machine (FSM) in Unity3d. It uses coroutines and Prime[31]’s excellent coroutine manager to implement concurrency and interruptibility, two important features for FSMs.

    I think the main benefit of my implementation is that long running tasks can be used in a ‘fire and forget’ manner: when they return with success we can kill all other tasks currently being performed using the coroutine manager. “

  9. I’m in the process of testing different solutions to the state machine problem.

    This one may fit the considerations raised in the comments above – also by Prime31

    https://github.com/prime31/StateKit

    “Lightweight and simple to use state machine implementing the “states as objects” system. The idea is to create a state machine for some target object (could be a player, NPC, overall game, menu system, etc) that allows you to separate all the states into separate classes while retaining access to the original target object.”

  10. Enum.ToString uses reflection, i wouldn’t recommend doing it repeatedly in your main game processing loop. Do it once for each state and cache the results in a dictionary or something.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

About

This is PlayMedusa's game devlog: sketches, artwork, news, tutorials... Know more about us and our work in our MAIN SITE!

We create games mostly because we enjoy doing so. We hope you also enjoy playing them! Check them out at itchio Some can be played on the browser!

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies