Coroutines
When working in Unity and you find yourself asking the following questions:
- How can I make sure task A finishes before I can do [task B]?
- How do I delay a method by X seconds?
- How can I wait for a condition to be met before continuing?
- How can I wait for a response from a web request?
- How to I prevent locking up the main thread whilst performing a computationally-intensive operation?
This is where Coroutines can help!
What are Coroutines?
Unlike normal C# functions which are executed to completion within a single frame, Coroutines can:
- Pause execution (
yield
) and return control to Unity - Continue execution in the next frame
Syntax
- A Coroutine must return:
IEnumerator
- Within the body, you must have: a
yield
statement - To start a Coroutine:
StartCoroutine(COROUTINE_FUNCTION())
ORStartCoroutine("NAME_OF_COROUTINE")_
How do you Use Coroutines?
How to wait for X seconds:
private void Start()
{
StartCoroutine(TaskA(3));
}
private IEnumerator TaskA(int delay)
{
Debug.Log("Task A started!");
yield return new WaitForSeconds(delay);
Debug.Log("Task A finished after " + delay + "seconds");
}
private void TaskB()
{
Debug.Log("Task B!");
}
Result:
How to run a computationally-intensive operation without locking up the main thread?
private int _counter = 0;
private void Start()
{
StartCoroutine(LongRunningTask());
}
void Update()
{
if(_counter < 20)
{
Debug.Log("_counter: " + _counter);
}
}
private IEnumerator LongRunningTask()
{
// simulate a long running task
while(_counter < 20)
{
_counter++;
// return execution to main thread and
// continue from here next frame
yield return null;
}
}
Result:
- You’ll notice that 1 is printed twice. That’s because:
Start
is called just before the first timeUpdate
is called- When
Update
is called, any previouslyyielded
Coroutines will be processed afterwards
Wait until a condition is met
private IEnumerator WaitUntilCounterIs(int value)
{
yield return new WaitUntil(() => _counter == value);
Debug.Log("Counter is now at: "+ value);
}
Result:
- The Debug.Log will only be called once
_counter
equalsvalue
- The above would be the same performance as running
while(_counter != value)
Considerations
- Coroutines do not run on separate threads, they run on the main thread
- You can stop a Coroutine using
StopCoroutine(name Of Coroutine/reference)
- Where possible, you can use C# Tasks for asynchronous functionality