Unity Coroutines – A note to self

As I’ve been working on the Radical Bowling project I’ve found myself using coroutines quite a bit. It seems like every time I have to look up the syntax, so I thought I would write a few quick examples to reference.

Example: Defer by time

In this example I can defer some behavior for the specified time. In this case I destroy the game object.

IEnumerator DestroySelf(float time)
    {
        yield return new WaitForSeconds(time);
        GameObject.Destroy(this.gameObject);
    }

Example: Lerp a value over time

In this example I Lerp the volume of an audio source from it’s starting volume to 0.0f over time.

IEnumerator FadeMusic(float time)
    {
        var audioSource = GetComponent();
        float volume = audioSource.volume;
        float currentTime = 0.0f;

        do
        {
            var newVolume = Mathf.Lerp(volume, 0.0f, currentTime / time);
            audioSource.volume = newVolume;
            currentTime += Time.deltaTime;
            yield return null;
        }
        while (currentTime <= time);
        audioSource.Stop();
    }

There are a lot of other ways that coroutines can be used but these are the two methods I've been using the most. Don't forget to call coroutines with the StartCoroutine() method.

Update: 4/18/2018

It's important to call Coroutines correctly. In my bowling game I created a bug when I made the DestroySelf() function public and called it from another class. Calling a coroutine from another class is supported and often a good idea, but in this case I had code elsewhere on my object that would destroy the game object before the coroutine could execute. Basically it went something like this:

- Step 1: Player throws ball
- Step 2: Ball triggers collider and calls coroutine with 2 second delay
- Step 3: Most of the time the ball rolls off the lane and is destroyed but another method

The issue was Step 2. I added this late last week to try to remove balls that didn't have enough remaining force to actually roll of the lane. I fixed this today by making a public function in the BallController class. I call this from my other class and it is responsible for starting the coroutine. Maybe not the most elegant solution, but this is a demo project after all.


    public void DestroySelf(float time)
    {
        StartCoroutine(_DestroySelf(time));
    }

    private IEnumerator _DestroySelf(float time)
    {
        yield return new WaitForSeconds(time);
        GameObject.Destroy(this.gameObject);
    }

Update: 4/21/2018

This morning I ran into an instance when I needed to cancel a running coroutine. After checking the docs this is what I came up with. A variable named coroutine keeps track of the running instance. I can pass this to StopCoroutine to... stop the coroutine.


    private IEnumerator coroutine;

    public void DestroySelf(float time)
    {
        coroutine = _DestroySelf(time);
        StartCoroutine(coroutine);
    }

    public void AbortDestroySelf()
    {
        if(coroutine != null)
        {
            StopCoroutine(coroutine);
            coroutine = null;
        }
    }

    private IEnumerator _DestroySelf(float time)
    {
        yield return new WaitForSeconds(time);
        GameObject.Destroy(this.gameObject);
    }

You may also like...