Go to Top

The down and dirty on coroutines. When they run and why they sometimes don't! Also learn about how to make cut sequences and long running operations using this powerful technology

Motivation

You should read this tutorial if you are not too sure about coroutines and maybe have had a problem getting them to work the way that you want.

Coroutines are a great way of:

  • Making things happen step by step
  • Writing routines that need to happen over time
  • Writing routines that have to wait for another operation to complete

For example you could easily imagine using a coroutine to orchestrate a cut scene sequence - or simply wait for an enemy to animate dying, pause and then respawn.

Coroutines are a very powerful part of Unity, but they are often much misunderstood by newcomers to the subject.  This tutorial will help you get a grip on the power and flexibility of coroutines and understand just how they work.

If you just want to delay an operation for a few seconds time you could consider just using Invoke.  You can use coroutines of course, but for beginners Invoke is easier.

Threads and Coroutines

First of all lets just be totally clear about this.  Coroutines are not threads.  Coroutines are not asynchronous.

A thread is a process that runs asynchronously with the other threads in the program.  On a multiprocessor machine a thread can really running its code at the same time as all of the other threads.  This makes programming threads a complicated thing to get right, because one thread could be changing something at exactly the same time as another thread is reading it.  This is even more complicated because the code you write is turned into assembly language by the compiler - which means another thread could actually change something in the middle of the game processing what appears to be a single line of your source code.  Because of this you have to go through hoops to ensure that such circumstances don't occur by either making sure that there is no shared memory or by locking other threads out of shared values while they are being read or changed.

Threads will be the subject of a subsequent article.

So What is a Coroutine?

Ok so we've established that a coroutine is definitely not a thread.  This means that only one coroutine will be executing at a time and it will be executing on the main thread of the game, so in fact it will be the only thing in the core game code running at that time.

You never need to worry about synchronisation or locking values when you are programming a coroutine.  You have total control right up until the point your code executes a yield.

So here is the definition of what a coroutine is:

A coroutine is a function that is executed partially and, presuming suitable conditions are met, will be resumed at some point in the future until its work is done.

Unity processes coroutines every frame of the game for every object that has one or more running.  The processing occurs after Update and before LateUpdate for most yield statements, but there are special cases:

When the coroutine is activated it will execute right up to the next yield statement and then it will pause until it is resumed.  You can see where it will resume in the diagram above, based on what you yield.

Let's look at a really simple coroutine:

IEnumerator TestCoroutine()
{
      while(true)
      {
           Debug.Log(Time.time);
           yield return null;
      }
}

This coroutine has a loop that apparently runs forever, it logs the current time and then it yields.  When it is resumed, it goes back around the loop, logs the time again and yields once more.

The code inside the loop is exactly like an Update function.  It runs once every frame for this object, just after the script's Update routine runs (if it has one).

When you call StartCoroutine(TestCoroutine()) the code executes immediately up to the first time it yields, it will then be resumed when Unity processes coroutines for this object.

If you start a coroutine early in the processing of a game object, like creating one in Start, Update or OnCollisionEnter then that coroutine will immediately run up to the first yield, then it will resume during the same frame if you yield return null.  This can sometimes lead to strange effects if you don't account for it.

Note that this isn't a problem if you make Start or OnCollisionEnter a coroutine, only if you start a coroutine from within them.  

To Infinity and Beyond

Now one more thing - the apparently infinite loop in our test coroutine turns out to be not so infinite!

That loop will never execute again if you make a call to stop the coroutines on the game object and it will not run again if the object is destroyed.  It will also be paused if the script is disabled directly or by using SetActiveRecursively(false) on the game object.

I Yield Sir

So I made a statement in the last section that you might be questioning.  I said:

Unity processes coroutines every frame of the game for every object that has one or more running.

You may be thinking "Oh no it doesn't, what if you use something like yield return new WaitForSeconds(1), then it doesn't process it for another 1 second!"

Well actually Unity does process that coroutine every frame, checking to see if the right amount of time has elapsed - it doesn't process your code, but it does process the coroutine which is the wrapper its made around your script.

