Lets Talk Coroutines
What are coroutines?
sudo async
Coroutines Vs Async
Coroutine Basics
public class Coroutines: Monobehaviour
{
public IEnumerator Coroutine()
{
Debug.log("Started");
yield return new WaitForSeconds(5);
Debug.log("5 seconds later!");
}
}
As a loop!
public class Coroutines: Monobehaviour
{
public IEnumerator Coroutine()
{
while(true)
{
yield return null; // DON'T FORGET THIS!!!
}
}
}
Yielding another coroutine
One cool thing we can do inside coroutines is wait on another coroutine to execute before continuing our code. For example
public IEnumerator Interact()
{
// Move close enough to interact with object
// And wait until we're in position to do the interact
yield MoveToPosition(interactPos);
Interact();
}
public IEnumerator MoveToPosition(Vector3 targetPos)
{
while(distanceFromTargetPos > interactRange)
{
MoveCharacter();
yield return null; // DON'T FORGET THIS!!!
}
}
Start as coroutine
Note on yielding
You’ll often see people define the yield points with something like yield return new WaitForSeconds(x);. While this is usually fine, if you’re working in a loop it’s better to predefine you’re waits if you can. For example
public IEnumerator Coroutine()
{
// make one wait
WaitForSeconds wait = new WaitForSeconds(1);
while(true)
{
// yield on that wait
yield return wait;
}
}
Managing coroutines
A lot of the time you can get away with just StartCoroutine() and StopAllCoroutines(), but sometime’s you’ll be having multiple coroutines running on a single object. You’ll want to cancel one of them while leaving the other running, so how do we do that? We can actually store these corutines in a Coroutine variable! StartCoroutine() will return this variable
Coroutine cr = StartCoroutine(CR);
Then when we want to stop it, we just pump it through StopCoroutine()
StopCoroutine(cr);
One of the more common uses I’ve had for this is animation transitions, or some other value, where say we want to run a close animation while the open animation is still playing. IE, we want to stop the open animation and start the close animation.
private Dictionary<Window, Coroutine> windowCRsDict = new();
public void Open(Window window)
{
if(windowCRsDict.TryGet(window, out Coroutine CR))
{
StopCoroutine(CR);
windowsCRsDict.Remove(window);
}
Coroutine openCR = StartCoroutine(Animate(window, true));
windowsCRsDict.Add(window, openCR);
}
public void Close(Window window)
{
if(windowCRsDict.TryGet(window, out Coroutine CR))
{
StopCoroutine(CR);
windowsCRsDict.Remove(window);
}
Coroutine openCR = StartCoroutine(Animate(window, false));
windowsCRsDict.Add(window, openCR);
}
private void Animate(Window window, bool opening)
{
// animate!
yield return null;
// remove the window from the dict, since the animation is finished
// we don't need to run a StopCoroutine because it's just gonna end after this anyway
if(windowsCRsDict.Contains(window))
{
windowsCRsDict.Remove(window);
}
}
Storing IEnumerator object
There is another way of saving/referencing coroutines, . I’ve never used this method myself, but I’m sure you could find a good case for it!
Coroutines and static methods
Yes, you can call coroutines from static classes/methods!
public static class StaticCoroutine
{
}
You just have have a refernce to a monobehavior that’s going to run it.