Particle Layer
Hs2dParticleLayer wraps a CompositorParticleSystem and feeds it camera-projected emitters. The particle system owns a fixed pool of compositor sprites hosted on an existing sprite layer compositor. Expired particles are hidden and parked offscreen; new emissions reuse inactive pool entries.
Particles are gameplay visuals and should use this fixed pool path. Do not draw particle loops directly to the screen each frame.
When To Use
Use a particle layer for:
| Use | Notes |
|---|---|
| Sparks, fire, explosions, rocket fire, lasers, missiles, camera sparkle, dust | Built-in emitter kinds are defined by NativeRigParticleEmitterKind. |
| Short-lived repeated effects | Use updateEmitters through Hs2dParticleLayer.update. |
| One-shot bursts | Use emitForEmitter with a temporary emitter object. |
Use sprite pools for long-lived projectiles or gameplay actors. Particles are visual effects, not entity ownership.
Construction Pattern
Create a host sprite layer first, then add particles to it:
const foreground = world.addHs2dSpriteLayer({
id: 'foreground',
width: screenWidth,
height: screenHeight,
offscreenX: -1000,
offscreenY: -1000,
});
this.particles = world.addParticleLayer({
id: 'ship-particles',
layer: foreground,
regions: createDefaultCompositorParticleRegions(),
poolSize: 160,
projectionScaleRatio: 1,
});
this.particleEmitters.push({
kind: 'rocketFire',
x: this.shipX,
y: this.shipY + 58,
rateMs: 24,
burstSize: 1,
accumulatorMs: 0,
});
Hs2dLevelScene.updateParticles automatically calls particles.update(deltaMs, this.particleEmitters, activeCamera) when this.particles and a camera are available.
Update, Render, And Compose Behavior
| Phase | Behavior |
|---|---|
| Build | Allocates particle sprite handles in a host sprite layer compositor and hides them. |
| Emitter update | Accumulates emitter time and emits bursts when accumulatorMs >= rateMs. |
| Particle update | Advances age and velocity, changes frame within the particle atlas, moves sprites relative to camera, and deactivates expired particles. |
| Render/compose | The host sprite layer renders and composes the particle sprites. Hs2dParticleLayer is not itself a GameSceneLayer. |
The layer adapts camera scale through projectionScaleRatio, similar to sprite layers.
The default atlas has 16 frames: sparkle 0-3, fire/explosion 4-7, laser/missile 8-11, and dust 12-15.
Performance Notes
- Keep
poolSizefixed and measured. - When the pool is full, new emissions are dropped rather than allocating more sprites.
- Reset optional telemetry counters once per stats window with
resetCounters.onStatsWindow()is compiled out when__TELEMETRY__is disabled, so required state resets belong elsewhere. - Use
clear()on restart or scene reset to hide all active particles. - Keep emitter arrays stable. Mutate emitter positions rather than replacing arrays in the frame loop.
- Use particles for short effects only; use sprite pools for gameplay collisions and ownership.
Code Sample
protected override updateParticles(deltaMs: number): void {
Hs2dParticleLayer.updateRocketEmitters(this.particleEmitters, {
x: this.shipX,
y: this.shipY,
});
super.updateParticles(deltaMs);
this.activeParticles = this.particles?.getStats().activeParticles ?? 0;
}
private emitExplosion(x: number, y: number): void {
this.particles?.emitForEmitter(
{ kind: 'explosion', x, y, rateMs: 1, burstSize: 12, accumulatorMs: 1 },
this.activeCamera,
);
}
Source References
| Source | Why it matters |
|---|---|
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dParticleLayer.ts | Hs2d particle wrapper, projection scale, update, emit, clear, counters, and stats. |
../games/hosanna-ui/src/hosanna-game/particles/CompositorParticleSystem.ts | Fixed particle pool, built-in emitters, emission behavior, movement, frame updates, and offscreen parking. |
../games/hosanna-ui/src/hosanna-game/hosanna2d/Hs2dWorld.ts | addParticleLayer creation and particle stats in world snapshots. |
../games/hosanna-ui/src/hosanna-game/hosanna2d/game/Hs2dLevelScene.ts | Scene-level particleEmitters array and updateParticles hook. |
../hosanna-ui-game-samples-public/src/hosanna-game-examples/native-shoot-em-up/VerticalShooterLevelScene.ts | Gameplay particle creation, rocket emitter updates, one-shot bursts, and stats. |
../hosanna-ui-game-samples-public/src/hosanna-game-examples/diagnostics/ParticleRigController.ts | Standalone particle diagnostic using CompositorParticleSystem directly. |