Spaces:
Sleeping
Sleeping
| /** | |
| * Sound Manager for RTS Game | |
| * Handles loading and playing sound effects | |
| * | |
| * Features: | |
| * - Async sound loading | |
| * - Volume control | |
| * - Enable/disable toggle | |
| * - Multiple concurrent sounds | |
| * - Fallback for unsupported formats | |
| */ | |
| class SoundManager { | |
| constructor() { | |
| this.sounds = {}; | |
| this.enabled = true; | |
| this.volume = 0.5; | |
| this.loaded = false; | |
| this.audioContext = null; | |
| // Initialize Audio Context (for better browser support) | |
| try { | |
| this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); | |
| } catch (e) { | |
| console.warn('[SoundManager] Web Audio API not supported, using HTML5 Audio fallback'); | |
| } | |
| } | |
| /** | |
| * Load all game sounds | |
| */ | |
| async loadAll() { | |
| console.log('[SoundManager] Loading sounds...'); | |
| const soundFiles = { | |
| 'unit_fire': '/static/sounds/fire.wav', | |
| 'explosion': '/static/sounds/explosion.wav', | |
| 'build_complete': '/static/sounds/build.wav', | |
| 'unit_ready': '/static/sounds/ready.wav', | |
| }; | |
| const loadPromises = Object.entries(soundFiles).map(([name, url]) => | |
| this.loadSound(name, url) | |
| ); | |
| await Promise.all(loadPromises); | |
| this.loaded = true; | |
| console.log(`[SoundManager] Loaded ${Object.keys(this.sounds).length} sounds`); | |
| } | |
| /** | |
| * Load a single sound file | |
| */ | |
| async loadSound(name, url) { | |
| try { | |
| const audio = new Audio(url); | |
| audio.preload = 'auto'; | |
| audio.volume = this.volume; | |
| // Wait for audio to be ready | |
| await new Promise((resolve, reject) => { | |
| audio.addEventListener('canplaythrough', resolve, { once: true }); | |
| audio.addEventListener('error', reject, { once: true }); | |
| audio.load(); | |
| }); | |
| this.sounds[name] = audio; | |
| console.log(`[SoundManager] Loaded: ${name}`); | |
| } catch (e) { | |
| console.warn(`[SoundManager] Failed to load sound: ${name}`, e); | |
| } | |
| } | |
| /** | |
| * Play a sound effect | |
| * @param {string} name - Sound name | |
| * @param {number} volumeMultiplier - Optional volume multiplier (0.0-1.0) | |
| */ | |
| play(name, volumeMultiplier = 1.0) { | |
| if (!this.enabled || !this.loaded || !this.sounds[name]) { | |
| return; | |
| } | |
| try { | |
| // Clone the audio element to allow multiple concurrent plays | |
| const audio = this.sounds[name].cloneNode(); | |
| audio.volume = this.volume * volumeMultiplier; | |
| // Play and auto-cleanup | |
| audio.play().catch(e => { | |
| // Ignore play errors (user interaction required, etc.) | |
| console.debug(`[SoundManager] Play failed: ${name}`, e.message); | |
| }); | |
| // Remove after playing to free memory | |
| audio.addEventListener('ended', () => { | |
| audio.src = ''; | |
| audio.remove(); | |
| }); | |
| } catch (e) { | |
| console.debug(`[SoundManager] Error playing sound: ${name}`, e); | |
| } | |
| } | |
| /** | |
| * Toggle sound on/off | |
| */ | |
| toggle() { | |
| this.enabled = !this.enabled; | |
| console.log(`[SoundManager] Sound ${this.enabled ? 'enabled' : 'disabled'}`); | |
| return this.enabled; | |
| } | |
| /** | |
| * Set volume (0.0 - 1.0) | |
| */ | |
| setVolume(volume) { | |
| this.volume = Math.max(0, Math.min(1, volume)); | |
| // Update volume for all loaded sounds | |
| Object.values(this.sounds).forEach(audio => { | |
| audio.volume = this.volume; | |
| }); | |
| console.log(`[SoundManager] Volume set to ${Math.round(this.volume * 100)}%`); | |
| } | |
| /** | |
| * Check if sounds are loaded | |
| */ | |
| isLoaded() { | |
| return this.loaded; | |
| } | |
| /** | |
| * Get sound status | |
| */ | |
| getStatus() { | |
| return { | |
| enabled: this.enabled, | |
| volume: this.volume, | |
| loaded: this.loaded, | |
| soundCount: Object.keys(this.sounds).length, | |
| }; | |
| } | |
| } | |
| // Export for use in game.js | |
| window.SoundManager = SoundManager; | |