fix(audio): advance tracks on end and avoid consecutive repeats

The audio creation effect had [showIntro, audioElement, playingTrack, musicVol] as deps. Any of those changing (volume slider, track change) triggered the cleanup which removed the ended listener and paused the audio. The if (audioElement) return guard then prevented recreating it, leaving a paused audio with no ended handler so tracks never advanced.

- Narrow creation effect deps to [showIntro] so it runs once and does not tear down on volume or track changes.
- Move the ended listener into its own effect with [audioElement, currentTrack] deps. The handler is re-attached on currentTrack changes and always reads the latest mode; the cleanup removes only the listener, not the audio.
- Update the randomize-on-currentTrack path to use a prev-aware picker so enabling randomize never replays the currently-playing track.
This commit is contained in:
itsRevela
2026-04-17 14:56:21 -05:00
parent 3823c576f9
commit 349ab4baae

View File

@@ -109,20 +109,6 @@ export function useAudioController({ musicVol, sfxVol, showIntro, isGameRunning,
const audio = new Audio(TRACKS[playingTrack]);
audio.volume = musicVol / 100;
const handleEnded = () => {
if (currentTrack === -1) {
// Randomize: pick a different track
setPlayingTrack((prev) => {
let next;
do { next = Math.floor(Math.random() * TRACKS.length); } while (next === prev && TRACKS.length > 1);
return next;
});
} else {
setPlayingTrack((prev) => (prev + 1) % TRACKS.length);
setCurrentTrack((prev) => (prev + 1) % TRACKS.length);
}
};
audio.addEventListener("ended", handleEnded);
const tryPlay = () => {
audio.play().catch((err) => {
@@ -137,19 +123,41 @@ export function useAudioController({ musicVol, sfxVol, showIntro, isGameRunning,
tryPlay();
setAudioElement(audio);
return () => {
audio.removeEventListener("ended", handleEnded);
audio.pause();
}, [showIntro]);
// Attach/re-attach `ended` listener when audio or currentTrack changes, so the
// handler always reads the latest randomize-vs-specific mode.
useEffect(() => {
if (!audioElement) return;
const handleEnded = () => {
if (currentTrack === -1) {
setPlayingTrack((prev) => {
if (TRACKS.length <= 1) return prev;
let next;
do { next = Math.floor(Math.random() * TRACKS.length); } while (next === prev);
return next;
});
} else {
setPlayingTrack((prev) => (prev + 1) % TRACKS.length);
setCurrentTrack((prev) => (prev + 1) % TRACKS.length);
}
};
}, [showIntro, audioElement, playingTrack, musicVol]);
audioElement.addEventListener("ended", handleEnded);
return () => audioElement.removeEventListener("ended", handleEnded);
}, [audioElement, currentTrack]);
// When user selects a specific track, sync playingTrack
useEffect(() => {
if (currentTrack >= 0) {
setPlayingTrack(currentTrack);
} else {
// Randomize: pick a new random track
setPlayingTrack(Math.floor(Math.random() * TRACKS.length));
// Randomize: pick a new random track, avoiding the current one
setPlayingTrack((prev) => {
if (TRACKS.length <= 1) return prev;
let next;
do { next = Math.floor(Math.random() * TRACKS.length); } while (next === prev);
return next;
});
}
}, [currentTrack]);