Is it possible to make a public/static reusable Coroutine?

Hi,

I have a simple selfdestruct coroutine in a script that runs after a delayed amount of time, like this:

    //Coroutine to self destruct in a given time
    IEnumerator DelayedSelfDestruct (float howLong){
        yield return new WaitForSeconds(howLong);
        Destroy(gameObject);
    }

It works fine, when call it from within the same script using StartCoroutine.

I would like to put this into a script of public static functions and reuse it from many different objects’ scripts, but every method I tried does not work.

Is that even possible to have a public static IEnumerator??

public static class SomeUtilityClass
{
    public static IEnumerator DelayedSelfDestruct(GameObject gameObj, float howLong)
    {
        yield return new WaitForSeconds(howLong);
        Destroy(gameObj);
    }
}

// example use from some monobehaviour
private void OnCollisionEnter(Collision other)
{
    StartCoroutine(SomeUtilityClass.DelayedSelfDestruct(gameObject));
}
4 Likes

you can also use extension methods that wrap it all up nicely:

public static class SomeUtilityClass
{

    public static void DelayedSelfDestruct(this MonoBehaviour behaviour, float howLong)
    {
        behaviour.StartCoroutine(DelayedSelfDestruct(behaviour.gameObject, howLong));
    }
   
    public static IEnumerator DelayedSelfDestruct(GameObject go, float howLong)
    {
        yield return new WaitForseconds(howLong);
        UnityEngine.Object.Destroy(go);
    }

}

private void OnCollisionEnter(Collision other)
{
    this.DelayedSelfDestruct(1f);
}
5 Likes

Very nice, thank you so much! I believe I tried Kru’s method, that was the logical and simple way to do it, so I will have to try again if it is possible, something must have been wrong in my code.

Sorry for old bump @lordofduct , but do you wanna explain the this MonoBehaviour behaviour part? If I remove it and run StartCoroutine direcly, it will yell at me, but having a hard time wrapping my head around what it does :). (self learned C# developer so probably missing some fundamental here)

I get that I send in the current MonoBehaviour context using this, but don’t understand why. Ex usage:

public void OnEnemyKilled() {
  SomeUtilityClass.DelayedSelfDestruct(this, 5f);
}

Or as Rider tells me to do using “To extension method invocation”:

public void OnEnemyKilled() {
  this.DelayedSelfDestruct(5f);
}

And this is even more confusing. Where is the reference to SomeUtilityClass here? Will this prevents from having say a public static class Animations and a public static class SomeUtilityClass with the same named methods (like DelayedSelfDestruct inside that class), assuming they are in the same namespace?

(btw there is a small type in WaitForSeconds for you copy pasters out there :p, and the IEnumerator can preferably be made private)

This syntax is called an “Extension method”. It basically makes DelayedSelfDestruct masquerade as if it’s a part of the MonoBehaviour class. As long as you have the namespace that SomeUtilityClass is in, you never have to reference SomeUtilityClass directly - the C# compiler will find it.

This is very popular for utility functions. Many people write extension methods for Vector3, for example, to do operations to Vector3 that are not standard but are common in their game. For example, I was writing a game where characters could walk on walls, so facingDirection.FlattenAlongNormal(groundNormal) was a really convenient operation to have quickly and easily.

The same is true for any class you don’t directly control. It’s just syntactic sugar; the following code is functionally identical (and probably what C# compiles it to under the hood):

public static class SomeUtilityClass
{

    public static void DelayedSelfDestruct(MonoBehaviour behaviour, float howLong)
    {
        behaviour.StartCoroutine(DelayedSelfDestruct(behaviour.gameObject, howLong));
    }
 
    public static IEnumerator DelayedSelfDestruct(GameObject go, float howLong)
    {
        yield return new WaitForSeconds(howLong);
        UnityEngine.Object.Destroy(go);
    }

}

private void OnCollisionEnter(Collision other)
{
    SomeUtilityClass.DelayedSelfDestruct(this, 1f);
}

Feel free to try it - my assumption is that the compiler will give you an “ambiguous reference” error.

3 Likes

Destroy has an overload that takes a time parameter, so while educational, all of this is pointless.

Destroy(gameObject, 5f);
3 Likes

:slight_smile: Yes, true. Though using a manual coroutine has the advantage that you can abort the destruction (as long as you store the Coroutine instance). AFAIK when using the delayed Destroy call you can not prevent the destruction. It’s a fire-and-forget call. Though in most cases that’s all you need ^^.

2 Likes