Dungeon-crawler background music keeps playing after navigating to another game #744

Closed
opened 2026-07-20 18:46:56 +00:00 by spikerj · 1 comment
Owner

Bug

On https://learn.spikersoft.com/dungeon-crawler, start a game (floor music playing), then navigate via the menu to another route (e.g. the space-game). The dungeon-crawler's looping background music keeps playing over the new page.

Root cause

`DungeonCrawlerComponent.cleanup()` (called from `ngOnDestroy`) disposes the renderer/scene/HUD and disconnects SignalR, but never stops the `AudioSystem`. THREE.Audio plays via WebAudio, which is independent of the component's DOM lifecycle, so the looping floor track (`setLoop(true)`) survives component destruction.

Secondary race: `AudioSystem.loadFloorMusic()` starts playback inside the async `AudioLoader.load` callback — navigating away while a track is still loading would start music after destroy even if `stopAll()` were called in cleanup.

Fix

  • Add `dispose()` to `AudioSystem` that stops+disconnects background music and footsteps and sets a disposed flag guarding the async load callbacks (and `playSound`).
  • Call it from `cleanup()` in `dungeon-crawler.component.ts`.
## Bug On https://learn.spikersoft.com/dungeon-crawler, start a game (floor music playing), then navigate via the menu to another route (e.g. the space-game). The dungeon-crawler's looping background music keeps playing over the new page. ## Root cause \`DungeonCrawlerComponent.cleanup()\` (called from \`ngOnDestroy\`) disposes the renderer/scene/HUD and disconnects SignalR, but never stops the \`AudioSystem\`. THREE.Audio plays via WebAudio, which is independent of the component's DOM lifecycle, so the looping floor track (\`setLoop(true)\`) survives component destruction. Secondary race: \`AudioSystem.loadFloorMusic()\` starts playback inside the async \`AudioLoader.load\` callback — navigating away while a track is still loading would start music *after* destroy even if \`stopAll()\` were called in cleanup. ## Fix - Add \`dispose()\` to \`AudioSystem\` that stops+disconnects background music and footsteps and sets a disposed flag guarding the async load callbacks (and \`playSound\`). - Call it from \`cleanup()\` in \`dungeon-crawler.component.ts\`.
Author
Owner

Resolved in spikersoft-angular PR #473 (merged to master, 0b3bf699). Added AudioSystem.dispose() (stops/disconnects background music + footsteps, disposed flag guards the async AudioLoader callbacks and playSound) and wired it into the dungeon-crawler component's cleanup(). Covered by new audio-system.spec.ts. Closing.

Resolved in spikersoft-angular PR #473 (merged to `master`, 0b3bf699). Added `AudioSystem.dispose()` (stops/disconnects background music + footsteps, `disposed` flag guards the async AudioLoader callbacks and `playSound`) and wired it into the dungeon-crawler component's `cleanup()`. Covered by new `audio-system.spec.ts`. Closing.
Sign in to join this conversation.