Not a stupid question at all.
Part of the confusion comes from the names we use to represent Coroutines.
IEnumerator represents the code that is run as a Coroutine. This is Unity taking advantage of a feature in C# itself in the IEnumerator.
Coroutine is the wrapper for the Coroutine (see the confusion here?).
All Coroutines are started with the StartCoroutine() method. StartCoroutine() only takes in an IEnumerator as a parameter, but it returns a Coroutine. This return is the handle which we can store to stop a coroutine from running.
Coroutine FadeIn() returns a Coroutine (much like StartCoroutine). It’s not the Coroutine itself (still confusing, I know). Fade(), which FadeIn calls is also a method that returns a Coroutine, but is not a Coroutine itself.
public Coroutine Fade(float target, float time)
{
if (currentActiveFade != null)
{
StopCoroutine(currentActiveFade);
}
currentActiveFade = StartCoroutine(FadeRoutine(target, time));
return currentActiveFade;
}
Fade manages the currentActiveCoroutine, which is really just a reference to (Unity calls it a Wrapper) the actual Coroutine which is started with StartCoroutine(FadeRoutine(target, time));
FadeIn calls Fade, which ends a Coroutine if one is running, and starts a new one with StartCoroutine and returns the result of StartCoroutine.
Now if we used IEnumerator instead of Coroutines our code would look like this:
public IEnumerator FadeOut(float time)
{
yield return Fade(1, time);
}
public IEnumerator FadeIn(float time)
{
yield return Fade(0, time);
}
public IEnumerator Fade(float target, float time)
{
if (currentActiveFade != null)
{
StopCoroutine(currentActiveFade);
}
currentActiveFade = StartCoroutine(FadeRoutine(target, time));
yield return currentActiveFade;
}
In this case, we would actually be adding overhead to our code execution.
Each time we use yield return SomeIEnumerator()
, Unity actually calls StartCoroutine behind the scenes and starts a new Coroutine, adding it to the list.
FadeIn would first be added to Portal’s list of active coroutines. Fader would continue being held as a Coroutine awaiting the end of execution until Fade finished. Fade would also be added to the list of active Coroutines. Finally FadeRoutine would be added to the list of active Coroutines. Fade would not be allowed to finish being evaluated (at the end of each frame, each active Coroutine is evaluated to see if it can run) until FadeRoutine was finished or cancelled.
By using Coroutine instead of IEnumerator, all that is added to the queue of running Coroutines is FadeRoutine, as the rest of the methods will end normally and get out of the way.
I know this section is confusing. It threw me for a loop when Sam first introduced the lecture, and I’ve been coding since the Reagan administration.
Sam put this section in to try to introduce us to some of the under the hood of Coroutines/IEnumerators.
One might be tempted to forego storing the Coroutine and just using StopAllCoroutines in FadeIn and FadeOut keeping them as IEnumerators. The problem with that approach is that it would also stop FadeIn or FadeOut, which is also what we don’t want.