user2853912
user2853912

Reputation: 31

Loops using coroutines

I have a question about coroutine behaviour in case of loops, see following code extract as example done on a Unity C# script:

void Start() {
    StartCoroutine(FSM());
}

IEnumerator FSM() {
    state="State1";
    while (true) {
        Debug.Log("State "+state);
        yield return StartCoroutine(state);
    }
}

IEnumerator State1() {
    while (true) {
        if (stateTransitionCond) {
            state = "NextState";
            yield break;
        }
        yield return null; 
    }
}

The status machine works fine, but while the current status is Status1 (stateTransitionCond==false), due to the yield return null inside the loop of State1() routine, I was expecting that loop inside FMS() also performs another iteration generating debug log 'Debug.Log("State "+state);'.

In other words I was expecting a lot of debug log (one for each iteration of State1() routine, when status is Status1) but in the reality only 1 execution is performed while status is Status1.

So I suppose I miss something about yield functionality, is there anybody that can explain me this behaviour?

Upvotes: 2

Views: 9047

Answers (1)

Robert Mitchell
Robert Mitchell

Reputation: 1334

Your issue stems from the fact that your code does not break out of the State1() method until stateTransitionCond == true.

The method starting the coroutine, FSM(), is not returned to until State1 is finished. In other words, control flow does not return to the calling method until the coroutine is complete. I believe this is due to the fact that you are yield-ing State1 inside FSM (yielding another coroutine). Obviously, "normal" methods do not wait for the coroutine to finish before continuing execution.

Please see the code sample below for an illustrative example:

using UnityEngine;
using System.Collections;

public class CoroutineTest : MonoBehaviour {
    // current FSM state
    public string state = ""; 

    void Start()
    {   
        StartCoroutine(FSM());
    }   

    IEnumerator FSM()
    {   
        state = "State1";

        while (true)
        {   
            Debug.Log("State: " + state);
            // ExecuteOnce will execute exactly once before returning to the outer function
            yield return StartCoroutine(ExecuteOnce());

            // ExecuteIndefinitely will execute indefinitely until its while() loop is broken
            // uncomment to test
            //yield return StartCoroutine(ExecuteIndefinitely());
        }   
    }   

    IEnumerator ExecuteOnce()
    {   
        Debug.Log("Calling ExecuteOnce()");
        yield return new WaitForSeconds(1f);
    }   

    IEnumerator ExecuteIndefinitely()
    {   
        Debug.Log("Calling ExecuteIndefinitely()");
        while (true)
        {   
            Debug.Log("Inside ExecuteIndefinitely()");
            yield return new WaitForSeconds(1f);
        }   
    }   
}

Upvotes: 2

Related Questions