Boss Arena Position Helpers
BossArena is a spatial helper layer wrapping a live BossRoom. Affixes, abilities, AI, and spawn profiles route through it so bosses never reference screen size or world coordinates directly. Every spawn position must come from one of: contains / clampPoint / randomPoint / cardinalPoints / ringPoints / edgePoints / oppositePlayer. Spec: docs/superpowers/specs/2026-04-25-bosses-as-enemies-design.md §2.6.
Built by createBossArena(room) in src/starship-survivors/engine/boss/arena.ts.
Arena geometry — cx, cy, radius, bounds
The arena exposes the room’s center as live getters:
arena.cx→room.cxarena.cy→room.cyarena.shape→'circle' | 'rect'
Two footprint sources back the helpers:
- Target footprint (
room.targetR/room.targetW/room.targetH) is used by all spawn-placement helpers —randomPoint,cardinalPoints,ringPoints,edgePoints,radius,diagonal,bounds. Stable while the room is closing so placements don’t drift mid-animation. - Current footprint (
room.currentR/room.currentW/room.currentH) is used bycontainsandclampPoint. Leash + cull check the actual boundary at this instant.
arena.radius() returns target radius (for circle) or min(targetW, targetH) / 2 (for rect). arena.diagonal() returns 2 * targetRadius or hypot(targetW, targetH). arena.bounds() returns {minX, minY, maxX, maxY} from the target footprint.
Ring points — count, fracOfRadius
ringPoints(count, fracOfRadius) returns count positions evenly spaced around a circle of radius targetRadius * fracOfRadius centered on (cx, cy). The first point is at angle 0 (east); subsequent points step by 2π / count clockwise (in screen coords).
const a = (i / count) * Math.PI * 2;
{ x: cx + cos(a) * r, y: cy + sin(a) * r }Returns [] for count <= 0. Ignores shape — always a circle (not perimeter-walking like edgePoints). Use for: ability patterns that spawn projectiles or minions in a ring at a chosen fraction of the arena’s radius (e.g. 0.6 = inner ring, 0.95 = near edge).
Cardinal points — fracOfRadius
cardinalPoints(fracOfRadius) returns exactly four positions: E, S, W, N (in that order), each at targetRadius * fracOfRadius from center. Equivalent to ringPoints(4, fracOfRadius) but iteration order starts east and goes south first. Used by terrain-pattern positionFn and ability patterns that need the four anchor directions (e.g. four-pillar spawn, cardinal-beam attacks).
Edge points — perimeter walk
edgePoints(count) returns count positions evenly spaced along the outer boundary (radius-1, not radius-frac).
- Circle: identical to
ringPoints(count, 1.0). - Rect: walks the perimeter parametrically.
tranges0..perimeterwhereperimeter = 2 * (targetW + targetH). The walk starts top-left corner, goes east along top, south down right side, west along bottom, north up left side.
Used by ability patterns that need wall-hugging spawns (rect arenas) or perimeter rings (circles).
Other helpers used by patterns
randomPoint(margin = 20)— uniform inside the arena. Circle usesr = R * sqrt(u)for uniform disc sampling; rect uses uniform per-axis.clampPoint(x, y, margin = 20)— projects a point inward to stay inside the current boundary minus margin. Used by abilities that compute a candidate spot then need it legalized.contains(x, y)— tests against current footprint. Used by leash + cull, never by spawn placement.oppositePlayer(playerX, playerY, dist)— mirrors the player across center, projects todistfrom center, clamps inside. Used by abilities that telegraph at the spot opposite the player (e.g. AoE the player must run toward).
How patterns compute positions around the boss
Pattern authors never read raw room dims. The flow is:
- Pattern receives
arena: BossArenain its tick/spawn callback. - For symmetric N-point patterns:
arena.ringPoints(n, frac). - For 4-anchor patterns:
arena.cardinalPoints(frac). - For wall/edge patterns:
arena.edgePoints(n). - For random scatter:
arena.randomPoint(margin). - For player-relative anchors:
arena.oppositePlayer(px, py, dist). - Any custom candidate position is run through
arena.clampPointbefore spawning.
DEFAULT_MARGIN = 20 for clampPoint and randomPoint. Patterns wanting tighter or looser packing pass an explicit margin.
Related
gameplay/concepts/boss-room-shapes— circle vs rect rooms, target vs current footprintgameplay/concepts/ability-patterns— pattern authoring conventionsgameplay/concepts/terrain-patterns— terrainpositionFnconsumers