Particle system being garbage collected

I want to spawn explosions when an actor is destroyed. Seems easy, I just give each actor a UParticleSystem* pointer and initialize it in the actor’s constructor with whatever explosion I want for that particular actor. When the actor’s hitpoints reach zero, I call SpawnEmitterAtLocation() and pass in the UParticleSystem* pointer. The emitter is set to auto-destroy, one loop, etc. Mostly, it appears to work correctly.

Problem is that the particle system sometimes gets garbage collected (I think). I’ll have a screen full of explosions and they’ll all just periodically disappear. My guess is that the garbage collector runs, sees that the actor that owned the pointer has been destroyed, and cleans it because there are no remaining pointers to it.

I tried a really hacky solution of forcing the actor to hang around for a few seconds before destroying it, but that has worse problems. For one, each type of explosion might have a different duration, and I don’t know a way in C++ to get an emitter’s duration. For another, doing it this way means I have to play games with making the actor invisible and turning off its collision, etc. Not clean.

Why not use the GameplayStatics instead of keeping a pointer to the Particle System Component on each actor? You can rather store a UParticleSystem* (i.e. not Component) reference on your actors and pass that to UGameplayStatics::SpawnEmitterAtLocation(…).

I might be wrong, but I think this uses the emitter pool so you will possibly gain a large performance benefit as well.

That’s how I do it. Here is the call in my actor’s code:

UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), m_explosion_ps, GetActorLocation(), FRotator::ZeroRotator);
Destroy();

I just found a forum thread where I asked about this nearly two years ago:

There wasn’t a solid answer there, but another user mentioned having the same/similar problem.

I think that I may have to resort to having an “explosion actor.” Just an empty actor with a particle system component. I believe I can use OnSystemFinished to know when the explosion is done and then Destroy() the actor.

This is a heavy workaround and is going to have a performance cost.