Best Practice for calling a continouus action from e.g. OnTriggerEnter

Hey,

I want to have an object fade to transparency over time when OnTriggerEnter is called.
How do I best achieve this? (I’m using C#)

I have a function Fade() that Lerps the object’s opacity.
Do I:

  • set a bool on OnTriggerEnter, have it checked in Update and then execute Fade() directly from update?
  • create a new Thread and calculate the float without the help of Unity’s Mathf.Lerp
  • make my function Fade() into an IEnumerator Fade() containing a while() loop that yields return null after each run through?

I’m kind of leaning towards the third option, but I’m not sure it is a good idea because I feel like I don’t really understand a lot about Coroutines/ rarely see them used in other people’s scripts. Is there a disadvantage in executing a while loop inside an IEnumerator compared to just calling a function from Update()?

Both are common ways to implement the features.

Update Loop:
You’ll always be running the condition check whether your fading code should still be executed, and this happens throughout the whole time your script is enabled. If that’s only a trivial check as in your case, it’s not a significant overhead at all.

Coroutine:
You might get a little extra garbage, which sounds bad at first, but isn’t a huge overhead either. The code will only be run as long as the coroutine keeps yielding, once it is done, there’s nothing left to process, not even a the ‘should this still be run’-flag in update.

Additional information:
Just like the ‘Start’ method, some other of the engine’s callbacks can be turned into a coroutine, this applies to the trigger and collision callbacks as well:

private IEnumerator OnTriggerEnter(Collider collider)
{
    // do something
    yield return ...
    // do something
}

Keep in mind that you most-likely want to prevent multiple coroutines from running, it’s up to you how you want to handle the situation.

One way to handle this situation could be the following, in which any new coroutine will be signaled to to be removed immediately as long as there is an active one:

private bool _isCoroutineActive = false;
private IEnumerator OnTriggerEnter(Collider collider)
{
    if (_isCoroutineActive)
    {
        // cancel the new routine
        yield break;
    }
    // signal that a rountine is already running
    _isCoroutineActive = true;

    // do something
    yield return null;
    // do something

    // signal that the active routine has finished
    _isCoroutineActive = false;
}

After all, there’s nothing much to worry about. Both are commonly used techniques.
I’m one of the guys that appreciates the concept of coroutines, others do not like them at all.

1 Like

Coroutines are great for simple applications. If the GameObject is only ever going to fade once in one direction, then use a coroutine.

For more sophisticated behaviour use Update.

Another alternative is to call StartCoroutine from inside OnTriggerEnter, which gives you finer control of what coroutine is running.

1 Like