Object Pooling
Why the kit can put hundreds of actors on screen, and the four rules for adding your own.
Pooling is why a ShmupKit stage can put hundreds of bullets and dozens of enemies on screen without stuttering. Actors are hidden and reused rather than created and destroyed, so once a stage is running it allocates nothing.
The subsystem exists automatically — there is nothing to place or enable. Projectiles, enemies, pickups, damage numbers and beams are already pooled.
How it works
| Step | What happens |
|---|---|
| Acquire | Looks for a hidden actor of the requested class. If it finds one it repositions it, unhides it and hands it back. If not, it spawns a new one and adds it to the pool. |
| In use | The actor is visible and ticking as normal. |
| Release | The actor is hidden and returned to the pool, ready to be handed out again. |
Pre-warming
The first time a class is acquired it has to be spawned, so a big opening wave can hitch as it creates its actors. Pre Warm creates them up front, during loading, and immediately releases them into the pool.
Wave assets have a Pre Warm Pool option that does this for you. You can also call Pre Warm directly with a class and a count.
Making your own actor poolable
Implement SKPoolableInterface on the Blueprint and handle its two events.
| Event | What to do in it |
|---|---|
| On Acquire From Pool | Reset everything about the previous life. The pool has already repositioned and unhidden the actor — you only reset your own state. |
| On Release To Pool | Stop everything: timers, effects, sounds, ticking. |
The rules
Four things to get right. Every one of them comes from a real bug, and they are the difference between pooling that works and pooling that produces mysterious behaviour an hour later.
Never use Initial Life Span
Unreal's Initial Life Span schedules Destroy() on a timer. On a
pooled actor that tears it out from under the pool — it vanishes mid-flight, and a dead actor is
later handed back out. The pool owns the lifetime. Use the kit's own Lifespan properties, which
release rather than destroy.
Reset every value you write
Anything written during a life must be restored on acquire, or the actor comes back carrying the last life's values. This applies to variables you add in Blueprint just as much as to the kit's own state.
Never trust a stored reference to a pooled actor
Because pooled actors are hidden rather than destroyed, a reference to a "dead" enemy stays valid forever — and that enemy may be alive again somewhere else entirely. Re-validate before using a stored target every time. Pointer validity means nothing here.
Remember a parked actor is inert
Weapons refuse to fire while their owner is hidden, and looping timers must be cleared on release or a parked actor keeps firing them. Disabling an actor's tick does not stop its components.
Symptoms of a pooling mistake
- An actor vanishes mid-flight — Initial Life Span is set on it
- A recycled pickup pays out the wrong reward — a value written last life was never reset
- A missile chases an enemy that is no longer there — a stored reference wasn't re-validated
- Effects are missing on reused actors but fine on fresh ones — the effect isn't restarted on acquire
- Something fires while invisible — a looping timer wasn't cleared on release