Example Patterns‎ > ‎

Projectile Self-Destruct

This is an example pattern for something like a projectile or bomb, which should explode when it hits something or after a certain amount of time.

First the code, then some explanation...

(This code has not been tested. Please report any issues found)

public float lifespan = 3  // So you can easily adjust in the inspector

public void OnSpawned()  // Might be able to make this private and still work?
{
// Start the timer as soon as this instance is spawned.
this.StartCoroutine(this.TimedDespawn());
}

private IEnumerator TimedDespawn()
{
// Wait for 'lifespan' (seconds) then despawn this instance.
yield return new WaitForSeconds(this.lifespan);

PoolManager.Pools["Projectiles"].Despawn(this.transform);
}

public void OnTriggerEnter(Collider other)
{
// Despawn if anything is hit
PoolManager.Pools["Projectiles"].Despawn(this.transform);
}

public void OnDespawned()
{
// Handle destruction visuals, like explosions and sending damage
// information to nearby objects
// ...
}

The co-routine is started in OnSpawned(), and handles the timed despawn. This has a big advantage in that if the instance is despawned from any other place (even another script, like a surface-to-air missile) before the timer finishes, the co-routine will automatically stop. You don't have to handle it yourself. This is the Unity behavior for co-routines; they do not survive when the component to which they are attached is disabled.

OnDespawned() will run when the instance is despawned in any way, which makes it a great place to handle generic destruction code. For example, what if you want your projectile to explode whether it hits something or just times out? Put all your explosion stuff in OnDespawned() and this will happen.

This pattern also offers additional flexibility, for example, if you didn't want the instance to despawn when it hits something, in the OnTriggerEnter method, you could stop the co-routine and do other stuff.


As a side note, you would not want to use Despawn(transform, seconds) with this pattern because this PoolManager method runs its own co-routine on the SpawnPool component so it doesn't get interrupted by another Despawn(); which is by design and a good thing most of the time.