Home / Legacy / Lesson 7: Introducing Unity 3d Coroutines

Lesson 7: Introducing Unity 3d Coroutines

/
/
/
354 Views
This entry is part 10 of 15 in the series Unity 3d Fundamentals Course

In the previous lesson we made our targets being able to move and rotate. However their behaviour is not very interesting: they start automatically and just loop indefinitely.

In this lesson we will use Unity 3d Coroutines to add a more complex and random behaviour to our targets.

Lesson Outline

Coroutines

This section will provide you the Coroutine basics.

What is a Coroutine?

A Coroutine is a function that allows pausing its own execution and resuming from the exact same point after a condition is met.

What’s the difference between a Coroutine and a “regular” function?

A regular function when called performs all its code until completion within a single frame. So if we want a task to occur over a period of time a regular function won’t work.

Lesson 7: Introducing Unity 3d Coroutines

This first example represents our script Lifecycle with the Start and Update methods. As expected the code inside the Start method only runs once at the beginning of the execution – the first frame. While the code inside the Update method is called on each frame until the end of the script execution. Now take the following example.

Lesson 7: Introducing Unity 3d Coroutines

Now on this second example we are calling a “regular” method from Start. So on the first frame, all code from Start and the SayHello methods are called.

We have the first log from Start – “Hello” – then we execute the function and show its own log – “Hello from a regular method” – and upon completion of the function, we continue to the Start method to call the last one – “Hello again”.

This is how a regular function works. When called the function runs to completion and then the execution continue if necessary. Much like if all code inside the function was brought to the method where it was called, creating a unique sequence of instructions.

Now what a Coroutine is able to do is to pause at a given point allowing the execution to continue and then resume from that point on another given frame.

Lesson 7: Introducing Unity 3d Coroutines

On this example we are also calling a Coroutine from Start. But as you can see its own log is not on the first frame as the others but on the next one. When we called the Coroutine we paused its own execution allowing the Start method to continue and then resumed it on the second frame continuing its execution and showing its own log.

Some of this names that sound strange to you: StartCoroutine, IEnumerator and yield. But basically these are the three essential names you need to use a Coroutine:

  • You need to call the Coroutine with the StartCoroutine method;
  • The Coroutine needs a return type of Ienumerator;
  • You need to include a yield statement inside your method;

I like to use the prefix “Co” on my Coroutines to remember that I need to call them using the StartCoroutine method. If you try to call a Coroutine like a regular function not only it won’t run as also won’t give any error or warning.

Without entering into too much detail about the IEnumerator and the yield statement, they are what allow the Coroutine to pause its current state and resume from that point on the next frame.

The yield statement defines when the Coroutine execution is resumed. In this case by returning 0 we are saying that the Coroutine should continue its execution on the next frame. But there are some more interesting yield statements such as the WaitForSeconds. This one makes the Coroutine continue after a given number of seconds.

Lesson 7: Introducing Unity 3d Coroutines

In this example instead of resuming right away, the Coroutine is scheduled to continue only one second after being paused. So on the following frames the Coroutine is “on hold” waiting for the right time to enter again on the sequence which in this case, considering a 30 fps frame rate, it would continue near the frame 30 (this is not the most technically accurate description but I’m focusing on explaining the concept).

Now this is all very interesting but I want to give you a more practical example. Imagine you want to create a Fade In animation for one of your objects. You can do it by incrementing at runtime the alpha property of the object material colour. However the increment needs to be applied over a certain period of time for the effect to be visible.

Lesson 7: Introducing Unity 3d Coroutines

In this example we are using a regular method to create the effect. We are incrementing the alpha value by 0.2f each time the for cycle completes, taking five cycles to reach the full opacity – 1.

However since we are using a regular method, the for loop will execute on a single frame and the object will become opaque almost instantly. Here we need a Coroutine to extend those changes through a series of frames in order to create the fading effect.

Lesson 7: Introducing Unity 3d Coroutines

Now we have the exact some instructions but inside a Coroutine and we are yielding its execution for 0.2 seconds at the end of each cycle. In this way each time the cycle is paused the execution continues only after 0.2 seconds creating a Fade In effect that prolongs for a full second.

In the previous lesson we used the Update method to move and rotate the targets because that function is called on each frame allowing us to change the object position over time. The same could have been done using a Coroutine. In this example the animation would work also if inside the Update method.

I am keeping this to the basic use of Coroutines. If you want to know more check this great article about Coroutines on Unity Gems.

Change the Target Movement and Rotation

We will introduce some waiting periods each time the target reaches the destination. Instead of looping between both positions without stopping, we will use a Coroutine with the WaitForSeconds yield statement to make it wait for a given time before proceeding.

First declare a public variable to hold how many seconds the target should wait.

Now let’s create our Coroutine.

Now the Coroutine is called whenever the target reaches the destination point. On the current script when the target reaches the destination we are replacing the current destination point for the other. We need to put this code inside the Coroutine body and call the Coroutine instead.

 

 

Now whenever the target reaches the destination it will start the Coroutine, wait for the given time and then proceed to the other point.

But we still have a problem in our script. Since we are calling this from the Update method we need to make sure the Coroutine is only called once or it will be called as long as the target is waiting to move again.

Let’s create a private control variable.

We will use this variable before calling the Coroutine and we need to change its value form inside the Coroutine body.

 

 

Now the target will wait before proceeding to the next point as expected. But I’m still not happy with the result. Let’s add some randomness to these waiting periods.

Instead of using the exact value defined in the waiting seconds variable, I want to use a random value based on the original waiting period. This is a simple way to add a more random behaviour to our targets.

First define a public variable to hold the random factor we will apply.

Now instead of using directly the waiting seconds we need to determine a new value using the random factor. We will use the Random.Range method.

static float Range(float min, float max);

  • returns a float – returns a random number contained inside the range limits;
  • float min – the bottom limit of the range;
  • float max – the upper limit of the range;

The range limits will be defined using the initial waiting seconds value and the random factor.

Now that the Target Movement is ready, apply the same changes to the Target Rotation script.

Of course the target behaviour in a real would be a lot more interesting and complex. The target could move only when up or just change the rotation when not moving or any other combination. However these examples were intended to introduce how to move, rotate and use Coroutines and not to extend into such details.

Full Codes

<TargetMovement>

Names to keep

What’s next…

On the following lessons we will add sounds to our project and also finish our Target Objects by creating a Target Controller and the several prefabs we will need to build our shooting range.

Series Navigation<< Video Add-ons: Fixing the Player WeaponLesson 8: Finishing the Environment >>

5 Comments

    • If you use yield return 0; the coroutine will be executed each frame.
      The coroutine executes each second if you yield return new WaitForSeconds(1);

Leave a Comment

Your email address will not be published. Required fields are marked *