Unity Coroutine, simple guide with code samples

Unity Coroutine gives you the power to pause and resume code blocks at your disposal. You can decide how the execution of code is to be done and which code needs to wait. You can execute the coroutine in a way to optimize your game’s performance. In this post, we will see what is a Coroutine and how to start and stop a coroutine along with examples, advantages and disadvantages.

What is a Coroutine in Unity?

A coroutine is a function that allows pausing its execution and resuming from the same point after a condition is met. You can start a coroutine and wait for its results before your code moves on to the next line. Or you could let the coroutine handle its business on the side while your code moves on to execute the rest of its functions.

A simple analogy to coroutine in real world is a traffic signal. The traffic on the road needs to wait until the signal turns green and meanwhile the traffic in other roads can move on. Similarly, Coroutine can help you pause some part of the code for some time. Unity has introduced Async await for delay in versions 2019 and above. So, it’s totally up to you to use which ever function you like.

Let’s say you want to spawn a cube in a scene 5 seconds after the game starts. You could implement a Unity timer function in the Update and then check how much time has passed, but there is a much simpler way of achieving this with the Unity coroutine.

Free Unity asset banner

A Coroutine in Unity looks like this

private IEnumerator SpawnBoxAfterSeconds(float seconds)
   {
       yield return new WaitForSeconds(seconds);
       Instantiate(objectToSpawn);
       Debug.Log("Spawned " + objectToSpawn.name + " after " + seconds + " seconds!");
   }

There might be a few things that may be unfamiliar to you in the code above. Let’s run through them.

IEnumerator

The return type is of IEnumerator. IEnumerator is an enum datatype. An enum only takes predefined constants as input. For example, if you take the compass the enum will take only east, west, north, and south.

In our code the value of IEnumerator datatype is sent to the system to indicate the status of the Coroutine. Depending on the value of the IEnumerator the system decides whether or not to execute the Coroutine.

Yield

The first line inside the function is: yield return new WaitForSeconds(seconds);

As you might have guessed, this line allows us to wait for 5 seconds. After 5 seconds, it will execute the code that follows it. In this case, it will instantiate a prefab and then print a debug log statement.

The keyword “yield” is what actually set the value of the IEnumarator which in turn tells the system to pause the script and continue on the next frame. It will keep doing this for 5 seconds, and then the code following it will be executed.

How to Start a Coroutine in Unity

To start a Coroutine you have to use a function called StartCoroutine(). This method takes a function name as input. You can also pass the function name as string input to the StartCoroutine().

A Unity coroutine is like a normal function, but it is called differently. Instead of calling it like any other function “SpawnBoxAfterSeconds(5f)” we need to specify that the coroutine needs to start. So, the code will be “StartCoroutine(SpawnBoxAfterSeconds(5f))”

This is true for all coroutines. Failing to do this will not throw an error, but the Unity coroutine function will not work at all.

Method 1: Example, calling the function with parameters

public class ExampleScript : MonoBehaviour
{
   public GameObject objectToSpawn;
   private void Start()
   {
       StartCoroutine(SpawnBoxAfterSeconds(5f));
   }

   

There is also another way of calling coroutines. You can pass the name of the function as a parameter in string format. However, you cannot pass a parameter for the function in this way of starting a Coroutine. It’s better to use the earlier examples in all scenarios. This way you are not prone to spelling errors, and you have the option to pass parameters if you want to at a later stage. The way you start the coroutine also decides how you are going to stop it. We will discuss more on this in the StopCoroutine section.

Method 2: Example, using a string input


   private void Start()
   {
       StartCoroutine("SpawnBoxAfterSeconds");
   }

   

4 Ways to stop a Coroutine in Unity

Now that we know how to start a coroutine, let’s go through how to stop it. It’s quite simple. There are 4 ways to stop a coroutine.

Method 1: Using the Coroutine’s name as string

The most common way is to use StopCoroutine(“SpawnBoxAfterSeconds”);

You do not need to specify the parameter. It will simply stop the Unity coroutine that has that function name. This method will only work if you also start the coroutine by passing the function name as a string like in the 2nd example of Starting a coroutine.

Now there is a problem here. What if you have called that coroutine more than one time? What will happen if you stop it as we did in the above example?

This will stop ALL the coroutines with that function name. So, if you do this:

private void Start()
   {
      StartCoroutine("SpawnBoxAfterSeconds");
      StartCoroutine("SpawnBoxAfterSeconds");
      StartCoroutine("SpawnBoxAfterSeconds");

      StopCoroutine("SpawnBoxAfterSeconds");
   }

This would stop all 3 Unity coroutines. This may or may not be what you intend to do, so use it with this point in mind.

As mentioned, stopping a coroutine by passing a string parameter only works if you start it the same way.

Method 2: Using an object of type Coroutine

How do we stop a coroutine if it was called like in the 1st example of Starting a coroutine?

You need to store the coroutine into a variable when you start it. That way you can stop the coroutine by passing that variable instead. Here’s an example:

public class ExampleScript : MonoBehaviour
{
   public GameObject objectToSpawn;
   private Coroutine spawnBoxCoroutine;
   private void Start()
   {
       spawnBoxCoroutine = StartCoroutine(SpawnBoxAfterSeconds(5f));
      
       StopCoroutine(spawnBoxCoroutine);
   }

