monsterplex/src/util/music.js

69 lines
2.7 KiB
JavaScript

// Menu music spans Intro -> MainMenu -> LevelSelect as one continuous bed
// (Phaser's sound manager lives on the game, not the scene, so a Sound
// object started in one scene keeps playing through scene.start() calls
// into the next). Only ONE menu track is active at a time:
// - the main title theme (DEFAULT_KEY) - the default, and what Intro /
// MainMenu always play;
// - a campaign's own theme, if the campaign defines one (musicKey, see
// data/levels/index.js) - LevelSelect switches to it while that
// campaign's map is showing (campaign 2 -> urban-trap-theme) and back
// to the main title for campaigns without one.
// playMenuTrack swaps the active track (stopping the old one); it resumes
// rather than restarts a track that's already active but paused, and no-ops
// if it's already playing. playMenuMusic is the default (main title)
// shorthand the menu scenes call from create().
const DEFAULT_KEY = 'main_title_music';
// The track currently active across the menu scenes (or null if none).
let activeKey = null;
/**
* Makes `key` the active menu track (stopping the current one if it's a
* different key), or resumes it if it's already active but paused. `key`
* defaults to the main title theme, so `playMenuTrack(scene, undefined)`
* and `playMenuMusic(scene)` are equivalent. A key that never loaded
* (missing file / load failure) silently falls back to the main title -
* the same load-tolerant pattern as voiceLine.js.
*/
export function playMenuTrack(scene, key = DEFAULT_KEY) {
if (!scene.cache.audio.exists(key)) key = DEFAULT_KEY;
if (activeKey === key) {
// Already the active track: keep it - resume if it was stopped (e.g. by
// PlayScene), no-op if it's still playing.
const existing = scene.sound.get(key);
if (!existing) {
scene.sound.add(key, { loop: true, volume: 0.5 }).play();
return;
}
if (!existing.isPlaying) existing.play();
return;
}
// Swap: stop the current track, then start (or resume) the new one.
if (activeKey) scene.sound.get(activeKey)?.stop();
activeKey = key;
const existing = scene.sound.get(key);
if (existing) {
existing.play();
return;
}
scene.sound.add(key, { loop: true, volume: 0.5 }).play();
}
// Intro / MainMenu always want the main title theme.
export function playMenuMusic(scene) {
playMenuTrack(scene, DEFAULT_KEY);
}
// PlayScene calls this when gameplay starts: stop WHATEVER menu track is
// active (main title or a campaign theme) and clear the active pointer, so
// the next menu scene's play* call starts its track fresh.
export function stopMenuMusic(scene) {
if (!activeKey) return;
const key = activeKey;
activeKey = null;
scene.sound.get(key)?.stop();
}