Quick answer: Call ps.Stop(true, ParticleSystemStopBehavior.StopEmitting) so existing particles can finish, then Destroy after IsAlive(true) goes false. Or set Stop Action = Destroy in the inspector.

A one-shot explosion is destroyed immediately after spawning — players see no particles. Destroying the system kills its alive particles instantly.

Stop Emitting, Let Them Age Out

ps.Stop(true, ParticleSystemStopBehavior.StopEmitting);

IEnumerator DestroyWhenDone()
{
    while (ps.IsAlive(true)) yield return null;
    Destroy(gameObject);
}
StartCoroutine(DestroyWhenDone());

StopEmitting halts new particle spawns but lets existing ones live out their lifetime. IsAlive(true) returns true while any sub-emitter still has particles.

Or Stop Action in the Inspector

Main module → Stop Action = Destroy (or Disable / Callback). Once the system stops and no particles remain, Unity destroys the GameObject for you — no coroutine needed.

Pooling Alternative

For frequent effects, pool the system instead of destroying. Disable when done, re-enable and Play on next use — no allocations, no destroy timing concerns.

Verifying

Explosions play to completion. The GameObject goes away after the last particle dies. No effects cut off mid-burst.

“Stop emitting, wait for IsAlive, then destroy. Or let Stop Action = Destroy do it.”

For looping effects (smoke), you also need to actually call Stop — just destroying mid-loop cuts particles dead too.