As per Unity docs, a coroutine is a function that can suspend its execution (yield) until the given YieldInstruction finishes. In other words, coroutines in Unity work like normal functions till they encounter a YieldInstruction. At this point, the coroutine is paused and the control returns to the function which called the coroutine in the first place. Further, the coroutine continues its execution normally after the yield condition is met.
Using the Coroutines in Unity
A coroutine is a function which has a return type of IEnumerator and it includes a yield return statement somewhere in the body. To set a coroutine running, you need to use the StartCoroutine function.
The yield return null line pauses the execution and is resumed in the following frame.
Here is an example of a coroutine that counts down the timer from 60 to 0.
void Start()
{
StartCoroutine("Timer");
}
public int timer = 60;
public IEnumerator Timer()
{
while (timer > 0)
{
yield return new WaitForSeconds(1);
timer--;
}
Debug.Log("Game Over");
yield return null;
}
There are other ways of using the StartCoroutine function:
StartCoroutine(Timer());
or
IEnumerator coroutine = Timer();
StartCoroutine(coroutine);
Note: StartCoroutine is a public method of the MonoBehaviour. Thus, you need a MonoBehaviour class or an object of MonoBehaviour to call a coroutine.
Benefits of Coroutines over update
Coroutines can be used as a way to spread an effect over a period of time, but it is also a useful optimization. We mostly use the Update function to perform periodic tasks. However, this function is called many times per second. You can use a coroutine when you do not need periodic task to repeat every frame. An example of this might be an alarm that warns the player if an enemy is nearby. The code might look something like this:
bool ProximityCheck()
{
for (int i = 0; i < enemies.Length; i++)
{
if(Vector3.Distance(transform.position,enemies[i].transform.position) < dangerDistance)
{
return true;
}
}
return false;
}
If there are a lot of enemies then calling this function every frame might introduce a significant overhead. However, you could use a coroutine to call it every tenth of a second:
IEnumerator DoCheck()
{
while(true)
{
if(ProximityCheck()){
//run... the enemy is near!
}
yield return new WaitForSeconds(.1f);
}
}
This would greatly reduce the number of checks carried out without any noticeable effect on gameplay.
Stopping a coroutine
You can stop a coroutine with StopCoroutine and StopAllCoroutines.
StopCoroutine has three function overloads:
A string function naming the active coroutine
Use this to stop the coroutine which initially started with a string.
StopCoroutine(“Timer”);
The IEnumerator variable used earlier to create the coroutine.
Use this to stop the coroutine which started with IEnumerator as above.
StopCoroutine(coroutine);
The Coroutine to stop the manually created Coroutine.
Use StopCoroutine with the Coroutine used for creation.
i.e., if you have started a coroutine as below:
Coroutine f1 = StartCoroutine(Timer());
you can stop coroutine using
StopCoroutine(f1);
Note: Using StopCoroutine(Timer()); will not stop the coroutine.
Yield Instructions that can be used
WaitForEndOfFrame | Waits until the end of the frame after Unity has rendererd every Camera and GUI, just before displaying the frame on screen. |
WaitForFixedUpdate | Waits until next fixed frame rate update function. |
WaitForSeconds | Suspends the coroutine execution for the given amount of seconds using scaled time. |
WaitForSecondsRealtime | Suspends the coroutine execution for the given amount of seconds using unscaled time. |
WaitUntil | Suspends the coroutine execution until the supplied delegate evaluates to true. |
WaitWhile | Suspends the coroutine execution until the supplied delegate evaluates to false. |
We will learn some interesting facts about Coroutines in the next part.
Happy Coding!