PURPOSE
Builds and tears down the permanent rectangular sealed arena used by mini-boss and boss levels. Unlike the legacy circular BossRoom that spawns large and shrinks over 30s, the sealed arena materializes at its final size already in 'locked' state and never moves. Three confinement layers — per-frame ship clamp in boss-room.ts, four Rapier static cuboid colliders, and visible thick walls — keep the player and entities inside. Wraps existing BossRoom infrastructure so spawnBoss, createBossArena, affixes, and abilities continue to function.
OWNS
spawnSealedArena()— strips biome terrain inside the footprint, constructs a locked rectBossRoom, registers four Rapier wall colliders, and stampsgame._sealedArenaActive = true. Returns theBossRoomfor the caller to assign togame.bossRoom.teardownSealedArena()— clears the arena wall colliders and resetsgame._sealedArenaActivetofalse. Safe to call when no arena is active.sealedArenaPlayerSpawn()— returns the player spawn position at arena center{ x: 0, y: 0 }. Dynamic in case a future caller spawns from a non-origin anchor, but normallybridge.tsresets the ship to origin on level advance.- Internal
destroyTerrainInsideArena(cx, cy, half)— drops terrain and floaters whose centroid sits inside an oversized cull box (half * 1.1) so chunks straddling the wall don’t leave half-pieces clipping inside. Rebuilds terrain chunks when anything is removed, teleports the Rapier ship body to arena center, and clears stray enemy bodies.
READS FROM
ship.x,ship.y— used as the arena center(cx, cy)so the room materializes around the player’s current position.game.time— written intoroom.spawnTime.world.terrain,world.floaters— iterated to find pieces inside the footprint.SEALED_ARENA_HALF_SIZE,SEALED_ARENA_WALL_THICKNESSfrom../../data/level-progression— geometric constants for arena half-extent and wall thickness.RapierWorld.isReady()— gate for all physics work; the function still produces a validBossRoomwhen physics isn’t initialized.
PUSHES TO
game._sealedArenaActive— boolean flag toggled totrueon spawn,falseon teardown so other systems can detect a sealed-arena level.world.terrain— splices removed pieces out in-place.world.floaters— splices removed floaters out in-place.RapierTerrain.addArenaWall(...)— four calls (top/bottom/left/right) registering static cuboid colliders, eachSEALED_ARENA_WALL_THICKNESSthick. Corners overlap by the wall thickness so diagonal knockback can’t squeeze through a gap.RapierTerrain.removePiece(t)/RapierTerrain.removeFloater(f)— per-entity physics cleanup before the array splice.RapierTerrain.clearArenaWalls()— called fromteardownSealedArena.RapierShip.teleportKeepVelocity(cx, cy)— snaps the Rapier ship body to arena center so visual position and physics body agree after terrain is stripped.RapierEnemies.clear()— defensive sweep so any stray boss/enemy bodies from a prior frame are dropped before the new arena starts.buildTerrainChunks(world)— rebuilt only when at least one terrain piece was removed.
DOES NOT
- Does not spawn the boss itself — caller invokes
spawnBossafter assigning the returned room togame.bossRoom. - Does not clear
game.bossRoomorgame.bossArena— that is the caller’s /onBossEncounterEnd’s responsibility. - Does not shrink, move, or animate the arena — the room is created already at its final size in
'locked'state. - Does not enforce the ship-inside-arena clamp itself — that is
updateBossRoominboss-room.ts. - Does not handle the circular
BossRoomshrink path — sealed arenas are alwaysshape: 'rect'. - Does not run any logic if
RapierWorld.isReady()is false beyond skipping physics calls; the returnedBossRoomis still valid.
Signals
game._sealedArenaActiveis the cross-system signal that the current level is a sealed-arena level.- The
BossRoomis returned instate: 'locked'withshape: 'rect',currentW === targetW === SEALED_ARENA_HALF_SIZE * 2, andcurrentR === targetR === SEALED_ARENA_HALF_SIZEso helpers that fall back tomin(W, H) / 2for circle-style queries get a coherent radius.
Entry points
spawnSealedArena()— called by the level-advance flow when starting a mini-boss or boss level. The returnedBossRoomis assigned togame.bossRoom, thenspawnBosswraps it in aBossArena.teardownSealedArena()— called by the level-advance flow after a boss is killed.sealedArenaPlayerSpawn()— called by the level-advance flow to position the ship for the new level.
Pattern notes
- Wall geometry uses
sideHalfLen = half + tso each side extends past the corners by the wall thickness. Combined with the four perpendicular walls, this guarantees no diagonal gap at the corners. - Wall placement: top and bottom walls sit at
cy ± (half + halfThick)with half-extents(sideHalfLen, halfThick); left and right walls sit atcx ± (half + halfThick)with half-extents(halfThick, sideHalfLen). - Cull radius for terrain removal is
half * 1.1— intentionally oversized so chunks whose centroid is just outside the arena but whose geometry crosses the wall are still removed. targetRandcurrentRare set tohalfeven though the shape is rect; this keeps circle-style helpers consistent without a separate branch.- After stripping terrain the ship’s Rapier body is teleported (velocity preserved) to the arena center because the visual
ship.{x,y}and the physics body must agree once the biome around them disappears. RapierEnemies.clear()is defensive — any leftover enemy bodies from the previous level are dropped before the new arena begins.buildTerrainChunksis only rebuilt when terrain was actually removed, avoiding redundant work on empty footprints.