So we know that we can effectively pause our code by yielding some value, here's what you can yield:

  • null - the coroutine executes the next time that it is eligible
  • WaitForEndOfFrame - the coroutine executes on the frame, after all of the rendering and GUI is complete
  • WaitForFixedUpdate - causes this coroutine to execute at the next physics step, after all physics is calculated
  • WaitForSeconds - causes the coroutine not to execute for a given game time period
  • WWW - waits for a web request to complete (resumes as if WaitForSeconds or null)
  • Another coroutine - in which case the new coroutine will run to completion before the yielder is resumed

You can also issue the command yield break; which immediately stops the coroutine.

Because of WaitForEndOfFrame coroutines can be used to get information from render textures when all cameras have completed rendering and the GUI has been displayed
Using yield return new WaitForSeconds(x) will never resume if the Time.timeScale is set to 0.

Of course the great thing about all of this is that you can write code that needs to execute over a period of time, or wait for some external event to occur, and keep it all nicely together in a single function making your code far more readable than if you had to write multiple functions or lots of code to keep checking the state of things.  That's really the point of coroutines.

Summary

  1. Coroutines are a really good way of making a sequence of operations happen over time or when some external process is completed
  2. Coroutines are not threads and are not asynchronous
  3. Nothing else is running when your coroutine is executing
  4. Your coroutine will resume when the conditions of your yield statement are met
  5. Coroutines are inactive when the script is disabled or the object is destroyed
  6. yield return new WaitForSeconds is dependent on game time which is affected by Time.timeScale

Practical Uses of Coroutines

Hopefully we've established what coroutines are and when they run.  Our advanced tutorial will examine the technology behind them.

Let's use coroutines to do something.  A couple of simple helper functions can really help us create easy cut sequences using a coroutine.

We can write a coroutine that moves an object to a target location and rotation.  We can write a coroutine that waits for an animation to be a certain percentage complete.  Then using those two tools we could easily script out a whole cut sequence in a single function where it will be easy to read!

The thing to watch for when moving things in a coroutine is to ensure that there isn't some fight breaking out between different coroutines or Update functions trying to manipulate the position of the object at the same time.

Ensure that you only have one coroutine affecting an object at one time and disable any Update functions that would move the object.

Here's an example of a coroutine to wait for an animation to be partially complete:

	//Wait for an animation to be a certain amount complete
	IEnumerator WaitForAnimation(string name, float ratio, bool play)
	{
		//Get the animation state for the named animation
		var anim = animation[name];
		//Play the animation
		if(play) animation.Play(name);

		//Loop until the normalized time reports a value
		//greater than our ratio.  This method of waiting for
		//an animation accounts for the speed fluctuating as the
		//animation is played.
		while(anim.normalizedTime + float.Epsilon + Time.deltaTime < ratio)
			yield return new WaitForEndOfFrame();

	}

You could write a coroutine to wait for an animation like this:

IEnumerator Die()
{
       //Wait for the die animation to be 50% complete
       yield return StartCoroutine(WaitForAnimation("die",0.5f, true));
       //Drop the enemies on dying pickup
       DropPickupItem();
       //Wait for the animation to complete
       yield return StartCoroutine(WaitForAnimation("die",1f, false));
       Destroy(gameObject);

}

The video will show you a lot more and the example project for it is available here.

Video

You should really watch this video if you want to know how to make very powerful coroutine tools, apply easing functions and take your coroutine exploits to the next level.

This video is quite long, but it has some really cool stuff in it!   Learn how to build a whole cut sequence using coroutines then see how to apply easing functions to yield statements.

By the end of the video you will know how to build advanced coroutine tools and use them to create great effects.  The download for the project has all of the stuff shown in the video.

, , , , ,