   private IEnumerator SpawnBoxAfterSeconds(float seconds)
   {
       yield return new WaitForSeconds(seconds);
       Instantiate(objectToSpawn);
       Debug.Log("Spawned " + objectToSpawn.name + " after " + seconds + " seconds!");
   }
}

As you can see in the example above, we created a variable of type Unity Coroutine. When We call StartCoroutine, it stores it into that object. This way we have a reference to it. In the next line, we call StopCoroutine(); and instead of passing a string with the name of the function, we pass the Coroutine object.

Note: Since we are creating a reference to the object, you can also do this even if you start the coroutine like this spawnBoxCoroutine = StartCoroutine(“SpawnBoxAfterSeconds”);

Method 3: Using an IEnumerator

The final way of stopping a Unity coroutine is by passing the IEnumerator variables inside StopCoroutine(). Here’s an example.

public class ExampleScript : MonoBehaviour
{
   public GameObject objectToSpawn;
   private IEnumerator SpawnBoxIEnumerator;
   private void Start()
   {
       SpawnBoxIEnumerator = SpawnBoxAfterSeconds(3f);
       StartCoroutine(SpawnBoxIEnumerator);
      
       StopCoroutine(SpawnBoxIEnumerator);
   }

   private IEnumerator SpawnBoxAfterSeconds(float seconds)
   {
       yield return new WaitForSeconds(seconds);
       Instantiate(objectToSpawn);
       Debug.Log("Spawned " + objectToSpawn.name + " after " + seconds + " seconds!");
   }
}

Method 4: Using a break statement

You can use the break statement to end any type of loop and Coroutines are no exception. You need to use the break statement along with yield in case of a Coroutine. If you use the break statement as you first line the Coroutine will end immediately.

Here is the sample code

private IEnumerator Using_break()
   {
       yield break;
       
   }

Wait options in Unity Coroutine

Wait For Seconds Method

We have a basic grasp of how coroutines work and how to call them. Now I’m going to show an example of waiting for a few seconds because it is used very often by developers. This can be used to replace the timer function and is a more efficient way to make a timer.

public class ExampleScript : MonoBehaviour
{
   public GameObject objectToSpawn;
   private IEnumerator SpawnBoxIEnumerator;

   private void Start()
   {
       StartCoroutine(SpawnBoxAfterSeconds(3f));
       Debug.Log("Complete!");
   }

   private IEnumerator SpawnBoxAfterSeconds(float seconds)
   {
       yield return new WaitForSeconds(seconds);
       Instantiate(objectToSpawn);
       yield return new WaitForSeconds(2f);
       Debug.Log("Spawned " + objectToSpawn.name + " after " + Time.time + " seconds!");
   }

Console log

As you can see, inside the Start function, we start the coroutine and then print “Complete!”. When the coroutine started it waited for 3 seconds (because that’s the amount we passed through the parameter), and then instantiated a Gameobject. Then it waited for 2 additional seconds and printed another message stating that it spawned Cube after 5 seconds. It says 5 seconds because that is the amount of time that has passed since the game started (3 + 2 seconds). we got the Time by using Time.time, which is a variable that returns the amount of time since the game started.

If you are planning to use the same delay multiple times then you can improve the performance of the WaitForSeconds function using a variable. Here is how to do it

public class ExampleScript : MonoBehaviour
{
   public GameObject objectToSpawn;
   private IEnumerator SpawnBoxIEnumerator;
   WaitForSeconds timer=new WaitForSeconds(2);
   

   private void Start()
   {
       StartCoroutine(SpawnBoxAfterSeconds(3f));
       Debug.Log("Complete!");
   }

