feat: integrate sound effects into game flow (countdown, answers, performance)
Wire up sound effects to game events: Countdown & Start: - Play countdown beep (0.4 volume) for 3-2-1 - Play race_start fanfare (0.6 volume) on GO! Answer Feedback (matching original logic from web_generator.py): - Streak sound: every 5th correct answer when streak > 0 - Whoosh sound: responses under 800ms (very fast!) - Combo sound: responses under 1200ms when streak >= 3 - Correct sound: regular correct answers - Incorrect sound: wrong answers Sound triggering follows exact original logic (lines 11530-11542, 11589): - Check streak % 5 first - Then check response time < 800ms - Then check response time < 1200ms AND streak >= 3 - Default to regular correct sound 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,9 +3,11 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useComplementRace } from '../context/ComplementRaceContext'
|
||||
import { useGameLoop } from '../hooks/useGameLoop'
|
||||
import { useSoundEffects } from '../hooks/useSoundEffects'
|
||||
|
||||
export function GameCountdown() {
|
||||
const { dispatch } = useComplementRace()
|
||||
const { playSound } = useSoundEffects()
|
||||
const [count, setCount] = useState(3)
|
||||
const [showGo, setShowGo] = useState(false)
|
||||
|
||||
@@ -13,12 +15,14 @@ export function GameCountdown() {
|
||||
const countdownInterval = setInterval(() => {
|
||||
setCount(prevCount => {
|
||||
if (prevCount > 1) {
|
||||
// TODO: Play countdown sound
|
||||
// Play countdown beep (volume 0.4)
|
||||
playSound('countdown', 0.4)
|
||||
return prevCount - 1
|
||||
} else if (prevCount === 1) {
|
||||
// Show GO!
|
||||
setShowGo(true)
|
||||
// TODO: Play start sound
|
||||
// Play race start fanfare (volume 0.6)
|
||||
playSound('race_start', 0.6)
|
||||
return 0
|
||||
}
|
||||
return prevCount
|
||||
@@ -26,7 +30,7 @@ export function GameCountdown() {
|
||||
}, 1000)
|
||||
|
||||
return () => clearInterval(countdownInterval)
|
||||
}, [])
|
||||
}, [playSound])
|
||||
|
||||
useEffect(() => {
|
||||
if (showGo) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useComplementRace } from '../context/ComplementRaceContext'
|
||||
import { useAIRacers } from '../hooks/useAIRacers'
|
||||
import { useAdaptiveDifficulty } from '../hooks/useAdaptiveDifficulty'
|
||||
import { useSteamJourney } from '../hooks/useSteamJourney'
|
||||
import { useSoundEffects } from '../hooks/useSoundEffects'
|
||||
import { LinearTrack } from './RaceTrack/LinearTrack'
|
||||
import { CircularTrack } from './RaceTrack/CircularTrack'
|
||||
import { SteamTrainJourney } from './RaceTrack/SteamTrainJourney'
|
||||
@@ -16,6 +17,7 @@ export function GameDisplay() {
|
||||
useAIRacers() // Activate AI racer updates (not used in sprint mode)
|
||||
const { trackPerformance, getAdaptiveFeedbackMessage } = useAdaptiveDifficulty()
|
||||
const { boostMomentum } = useSteamJourney()
|
||||
const { playSound } = useSoundEffects()
|
||||
|
||||
// Show adaptive feedback with auto-hide
|
||||
useEffect(() => {
|
||||
@@ -66,6 +68,22 @@ export function GameDisplay() {
|
||||
dispatch({ type: 'SUBMIT_ANSWER', answer })
|
||||
trackPerformance(true, responseTime)
|
||||
|
||||
// Play appropriate sound based on performance (from web_generator.py lines 11530-11542)
|
||||
const newStreak = state.streak + 1
|
||||
if (newStreak > 0 && newStreak % 5 === 0) {
|
||||
// Epic streak sound for every 5th correct answer
|
||||
playSound('streak')
|
||||
} else if (responseTime < 800) {
|
||||
// Whoosh sound for very fast responses (under 800ms)
|
||||
playSound('whoosh')
|
||||
} else if (responseTime < 1200 && state.streak >= 3) {
|
||||
// Combo sound for rapid answers while on a streak
|
||||
playSound('combo')
|
||||
} else {
|
||||
// Regular correct sound
|
||||
playSound('correct')
|
||||
}
|
||||
|
||||
// Boost momentum for sprint mode
|
||||
if (state.style === 'sprint') {
|
||||
boostMomentum()
|
||||
@@ -82,6 +100,9 @@ export function GameDisplay() {
|
||||
// Incorrect answer
|
||||
trackPerformance(false, responseTime)
|
||||
|
||||
// Play incorrect sound (from web_generator.py line 11589)
|
||||
playSound('incorrect')
|
||||
|
||||
// Show adaptive feedback
|
||||
const feedback = getAdaptiveFeedbackMessage(pairKey, false, responseTime)
|
||||
if (feedback) {
|
||||
@@ -99,7 +120,7 @@ export function GameDisplay() {
|
||||
|
||||
window.addEventListener('keydown', handleKeyPress)
|
||||
return () => window.removeEventListener('keydown', handleKeyPress)
|
||||
}, [state.currentInput, state.currentQuestion, state.questionStartTime, state.style, dispatch, trackPerformance, getAdaptiveFeedbackMessage, boostMomentum])
|
||||
}, [state.currentInput, state.currentQuestion, state.questionStartTime, state.style, state.streak, dispatch, trackPerformance, getAdaptiveFeedbackMessage, boostMomentum, playSound])
|
||||
|
||||
// Handle route celebration continue
|
||||
const handleContinueToNextRoute = () => {
|
||||
|
||||
Reference in New Issue
Block a user