engine/destructibles
PURPOSE — Runtime lifecycle for boss-arena terrain: materializes a pattern’s pillars and hazard zones into the live world at encounter start, removes them at encounter end, applies damage and death state to pillars, ticks hazard-zone overlap damage against the ship, and reaps dead pillars after their death effects play.
OWNS
- Boss-terrain pillar entries (position, radius, current HP, max HP, alive flag, boss-terrain tag, kind discriminator).
- Boss-terrain hazard-zone entries (position, radius, damage-per-second, wall-clock pulse phase, boss-terrain tag, kind discriminator).
- The boss-terrain tag (
_isBossTerrain) used to distinguish this module’s entries from other entries that may share the destructibles array. - Pillar HP bookkeeping and the alive → dead transition.
- Hazard-zone pulse-phase accumulator advanced each tick.
READS FROM
data/terrain-patternsfor the pattern registry, per-pattern destructible specs, and per-pattern hazard-zone specs (radius, HP, damage-per-second, position-resolver callbacks).engine/boss/arenafor the arena reference passed to each spec’s position-resolver callback.- The host world’s destructibles array (read for cull / reap sweeps, read for hazard-zone iteration each tick).
PUSHES TO
- The host world’s destructibles array — appends pillars and hazard zones on apply, splice-removes on cull and reap.
- Caller-supplied damage callback — invoked from the hazard tick with the per-frame overlap damage amount; the caller decides which ship-damage path it lands on.
DOES NOT
- Resolve bullet, contact, or AOE damage onto pillars — callers route hits through the damage entry point with a pre-resolved amount.
- Render pillars, hazard zones, telegraphs, or pulse halos — only writes the state the renderer reads.
- Decide which terrain pattern an encounter uses, define the pattern set, or compute per-pattern positions — those live in
data/terrain-patternsand the boss-encounter layer. - Schedule pattern apply or cull — the boss-encounter layer drives the lifecycle.
- Run hazard-zone overlap on entities other than the ship.
- Award score, drops, or upgrade rolls when a pillar dies.
- Play death VFX, audio, or screen shake when a pillar dies — the cleanup pass assumes those have already happened upstream.
- Pool or recycle entries — apply allocates fresh, cull and reap discard.
Signals fired / Signals watched — none. The module is driven by direct function calls from the boss-encounter layer and the main update loop, and pushes damage back through a caller-supplied callback.
Entry points
applyTerrainPattern— materializes the pattern’s pillars and hazard zones into the world; culls any leftover boss-terrain entries first; no-op for empty patterns.cullTerrainPattern— sweeps every boss-terrain-tagged entry out of the world’s destructibles array; safe when no pattern is active.damageBossPillar— applies an amount of damage to a pillar, flips it to dead when HP hits zero, returns whether this call killed it.tickHazardZones— per-frame: advances each hazard zone’s pulse phase, tests ship overlap, and routes per-frame damage through the supplied callback.reapDeadBossPillars— splice-removes pillars whose alive flag is false; meant to run after death effects.
Pattern notes
- Pillars and hazard zones share the host’s destructibles array and are distinguished from other entries by the
_isBossTerraintag and from each other by akinddiscriminator. Cull and reap walk the array and filter by tag. - Apply is idempotent by construction: it culls existing boss-terrain entries before pushing the new pattern, so callers don’t need to track previous state.
- Cull and reap both use swap-with-last-then-pop while iterating in reverse — entry order is not preserved.
- The hazard tick takes a caller-supplied damage callback rather than knowing about the ship-damage path itself, keeping the module decoupled from combat resolution.
- The host-world contract is intentionally narrow (only the destructibles array) so tests can pass a stripped-down stand-in without standing up a full world state.
- Hazard-zone pulse phase advances on the same dt passed to the tick; the renderer reads it for visual pulsing but the module makes no assumption about which clock (wall vs. game) the caller uses.
- Pillar death is a two-step lifecycle: the damage entry point flips the alive flag in place, and a separate reap pass removes the entry later — mid-frame death is safe.