A coroutine can be thought of
as being a function that is executed in intervals.
These functions work with special yield statements
which return the code execution out of the function.
Then, when the function continues,
execution begins again, right from where it left off.
Let's take a look at an example coroutine.
To start, let's take a look at the coroutine itself,
which we have called MyCoroutine().
The first thing to notice is its return type, IEnumerator.
This means that the function can return anything
which implements the IEnumerator interface.
There is more to returning from a coroutine
than usual, however, as you will see in a moment.
Next we see that it takes a Transform as a parameter.
We are then starting a While loop, which will
continue until the distance between the object
and the target is less than .05.
Within the loop, we are firstly lerping
the object's position between itself
and the target position.
Then we have the line: "yield return null;".
This is what allows the coroutine to work the way it does.
What this means is that when this line of code is executed,
it will yield execution of the function
and return a null IEnumerator.
The code will resume at this point, at the time
dictated by the return value.
Since the return value is null, that means
the coroutine will resume after the next Update().
Since the coroutine will resume at the end of the loop,
the loop condition will then be re-evaluated.
If the Transform has not reached the target yet,
it will lerp closer to the target,
and again it will yield until the next Update().
Once the loop condition is no longer evaluated to true,
the loop will exit and the coroutine will print,
"Reached the target" to the console.
At that point, the coroutine will yield again,
but this time, it's returning an instance of the WaitForSeconds class.
The constructor is called using the "new" keyword,
and in this case, we're passing in 3 as a parameter.
Predictably, the result of returning an instance
of the WaitForSeconds class is that the code
will continue execution after the given number of seconds.
After three seconds, the words
"MyCoroutine is now finished" are printed to the console.
At that point, we've reached the end of the coroutine
and execution will finish.
Now let's look at how to call a coroutine.
We do so simply with the StartCoroutine() function.
It takes a parameter of either a coroutine call,
or a string of the coroutine's name.
The former call is the one we've shown here,
and is more advisable.
However, if you use a call with a name string,
then you can also call StopCoroutine()
to halt it prematurely.
Now let's see this coroutine in action.
We have attached the coroutine script
to this little robot, and we have created a target object.
When the Scene is run, the robot moves
towards its target, and when the robot
reaches its target, the console displays the message.
Then, three seconds later, the coroutine finishes
with the second message.
Note that we have created movement,
without using Update(), or creating any timers.
This is really excellent, and makes our code more efficient.
However, a real strength of coroutines is
when they are combined with properties.
Let's take a look at an example of that.
In this Scene, we have another robot.
The robot has a PropertiesAndCoroutines script on it.
We also have a script called "Click Set Position"
attached to the environment.
The PropertiesAndCoroutines script
has a public Vector3 property called "target"
that encapsulates the target field.
Remember that when we allocate to the target property,
we call the set function.
The ClickSetPosition script sets the target of an object
with a PropertiesAndCoroutines script on it,
to wherever we click in the environment.
Back on the PropertiesAndCoroutines script,
let's see what happens when the target is set.
First, we set the target field to the correct value,
then we stop any movement coroutines.
It is important to note that StopCoroutine() only works
with coroutines that have been started
by the string call, as we are on the next line.
This is the alternate way of calling StartCoroutine(),
we pass the name of the coroutine as a string,
and then the parameter afterwards.
Our movement coroutine is similar to the MyCoroutine()
from the last example; it simply lerps the Cube's position
towards a given target until it's close.
The effect of having our script set up like this
is that we have a moving GameObect
without the need for an Update() function
that polls for values every frame.
Polling for values is something that reduces
the efficiency of the code we write.
And while we sometimes have to,
it is something we should try to avoid.