diff --git a/CLAUDE.md b/CLAUDE.md index a29f1e0..2a4d4c2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,7 +16,7 @@ This is a client-side JavaScript application that runs directly in the browser: The project uses an **Entity-Component-System (ECS)** pattern with event-driven communication: - **Entities**: `Player` and `Puck` classes represent game objects -- **Systems**: Modular systems handle specific concerns (rendering, physics, AI, rules, audio) +- **Systems**: Modular systems handle specific concerns (rendering, physics, AI, rules) - **Game Engine**: Central orchestrator that manages all systems and entities - **Game State**: Centralized state management for scores, time, penalties, etc. @@ -25,7 +25,7 @@ The application loads scripts in a specific order due to class dependencies: 1. **Utilities**: `vector.js`, `physics.js` (foundational math/physics) 2. **Entities**: `player.js`, `puck.js` (game objects) -3. **Systems**: `renderer.js`, `physics-system.js`, `ai-system.js`, `rules-system.js`, `audio-system.js` +3. **Systems**: `renderer.js`, `physics-system.js`, `ai-system.js`, `rules-system.js` 4. **Engine**: `game-state.js`, `game-engine.js`, `main.js` (orchestration) ### Key Classes and Responsibilities @@ -46,7 +46,6 @@ The engine runs at 60 FPS using `requestAnimationFrame` with these phases: 3. AI decision making 4. Rules enforcement 5. Rendering -6. Audio updates ### Hockey-Specific Features - **12 players** (6 per team) with distinct roles: Center (C), Left/Right Wing (LW/RW), Left/Right Defense (LD/RD), Goalie (G) diff --git a/index.html b/index.html index ea2b1c7..7d70e63 100644 --- a/index.html +++ b/index.html @@ -35,7 +35,6 @@
-
@@ -48,7 +47,6 @@ - diff --git a/src/engine/game-engine.js b/src/engine/game-engine.js index 50cafc4..8800f65 100644 --- a/src/engine/game-engine.js +++ b/src/engine/game-engine.js @@ -3,7 +3,6 @@ class GameEngine { this.canvas = canvas; this.gameState = new GameState(); this.renderer = new Renderer(canvas); - this.audioSystem = new AudioSystem(); this.players = []; this.puck = new Puck(500, 300); @@ -75,7 +74,6 @@ class GameEngine { startTime: Date.now() }); - this.audioSystem.onGoal(data.team); setTimeout(() => { this.startFaceoff(); @@ -90,7 +88,6 @@ class GameEngine { startTime: Date.now() }); - this.audioSystem.onSave(); }); this.gameState.on('penalty', (data) => { @@ -99,11 +96,9 @@ class GameEngine { penalizedPlayer.state.penaltyTime = data.duration; } - this.audioSystem.onPenalty(); }); this.gameState.on('period-end', () => { - this.audioSystem.onPeriodEnd(); }); this.gameState.on('faceoff-start', (data) => { @@ -132,10 +127,6 @@ class GameEngine { e.target.textContent = `Speed: ${speeds[nextIndex]}x`; }); - document.getElementById('sound-toggle').addEventListener('click', (e) => { - const enabled = this.audioSystem.toggle(); - e.target.textContent = `Sound: ${enabled ? 'ON' : 'OFF'}`; - }); document.getElementById('reset-game').addEventListener('click', () => { this.resetGame(); diff --git a/src/systems/audio-system.js b/src/systems/audio-system.js deleted file mode 100644 index 7d0382a..0000000 --- a/src/systems/audio-system.js +++ /dev/null @@ -1,245 +0,0 @@ -class AudioSystem { - constructor() { - this.audioContext = null; - this.sounds = {}; - this.volume = 0.7; - this.enabled = true; - this.initialized = false; - - this.initializeAudio(); - } - - async initializeAudio() { - try { - this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); - this.generateSounds(); - this.initialized = true; - } catch (error) { - console.warn('Audio initialization failed:', error); - this.enabled = false; - } - } - - generateSounds() { - this.sounds = { - puckHit: this.createPuckHitSound(), - stick: this.createStickSound(), - goal: this.createGoalSound(), - save: this.createSaveSound(), - whistle: this.createWhistleSound(), - crowd: this.createCrowdSound(), - skate: this.createSkateSound(), - board: this.createBoardSound() - }; - } - - createPuckHitSound() { - return this.createPercussiveSound(150, 0.1, 'sawtooth'); - } - - createStickSound() { - return this.createPercussiveSound(200, 0.05, 'square'); - } - - createGoalSound() { - return this.createMelodicSound([400, 500, 600], 0.8, 'sine'); - } - - createSaveSound() { - return this.createPercussiveSound(100, 0.3, 'triangle'); - } - - createWhistleSound() { - return this.createMelodicSound([800, 900], 0.5, 'sine'); - } - - createCrowdSound() { - return this.createNoiseSound(0.2, 2.0); - } - - createSkateSound() { - return this.createNoiseSound(0.1, 0.2); - } - - createBoardSound() { - return this.createPercussiveSound(80, 0.2, 'triangle'); - } - - createPercussiveSound(frequency, duration, waveType = 'sine') { - return () => { - if (!this.enabled || !this.audioContext) return; - - const oscillator = this.audioContext.createOscillator(); - const gainNode = this.audioContext.createGain(); - - oscillator.connect(gainNode); - gainNode.connect(this.audioContext.destination); - - oscillator.type = waveType; - oscillator.frequency.setValueAtTime(frequency, this.audioContext.currentTime); - oscillator.frequency.exponentialRampToValueAtTime( - frequency * 0.5, - this.audioContext.currentTime + duration - ); - - gainNode.gain.setValueAtTime(this.volume * 0.3, this.audioContext.currentTime); - gainNode.gain.exponentialRampToValueAtTime( - 0.001, - this.audioContext.currentTime + duration - ); - - oscillator.start(this.audioContext.currentTime); - oscillator.stop(this.audioContext.currentTime + duration); - }; - } - - createMelodicSound(frequencies, duration, waveType = 'sine') { - return () => { - if (!this.enabled || !this.audioContext) return; - - frequencies.forEach((freq, index) => { - const delay = index * 0.1; - const oscillator = this.audioContext.createOscillator(); - const gainNode = this.audioContext.createGain(); - - oscillator.connect(gainNode); - gainNode.connect(this.audioContext.destination); - - oscillator.type = waveType; - oscillator.frequency.setValueAtTime(freq, this.audioContext.currentTime + delay); - - gainNode.gain.setValueAtTime(0, this.audioContext.currentTime + delay); - gainNode.gain.linearRampToValueAtTime( - this.volume * 0.2, - this.audioContext.currentTime + delay + 0.05 - ); - gainNode.gain.exponentialRampToValueAtTime( - 0.001, - this.audioContext.currentTime + delay + duration - ); - - oscillator.start(this.audioContext.currentTime + delay); - oscillator.stop(this.audioContext.currentTime + delay + duration); - }); - }; - } - - createNoiseSound(volume, duration) { - return () => { - if (!this.enabled || !this.audioContext) return; - - const bufferSize = this.audioContext.sampleRate * duration; - const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate); - const data = buffer.getChannelData(0); - - for (let i = 0; i < bufferSize; i++) { - data[i] = (Math.random() * 2 - 1) * volume * this.volume; - } - - const source = this.audioContext.createBufferSource(); - const gainNode = this.audioContext.createGain(); - const filter = this.audioContext.createBiquadFilter(); - - source.buffer = buffer; - source.connect(filter); - filter.connect(gainNode); - gainNode.connect(this.audioContext.destination); - - filter.type = 'lowpass'; - filter.frequency.setValueAtTime(2000, this.audioContext.currentTime); - - gainNode.gain.setValueAtTime(1, this.audioContext.currentTime); - gainNode.gain.exponentialRampToValueAtTime(0.001, this.audioContext.currentTime + duration); - - source.start(this.audioContext.currentTime); - }; - } - - playSound(soundName, volume = 1) { - if (!this.enabled || !this.sounds[soundName]) return; - - try { - if (this.audioContext.state === 'suspended') { - this.audioContext.resume(); - } - this.sounds[soundName](); - } catch (error) { - console.warn('Failed to play sound:', soundName, error); - } - } - - onPuckHit(velocity) { - const intensity = Math.min(1, velocity / 500); - if (intensity > 0.1) { - this.playSound('puckHit', intensity); - } - } - - onStickContact() { - this.playSound('stick'); - } - - onGoal(team) { - this.playSound('goal'); - setTimeout(() => this.playSound('crowd'), 500); - } - - onSave() { - this.playSound('save'); - } - - onPenalty() { - this.playSound('whistle'); - } - - onPeriodEnd() { - this.playSound('whistle'); - } - - onBoardCollision(velocity) { - const intensity = Math.min(1, velocity / 300); - if (intensity > 0.2) { - this.playSound('board', intensity); - } - } - - onPlayerMovement(speed) { - if (speed > 100 && Math.random() < 0.01) { - this.playSound('skate', 0.3); - } - } - - setVolume(volume) { - this.volume = Math.max(0, Math.min(1, volume)); - } - - setEnabled(enabled) { - this.enabled = enabled; - } - - toggle() { - this.enabled = !this.enabled; - return this.enabled; - } - - resume() { - if (this.audioContext && this.audioContext.state === 'suspended') { - return this.audioContext.resume(); - } - } - - suspend() { - if (this.audioContext && this.audioContext.state === 'running') { - return this.audioContext.suspend(); - } - } - - getState() { - return { - enabled: this.enabled, - volume: this.volume, - initialized: this.initialized, - contextState: this.audioContext ? this.audioContext.state : 'not-initialized' - }; - } -} \ No newline at end of file