File size: 4,338 Bytes
12d64f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/**
 * 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;