   private IEnumerator SpawnBoxAfterSeconds(float seconds)
   {
       yield return new WaitForSeconds(seconds);
       Instantiate(objectToSpawn);
       yield return timer;
       Debug.Log("Spawned " + objectToSpawn.name + " after " + Time.time + " seconds!");
   }


 
We have another problem!

Inside the start function, we printed “Complete!”, but the coroutine is not complete yet. Let’s fix that in this coming section y waiting for the Coroutine to finish.

Waiting for Coroutine to finish

In order to wait for a coroutine to finish processing before we can move on, we need to yield from the place that we are calling the coroutine and the function from which we are starting the Coroutine should also be a Coroutine. Here’s an example:

private IEnumerator Start()
{
   yield return StartCoroutine(SpawnBoxAfterSeconds(3f));
   Debug.Log("Complete!");
}

private IEnumerator SpawnBoxAfterSeconds(float seconds)
{
   yield return new WaitForSeconds(seconds);
   Instantiate(objectToSpawn);
   yield return new WaitForSeconds(2f);
   Debug.Log("Spawned " + objectToSpawn.name + " after " + Time.time + " seconds!");
}

We converted the start function into a Coroutine with a return type IEnumerator and added the keywords yield return before we started the coroutine. Yield as we mentioned, is what tells unity to move on to the next frame. So, until the SpawnBoxAfterSeconds Coroutine hasn’t been completed, we do not move on to the next line. Note that this could cause the game to get stuck in an infinite loop if not written correctly.

Below is the result of the above code. As you can see, “Complete!” gets called right after the cube is spawned.

WaitForSeconds is affected by Time.timescale in Unity. If you want the Coroutine to run even when the timescale is set to zero then you can use the function below.

yield return new WaitForSecondsRealtime(5);

This uses the system time and is not affected by change in time in Unity.

Make Unity Coroutine Wait Until a condition is true

You can use WaitUntil method to pause a Coroutine in Unity till a condition is met. WaitUntill takes a Boolean as input parameter and pauses the Coroutine until the parameter is true.

Here is how to use it

yield return new WaitUntil(() => game_paused);

Make Unity Coroutine Wait While a condition is true

WaitWhile is very similar to WaitUntil. The Difference between them is WaitUntil will pause till the parameter is false whereas WaitWhile will pause when the parameter is true.

Here is how to use WaitWhile

yield return new WaitWhile(() => game_playing );

Make Coroutine wait till end of frame

You can make the Coroutine wait till the end of the current frame using the function WaitForEndOfFrame.

Here is a code sample

yield return new WaitForEndOfFrame();

Make Coroutine wait will next frame

As you have seen in the above examples you can pass many functions to the yield statement depending on how you want the Coroutine to wait before proceeding. If you want the Coroutine to just wait till the next frame then you can pass null to the yield statement.

Here is how to use it

yield return null;

Making a timer with coroutine

You can implement a Unity timer with Unity Coroutine with much ease. Coroutines are useful to execute a function over a number of frames. The main difference between using a coroutine and normal time.deltatime is displaying time. If you want to display a timer that changes every frame then it’s better not to use a coroutine. But if you want to execute a function after a time period then coroutine is the easiest way.

One other important thing to note is coroutine can be used only with MonoBehaviour. If you are looking to make a Unity timer without MonoBehaviour then use the first method.

Creating the script

  1. Create a new script callled Waitforsecond_unity.
  2. Copy and paste the code below into the script.
  3. Set the required time in the delay variable.
  4. Click play the value of ammo variable will set to 50 after 5 seconds.
using System.Collections; 
using System.Collections.Generic; 
using UnityEngine;

public class Waitforsecond_unity : MonoBehaviour
{

public float delay = 5f;
private int ammo=0;
void Start()
{
    StartCoroutine("Delaythis");
}
IEnumerator Delaythis()
{
    
        yield return new WaitForSeconds(delay)
        ammo=50;


}
}

If you are using the yield statement then the return type should be IEnumerator.

Advantages and Uses of Unity Coroutine

Coroutines are mainly used, when necessary, rather than for convenience. It is easy to use, and it’s quite handy in many situations. However, the sad truth is that coroutines are expensive when overused or when not tracked. Make sure that your coroutines always end. And if they do not work in a way that they end when a condition is satisfied (maybe you want to constantly calculate something all the time), then stop the coroutines manually through code yourself. Cleanup is very important when using a lot of coroutines.

Advantages

  • The advantages of coroutines are that they work wonders in smaller games. You wouldn’t need to worry about the performance overhead, and you can use them as you please. Don’t get me wrong, you can use them even in large-scale games, but they need to be used carefully and properly.
  • They are convenient when you want to wait (as shown in above examples), you can wait for a few seconds, you can wait for the end of the frame, and you can even bypass Unity time. This means that if your Time.timescale is set to 0 when your game is paused, or is part of your game’s mechanics, you can use yield return “yield return WaitForSecondsRealtime(2f)
  • Another advantage is that you can run a separate block of code on the side while your script goes through all its lines of code. What I mean by this is that when you call a coroutine, a piece of functionality can run without your main code having to stop and wait for the process to finish. An example was made in the Wait for seconds example, where the print happened even though the coroutine hadn’t finished its process yet. Which can come in handy.

Disadvantages

  • A disadvantage would be that coroutines return IEnumerator, so you cannot return a float or GameObject, for example. Although it is possible, it would require further implementation that is not provided by Unity by default.
  • As mentioned above, they can be expensive if used too much, because they also create garbage and are not completely running on a separate thread in the backend.
  • Another disadvantage arises if Coroutines are used for the wrong reason, or implemented wrong. For example, if you have some code running that depends on a variable being set inside a coroutine, you may get a null result because the coroutine didn’t set the variable in time.

Leave a Reply

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