feat: 收敛玩法运行时配置并加入故障恢复

This commit is contained in:
2026-04-01 13:04:26 +08:00
parent 1635a11780
commit 3ef841ecc7
73 changed files with 8820 additions and 2122 deletions

View File

@@ -5,6 +5,7 @@ export type AudioCueKey =
| 'control_completed:finish'
| 'punch_feedback:warning'
| 'guidance:searching'
| 'guidance:distant'
| 'guidance:approaching'
| 'guidance:ready'
@@ -21,7 +22,9 @@ export interface GameAudioConfig {
masterVolume: number
obeyMuteSwitch: boolean
backgroundAudioEnabled: boolean
distantDistanceMeters: number
approachDistanceMeters: number
readyDistanceMeters: number
cues: Record<AudioCueKey, AudioCueConfig>
}
@@ -38,7 +41,9 @@ export interface GameAudioConfigOverrides {
masterVolume?: number
obeyMuteSwitch?: boolean
backgroundAudioEnabled?: boolean
distantDistanceMeters?: number
approachDistanceMeters?: number
readyDistanceMeters?: number
cues?: Partial<Record<AudioCueKey, PartialAudioCueConfig>>
}
@@ -47,7 +52,9 @@ export const DEFAULT_GAME_AUDIO_CONFIG: GameAudioConfig = {
masterVolume: 1,
obeyMuteSwitch: true,
backgroundAudioEnabled: true,
distantDistanceMeters: 80,
approachDistanceMeters: 20,
readyDistanceMeters: 5,
cues: {
session_started: {
src: '/assets/sounds/session-start.wav',
@@ -91,6 +98,13 @@ export const DEFAULT_GAME_AUDIO_CONFIG: GameAudioConfig = {
loopGapMs: 1800,
backgroundMode: 'guidance',
},
'guidance:distant': {
src: '/assets/sounds/guidance-searching.wav',
volume: 0.34,
loop: true,
loopGapMs: 4800,
backgroundMode: 'guidance',
},
'guidance:approaching': {
src: '/assets/sounds/guidance-approaching.wav',
volume: 0.58,
@@ -129,6 +143,7 @@ export function mergeGameAudioConfig(overrides?: GameAudioConfigOverrides | null
'control_completed:finish': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['control_completed:finish'] },
'punch_feedback:warning': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['punch_feedback:warning'] },
'guidance:searching': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['guidance:searching'] },
'guidance:distant': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['guidance:distant'] },
'guidance:approaching': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['guidance:approaching'] },
'guidance:ready': { ...DEFAULT_GAME_AUDIO_CONFIG.cues['guidance:ready'] },
}
@@ -170,7 +185,15 @@ export function mergeGameAudioConfig(overrides?: GameAudioConfigOverrides | null
backgroundAudioEnabled: overrides && overrides.backgroundAudioEnabled !== undefined
? !!overrides.backgroundAudioEnabled
: true,
distantDistanceMeters: clampDistance(
Number(overrides && overrides.distantDistanceMeters),
DEFAULT_GAME_AUDIO_CONFIG.distantDistanceMeters,
),
approachDistanceMeters: clampDistance(Number(overrides && overrides.approachDistanceMeters), DEFAULT_GAME_AUDIO_CONFIG.approachDistanceMeters),
readyDistanceMeters: clampDistance(
Number(overrides && overrides.readyDistanceMeters),
DEFAULT_GAME_AUDIO_CONFIG.readyDistanceMeters,
),
cues,
}
}

View File

@@ -66,6 +66,11 @@ export class SoundDirector {
}
const hasFinishCompletion = effects.some((effect) => effect.type === 'control_completed' && effect.controlKind === 'finish')
if (hasFinishCompletion) {
this.stopGuidanceLoop()
this.play('control_completed:finish')
return
}
for (const effect of effects) {
if (effect.type === 'session_started') {
@@ -85,15 +90,19 @@ export class SoundDirector {
}
if (effect.type === 'guidance_state_changed') {
if (effect.guidanceState === 'searching') {
this.startGuidanceLoop('guidance:searching')
if (effect.guidanceState === 'distant') {
this.startGuidanceLoop('guidance:distant')
continue
}
if (effect.guidanceState === 'approaching') {
this.startGuidanceLoop('guidance:approaching')
continue
}
this.startGuidanceLoop('guidance:ready')
if (effect.guidanceState === 'ready') {
this.startGuidanceLoop('guidance:ready')
continue
}
this.stopGuidanceLoop()
continue
}
@@ -273,6 +282,7 @@ export class SoundDirector {
isGuidanceCue(key: AudioCueKey): boolean {
return key === 'guidance:searching'
|| key === 'guidance:distant'
|| key === 'guidance:approaching'
|| key === 'guidance:ready'
}