Coroutines in Unity: Part 2 – Interesting facts

Coroutines in Unity: Part 2 – Interesting facts

In the previous part, we learnt about the basics of coroutines in Unity. Let us now learn some important and interesting points regarding Coroutines.

Effect of Disabling an object on Coroutines in Unity:

Disabling a gameobject, i.e. using SetActive(false) stops a coroutine.

Also, calling Destroy(example) (where example is a MonoBehaviour instance) immediately triggers OnDisable. The coroutine is thus processed, effectively stopping it. Finally, OnDestroy is invoked at the end of the frame.

However, disabling a MonoBehaviour does not stop a coroutine.

Script Execution order affects Coroutines in Unity

The script execution order affects the execution of coroutine as well. For instance, lets say, I have two scripts: Script1 and Script2. These scripts have an execution order of 100 and 120 respectively (i.e. Script1 runs first). Further, in both scripts, I call a Coroutine in Start() function. 

So, the execution order of functions is:

Start() of Script1
Start() of Script2
Coroutine of Script1
Coroutine of Script2

StartCoroutine is a method of MonoBehaviour

StartCoroutine is a public method of the MonoBehaviour. Thus, you need a MonoBehaviour class or an object of MonoBehaviour to call a coroutine.

Only one coroutine can wait for another coroutine

Lets us understand this with an example

     void Start ()
     {
         Coroutine f1 = StartCoroutine(firstcoroutine ());
         StartCoroutine(waitingCoroutine1 (f1));
         StartCoroutine(waitingCoroutine2 (f1));
     }

    IEnumerator firstcoroutine()
    {
        yield return new WaitForSeconds(3);
    }

    IEnumerator waitingCoroutine1(Coroutine c)
    {
        yield return c;
        Debug.Log("end waitingCoroutine1");
    }

    IEnumerator waitingCoroutine2(Coroutine c)
    {
        yield return c;
        Debug.Log("end waitingCoroutine2");
    }

Here, we have three coroutines where waitingCoroutine1 and waitingCoroutine2 wait for firstcoroutine at the yield statement. On running this script, you will get a unity log stating:

Another coroutine is already waiting for this coroutine! Currently only one coroutine can wait for another coroutine!“.

Consequently, Debug.Log(“end waitingCoroutine2”); statement is never executed. This is because waitingCoroutine1 is already waiting for firstcoroutine, so waitingCoroutine2 cannot simultaneously wait for firstcoroutine.

Coroutines in Unity cannot be started on an inactive GameObject

Lets say you have a script Execution1 attached to gameobject: Object1

public class Execution1 : MonoBehaviour
{
    public IEnumerator ExecuteIt()
    {
        yield return null;
        Debug.Log(" Coroutine Execution1");
    }
}

Another script RunExecution has a function that accesses the ExecuteIt function of Execution1. This script is attached to Object2.

public class RunExecution : MonoBehaviour
{
    public Execution1 executeRoutine1;

    void Start()
    {
       executeRoutine1.StartCoroutine(executeRoutine1.ExecuteIt());
    }
}

If Object1 is disabled, ExecuteIt throws an exception:

“Coroutine couldn’t be started because the game object ‘Object1’ is inactive!”

However, if we had written the following in RunExecution

    void Start()
    {
       StartCoroutine(executeRoutine1.ExecuteIt());
    }

The ExecuteIt function is called as the calling script is placed on Object2 which is still active.

WaitForSeconds is dependent on TimeScale

The following Coroutine will not work when Time.timeScale is equal to 0.

    public int timer = 60;
    public IEnumerator Timer()
    {
        while (timer > 0)
        {
            Debug.Log("inside timer");
            yield return new WaitForSeconds(1);
            timer--;
        }
        Debug.Log("Game Over");
        yield return null;
    }

This is because timeScale affects all the time and delta time measuring variables. Thus when timeScale = 0, WaitForSeconds waits indefinitely.

Coroutines in Unity can be stopped only at the yield statement

It means that whenever you try and stop the coroutine, any lines written before the yield statement will execute irrespective of stopping the coroutine.

To explain this, lets take the example of the above Timer Coroutine. You can notice the Debug statement in the while loop. Whenever you try and stop this coroutine, this debug will always run.

We will learn about when to use Coroutines in the next part.

Happy Coding!

Share This Post