Object Pooling

Why the kit can put hundreds of actors on screen, and the four rules for adding your own.

♻️Zero allocation
⏱️6 min read
⚠️4 rules
USKPoolSubsystem · ISKPoolableInterface

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

StepWhat happens
AcquireLooks 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 useThe actor is visible and ticking as normal.
ReleaseThe actor is hidden and returned to the pool, ready to be handed out again.
Hidden is the "available" flag. A pooled actor is never destroyed — hiding it is what marks it free. This is worth knowing because it explains the rules below.

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.

EventWhat to do in it
On Acquire From PoolReset everything about the previous life. The pool has already repositioned and unhidden the actor — you only reset your own state.
On Release To PoolStop 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.

1

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.

2

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.

3

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.

4

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

Where next

Projectiles

The most heavily pooled actors in the kit.

Read →

Spawning & Waves

Pre-warming a wave.

Read →

Core Concepts

How pooling shapes the rest of the kit.

Read →