tweaked final audio transition

Этот коммит содержится в:
Constantin Rusu 2025-01-14 21:42:37 +00:00
родитель d39044699d
Коммит 0e80eed2f2
5 изменённых файлов: 106 добавлений и 40 удалений

Двоичные данные
public/final-theme.wav Обычный файл

Двоичный файл не отображается.

Просмотреть файл

Просмотреть файл

@ -22,9 +22,15 @@ export const EndGameDialog = ({ onContinue, startFade }: EndGameDialogProps) =>
const [open, setOpen] = useState(true);
const { t } = useTranslation();
const [step, setStep] = useState(0);
const [showButton, setShowButton] = useState(false);
useEffect(() => {
switchToFinalMusic();
// Start final music when dialog appears, with a slight delay to match the fade-in
const timer = setTimeout(() => {
switchToFinalMusic();
}, 800); // Match the dialog's fade-in duration
return () => clearTimeout(timer);
}, []);
const messages = [
@ -33,15 +39,28 @@ export const EndGameDialog = ({ onContinue, startFade }: EndGameDialogProps) =>
t('endGame.message3')
];
const handleNext = () => {
useEffect(() => {
const messageDelay = 4000; // 4 seconds per message
const showButtonDelay = 2000; // 1.5 seconds after last message
let timer: NodeJS.Timeout;
if (step < messages.length - 1) {
setStep(step + 1);
} else {
setOpen(false);
setTimeout(() => {
onContinue();
}, 500);
// Advance to next message
timer = setTimeout(() => setStep(step + 1), messageDelay);
} else if (step === messages.length - 1 && !showButton) {
// Show button after last message
timer = setTimeout(() => setShowButton(true), showButtonDelay);
}
return () => clearTimeout(timer);
}, [step, messages.length, showButton]);
const handleViewReport = () => {
setOpen(false);
setTimeout(() => {
onContinue();
}, 500);
};
return (
@ -84,14 +103,23 @@ export const EndGameDialog = ({ onContinue, startFade }: EndGameDialogProps) =>
</div>
</DialogHeader>
<div className="flex justify-center mt-8">
<Button
onClick={handleNext}
className="bg-emerald-950/20 hover:bg-emerald-950/30 text-emerald-400 border border-emerald-500/50 font-semibold py-6 px-8 text-lg"
>
{step < messages.length - 1 ? t('buttons.continue') : t('buttons.viewReport')}
</Button>
</div>
<AnimatePresence>
{showButton && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="flex justify-center mt-8"
>
<Button
onClick={handleViewReport}
className="bg-emerald-950/20 hover:bg-emerald-950/30 text-emerald-400 border border-emerald-500/50 font-semibold py-6 px-8 text-lg"
>
{t('buttons.viewReport')}
</Button>
</motion.div>
)}
</AnimatePresence>
<div className="absolute -z-10 inset-0 overflow-hidden">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,_var(--tw-gradient-stops))] from-emerald-950/20 via-black/40 to-black/60 animate-pulse-slow"></div>

Просмотреть файл

@ -194,8 +194,11 @@ const Index = () => {
// Start the fade to black and fade out loading overlay
setShowFinalFade(true);
setIsLoading(false);
// Stop the background music here, before the fade completes
stopBackgroundMusic();
// Wait for fade to complete
await new Promise(resolve => setTimeout(resolve, 1500));
// Set game complete after fade is done
setGameComplete(true);
return;
}

Просмотреть файл

@ -36,11 +36,13 @@ export function startBackgroundMusic() {
export function stopBackgroundMusic() {
if (backgroundMusic) {
console.log('Stopping background music');
backgroundMusic.pause();
backgroundMusic.currentTime = 0;
backgroundMusic = null;
}
if (finalMusic) {
console.log('Stopping final music');
finalMusic.pause();
finalMusic.currentTime = 0;
finalMusic = null;
@ -48,31 +50,64 @@ export function stopBackgroundMusic() {
}
export function switchToFinalMusic() {
// Fade out current background music
if (backgroundMusic) {
const fadeOut = setInterval(() => {
if (backgroundMusic && backgroundMusic.volume > 0.05) {
backgroundMusic.volume -= 0.05;
} else {
clearInterval(fadeOut);
stopBackgroundMusic();
// Start final music
finalMusic = new Audio("/final-theme.mp3");
finalMusic.loop = true;
finalMusic.volume = 0;
finalMusic.muted = isMuted;
finalMusic.play().catch(console.error);
// Fade in final music
const fadeIn = setInterval(() => {
if (finalMusic && finalMusic.volume < 0.3) {
finalMusic.volume += 0.05;
} else {
clearInterval(fadeIn);
}
}, 100);
}
}, 100);
// If there's already final music playing, don't start it again
if (finalMusic) {
console.log('Final music already playing, skipping...');
return;
}
console.log('Attempting to switch to final music...');
// Create and prepare the final music track
finalMusic = new Audio("/final-theme.wav");
finalMusic.loop = false;
finalMusic.volume = 0;
finalMusic.muted = isMuted;
// Start playing the final track immediately (it will be silent at first)
finalMusic.play().then(() => {
console.log('Final music started successfully');
// If background music is playing, fade it out while fading in the final music
if (backgroundMusic) {
console.log('Fading transition between tracks...');
const fadeTransition = setInterval(() => {
if (backgroundMusic && backgroundMusic.volume > 0.05) {
backgroundMusic.volume -= 0.05;
}
if (finalMusic && finalMusic.volume < 0.3) {
finalMusic.volume += 0.05;
}
if ((!backgroundMusic || backgroundMusic.volume <= 0.05) &&
(!finalMusic || finalMusic.volume >= 0.3)) {
clearInterval(fadeTransition);
stopBackgroundMusic(); // This will clean up the background track
console.log('Fade transition complete');
}
}, 100);
} else {
// If no background music, just fade in the final track
console.log('Fading in final music...');
const fadeIn = setInterval(() => {
if (!finalMusic) {
clearInterval(fadeIn);
return;
}
if (finalMusic.volume < 0.3) {
finalMusic.volume += 0.05;
} else {
clearInterval(fadeIn);
console.log('Final music fade in complete');
}
}, 100);
}
}).catch(error => {
console.error('Failed to start final music:', error);
});
finalMusic.addEventListener('ended', () => {
console.log('Final music finished playing');
});
}
// Create or get a cached audio element