37 Responses to "Coroutines++"

  • morton
    November 25, 2012 - 3:18 am Reply

    very useful, thank you.

    in the video you use ToArray() in the foreach statement. could you please explain why?
    would the expression (ball != null) otherwise cause problems?

    • whydoidoit
      November 25, 2012 - 5:42 am Reply

      So firstly the foreach loop is running over quite a period of time – in the previous section of the video I make it so that the balls are destroyed when they fall off the edge, and I remove them from allBalls when that happens.

      Now a foreach loop does not like the collection it is iterating over to change, so as we are yielding in it, it is very likely it WILL change due to something being destroyed and removed from the list. To fix that I make a copy of the collection by using .ToArray() – so that just makes a copy of the list when the foreach loop starts, nothing will be removed from that copy. Now that we have a copy the loop is happy – but Unity will be setting the contents of it to null when they are destroyed (its one of those weird useful/unuseful features that are not well documented) – so if the ball has been deleted it will start returning null.

      Now here’s a couple of points:

      1. When, later in the video, I set timeScale = 0 actually no balls would have been deleted (because they aren’t moving)! I decided to leave it in as belt and braces.

      2. We could have taken a single copy of the array and continually used that – but when timeScale was running we might have had a newly spawned ball that wasn’t affected by the later code – again when timeScale became 0 that would not have happened.

      I hope that clears it up? Let me know :)

      • morton
        November 25, 2012 - 9:28 am Reply

        yes, all clear. thanks a lot.

  • moonlite
    November 27, 2012 - 11:41 pm Reply

    What do it means by “Nothing else is running when your Coroutine is executing”? As in all other function will not run when Corountine is executing??

    • whydoidoit
      November 28, 2012 - 12:39 am Reply

      I mean that no other code is running at the same time as your coroutine is in operation. Other code will run when you yield.

  • Pravin
    January 31, 2013 - 11:40 am Reply

    Wonderful and detailed explanation along with a practical example. You have covered most of the nitty-gritty of co-routines. Thx.

  • Chris
    February 15, 2013 - 11:16 am Reply

    Is it possible to make a co routine wait until a button is pressed before continuing? I’m attempting to do it at the moment, but with no success. This is what I’ve tried;

    using UnityEngine;
    using System.Collections;

    public class example : MonoBehaviour {
    public bool check = false;

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

    IEnumerator Do() {
    SomethingElse();
    yield return StartCoroutine(Something());
    SomethingElse();
    }

    IEnumerator Something(){
    if (Input.GetButton(“Jump”)){
    check = true;
    }
    while(check == false){
    yield return new WaitForEndOfFrame();
    }
    }

    public void SomethingElse(){
    print(“Run”);
    }

    }

  • fafase
    February 15, 2013 - 8:01 pm Reply

    Hei Chris,

    you can simplify the Something function to this:

    IEnumerator Something(){
    while(!Input.GetKeyDown(KeyCode.Space)){
    yield return null;
    }
    }

    I guess it will do what you are expecting. You should get a first print of Run then a second on pressing Space.
    The idea is that as long as the Input returns false (notice the ! in front of Input) you will yield and get back to it. Once you press, the Input returns true and you jump over the yield and finish the function that returns to the calling function and all is done.

    Fafase

    • Chris
      February 16, 2013 - 8:22 am Reply

      thanks fafase, it worked like a charm :)

  • Kris Kirov
    February 15, 2013 - 8:21 pm Reply

    Kind Sir.
    This tutorial was most welcome !Thank you

  • Karsnen
    May 2, 2013 - 1:04 am Reply

    Amazing tutorials. Overall UnityGems.

    Thanks Mike.

  • Karsnen
    May 11, 2013 - 11:00 pm Reply

    Hello Mike,

    Thank you for your wonderful tutorials. I am extensively using it for my mobile development.
    Being a sole developer, this is just a concern. I am pretty sure there is nothing serious but I wanted to hear it from you.

    I use the easing function library extensively and most of the routines look like this.

    IEnumerator MoveObject(Vector3 Target, float Timer, EasingType ease = EasingType.Sine, Func EasingFunction = null)

    and I call them like this

    StartCoroutine(MoveObject(new Vector3(6,0,0), 10f, EasingType.Sine));

    So is there any worry I should be having as my target is mobile, you know like garbage like and what not. Right now I am replacing updates with routines.

    Thank you.

  • vexe
    June 4, 2013 - 3:22 pm Reply

    I’m not sure what’s the “Hijack” example was all about – could you tell us a bit about it – thanks.

  • Karsnen
    June 5, 2013 - 2:01 pm Reply

    @vexe,

    If you want to pause, stop, resume and play co-routines – you are looking at “Hijack” example.

    It is very useful when you want to have absolute control over co-routines which would help to avoid Update () methods completely.

  • Richard Ellicott
    July 10, 2013 - 1:39 pm Reply

    i am fairly sure i do not require these as I write my own event sequencing and contain most code in large central scripts that control everything

    if for example, you often find code that checks a sequence of events to have a >= time to the current time, you do this each second, well you have you own timing code and you cannot loose threads… i’ll leave unity itself to multitask away all the stuff that is hidden from me.

    so what i have noted is that yes this is clever, but it is easier to loose track of things, why do you need to make an event for 3 seconds in the future and not already have event code etc…this should be reserved for non-game effecting things in my opinion, so say for example graphical particles that have no consequence on gameplay… anything you don’t mind loosing track of.

    but yeah that is my opinion, i may yet be forced to use them for animation, if they can make the code more flexible to different animation timings and stuff that is good

  • Caue Rego
    August 13, 2013 - 3:31 pm Reply

    Two questions:

    1. You say in one note: “this isn’t a problem if you make Start or OnCollisionEnter a coroutine”. What do you mean by “make Start”?! Can we make something like `IEnumerator Start ()` instead of `void Start ()`?

    2. On the video you make 2 kinds of call to IEnumerators (by 16:40):

    yield return StartCoroutine(MoveObject(#whatever parameters#))
    yield return WaitForRealSeconds(0.5f);

    in which `WaitForRealSeconds` is just a wrapper for `Wait`:

    Coroutine WaitForRealSeconds(float time)
    {
    return StartCoroutine(wait(time));
    }

    So, what that Coroutine, right there, exists for? I suppose it is just to show another way of doing the exact same thing, but I never declared a `Coroutine` to test it.

  • whydoidoit
    August 15, 2013 - 10:08 am Reply

    1. Yes you can do exactly that.

    2. Coroutine is the return value of StartCoroutine and is something you can yield.

    I did it both ways because the second way can be easier to read in the source. Also the second method shows you how to return a co routine from a function which is sometimes useful if a function might return more than one possibility.

  • Andy
    August 20, 2013 - 9:49 am Reply

    Hi,

    what i don’t get is how can changing the return type change how Start() is executed? This code inside Start() can only work if Unity now calls Start() via a StartCoroutine(Start())? If i put Test() inside start, the code does not work?

    So is it correct that the default known “messages” like Awake/Start/Ontrigger will be called via StartCoroutine automatically by Unity if the return signature changes to IEnumerator, since i can get this behavior working on any none Unity message function?

    public IEnumerator Start()
    {
    while (true) {
    Debug.Log(“Loop”);
    yield return new WaitForSeconds(1);
    }
    }

    Example1:

    public void Start()
    {
    Test();
    }

    public IEnumerator Test()
    {
    while (true) {
    Debug.Log(“Loop”);
    yield return new WaitForSeconds(1);
    }
    }

    • whydoidoit
      August 20, 2013 - 10:02 am Reply

      Well Unity checks the return type of the method when it goes looking for it on the class. If it’s an IEnumerator it calls StartCoroutine on it and otherwise it just calls it…

      • whydoidoit
        August 20, 2013 - 10:03 am Reply

        Calling Test() like that doesn’t actually add it to the Coroutine list in Unity so nothing happens (note that in JS it does pick it up magically for you).

        Any SendMessage function, OnCollisionXXX, OnTriggerXXX can be coroutines if you declare them as IEnumerator.

        • Andy
          August 20, 2013 - 11:17 am Reply

          So as i suspected, Unity will check for its known functions/messages via reflection and call them as coroutine if the return type is of IEnumerator.

          This explains why so many coroutine examples worked, while i had problems understand why they actually worked, since i first suspected its the c# compiler doing some yield magic, while it was special unity logic.

          Thx for the info

  • haim
    September 24, 2013 - 6:27 pm Reply

    Hi,

    thanks for the info. it’s very helpful.
    i have a question about this:
    what if i created script with coroutine, attach it to object and then instantiate the object
    multiple times in the scene? what should happen then?
    will they effect each other?

  • Nic
    October 2, 2013 - 9:37 am Reply

    I understand that yield return null makes you wait 1 frame and have been using it regularly without spotting any glaring bugs. However, in this particular situation, i think it did not hold the coroutine for 1 frame but rather executed the rest of the code in the coroutine. Here is an example mockup. Pardon me if I made any syntax errors as i just want to deliver the gist.

    public Class ClassA : MonoBehaviour
    {
    public event Action started;

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

    IEnumerator StartA ()
    {
    StartCoroutine (aCoroutine1 ());

    if (started != null)
    started();

    StartCoroutine (aCoroutine2 ());

    yield break;
    }
    }

    public Class ClassB : MonoBehaviour
    {
    public ClassA classA;

    void Start ()
    {
    classA.started += OnClassAStarted;
    }

    void OnClassAStarted ()
    {
    yield return null;

    StartCoroutine (aCoroutine3());
    }
    }

    Is it wrong for me to assume that when the classA instance fires the started event (which passes control to the classB.OnClassAStarted handler), the classB instance will yield for 1 frame and allow classA to execute aCoroutine2 before classB executes aCoroutine3 in the next frame?

    However, based on the Unity debugger, the result I got was the yield return null in the classB instance went straight to starting aCoroutine3 before passing control back to classA instance to run aCoroutine2 (I presume it all happened in the same frame since there is no yielding in StartA(), which was not what I intended or expected.

    • whydoidoit
      October 2, 2013 - 9:44 am Reply

      Well StartA – isn’t actually a coroutine – it all executes immediately because nothing yields.

      OnClassAStarted is not a coroutine (because it couldn’t be as an event) therefore a yield in it shouldn’t even compile.

      if OnClassAStarted did a StartCoroutine on a function that looked like:

      IEnumerator ClassAStarted()
      {
      yield return null;
      StartCoroutine(aCoroutine3());
      }

      Then aCoroutine3 would start on the next frame.

    • Nic
      October 2, 2013 - 10:15 am Reply

      Sorry I did not recreate the thing correctly. What I did was actually what you had suggested. I had called a coroutine in the event handler and expected it to yield but from the unity debugger’s control flow it did not yield but went straight to StartCoroutine(aCoroutine3()).

      p.s. how do I edit my post btw? I only see a reply button.

      void ClassAStarted ()
      {
      StartCoroutine (ClassAStarted());
      }

      IEnumerator ClassAStarted()
      {
      yield return null;
      StartCoroutine(aCoroutine3());
      }

  • Coroutines in Unity | ttlaoc
    October 3, 2013 - 12:30 pm Reply

    […] Unity coroutines (C#) and the yield statement, I have found a very good web where I understood this topic perfectly. The only problem with this web is that some of the contents are in […]

  • Peter
    October 24, 2013 - 11:58 am Reply

    Thanks for explaining coroutines. Your video does make this more clear.

  • Josh
    November 25, 2013 - 3:42 pm Reply

    Why do you add epsilon when calculating the time of the animation? It’s so small, and the check is just a less-than, so I’m not sure what’s happening there.

  • Nezabyte
    March 4, 2014 - 1:03 am Reply

    Thanks for this awesome article! It’s my favorite one for every time I want to refresh my memory on coroutines.

  • Candra
    April 4, 2014 - 1:38 am Reply

    Hello, nice article. I want to ask about WaitForSeconds, is it can be paused? without Time.timescale. In my code below, the Tier1() WaitForSeconds is the one that I need to be paused.

    after search in google I got the _sync() function method, that used for pausing a coroutine, but the WaitForSeconds() process still counting the time when I pause my game.

    can you help me? or is there any method to waiting something that can be paused? I need it to hold my launch variable to become true.

    IEnumerator Tier1()
    {
    //Rocket from bottom
    print(“tier1″);
    SpawnRocket();
    yield return new WaitForSeconds(Random.Range(minTime,maxTime));
    launch = true;
    yield return GM._sync();
    }

    public Coroutine _sync()
    {
    return StartCoroutine(PauseRoutine());
    }

    public IEnumerator PauseRoutine()
    {
    while(pause)
    {
    yield return new WaitForFixedUpdate();
    }
    yield return new WaitForSeconds(0);
    }

    • whydoidoit
      April 4, 2014 - 1:58 am Reply

      So you just need to write your own version of WaitForSeconds (one of the videos covers it I believe), but something like


      public bool pauseWait;
      IEnumerator WaitForSecondsPausable(float numberOfSeconds) {
      var t = 0f;
      while(t < numberOfSeconds) {
      if(!pauseWait) t += Time.deltaTime;
      }
      }

      //Then

      yield return StartCoroutine(WaitForSecondsPausable(Random.Range(minTime, maxTime)));

Leave a Reply