Add configurable game flow, finish punching, and audio cues
This commit is contained in:
100
miniprogram/game/audio/soundDirector.ts
Normal file
100
miniprogram/game/audio/soundDirector.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { type GameEffect } from '../core/gameResult'
|
||||
|
||||
type SoundKey = 'session-start' | 'start-complete' | 'control-complete' | 'finish-complete' | 'warning'
|
||||
|
||||
const SOUND_SRC: Record<SoundKey, string> = {
|
||||
'session-start': '/assets/sounds/session-start.wav',
|
||||
'start-complete': '/assets/sounds/start-complete.wav',
|
||||
'control-complete': '/assets/sounds/control-complete.wav',
|
||||
'finish-complete': '/assets/sounds/finish-complete.wav',
|
||||
warning: '/assets/sounds/warning.wav',
|
||||
}
|
||||
|
||||
export class SoundDirector {
|
||||
enabled: boolean
|
||||
contexts: Partial<Record<SoundKey, WechatMiniprogram.InnerAudioContext>>
|
||||
|
||||
constructor() {
|
||||
this.enabled = true
|
||||
this.contexts = {}
|
||||
}
|
||||
|
||||
setEnabled(enabled: boolean): void {
|
||||
this.enabled = enabled
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
const keys = Object.keys(this.contexts) as SoundKey[]
|
||||
for (const key of keys) {
|
||||
const context = this.contexts[key]
|
||||
if (!context) {
|
||||
continue
|
||||
}
|
||||
context.stop()
|
||||
context.destroy()
|
||||
}
|
||||
this.contexts = {}
|
||||
}
|
||||
|
||||
handleEffects(effects: GameEffect[]): void {
|
||||
if (!this.enabled || !effects.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const hasFinishCompletion = effects.some((effect) => effect.type === 'control_completed' && effect.controlKind === 'finish')
|
||||
|
||||
for (const effect of effects) {
|
||||
if (effect.type === 'session_started') {
|
||||
this.play('session-start')
|
||||
continue
|
||||
}
|
||||
|
||||
if (effect.type === 'punch_feedback' && effect.tone === 'warning') {
|
||||
this.play('warning')
|
||||
continue
|
||||
}
|
||||
|
||||
if (effect.type === 'control_completed') {
|
||||
if (effect.controlKind === 'start') {
|
||||
this.play('start-complete')
|
||||
continue
|
||||
}
|
||||
|
||||
if (effect.controlKind === 'finish') {
|
||||
this.play('finish-complete')
|
||||
continue
|
||||
}
|
||||
|
||||
this.play('control-complete')
|
||||
continue
|
||||
}
|
||||
|
||||
if (effect.type === 'session_finished' && !hasFinishCompletion) {
|
||||
this.play('finish-complete')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
play(key: SoundKey): void {
|
||||
const context = this.getContext(key)
|
||||
context.stop()
|
||||
context.seek(0)
|
||||
context.play()
|
||||
}
|
||||
|
||||
getContext(key: SoundKey): WechatMiniprogram.InnerAudioContext {
|
||||
const existing = this.contexts[key]
|
||||
if (existing) {
|
||||
return existing
|
||||
}
|
||||
|
||||
const context = wx.createInnerAudioContext()
|
||||
context.src = SOUND_SRC[key]
|
||||
context.autoplay = false
|
||||
context.loop = false
|
||||
context.obeyMuteSwitch = true
|
||||
context.volume = 1
|
||||
this.contexts[key] = context
|
||||
return context
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user