class GameEngine { constructor(canvas) { this.canvas = canvas; this.gameState = new GameState(); this.renderer = new Renderer(canvas); this.players = []; this.puck = new Puck(500, 300); this.puckActive = false; // Puck starts inactive for faceoff this.lastTime = 0; this.deltaTime = 0; this.targetFPS = 60; this.frameTime = 1000 / this.targetFPS; this.isRunning = false; this.effects = []; this.setupPlayers(); this.setupEventListeners(); this.setupControls(); // Initialize debug system after all other systems are set up window.debugMode = false; // Initialize debug mode this.debugSystem = new DebugSystem(this); } setupPlayers() { const homeTeamPositions = [ { role: 'G', x: 10, y: 300 }, { role: 'LD', x: 200, y: 220 }, { role: 'RD', x: 200, y: 380 }, { role: 'LW', x: 350, y: 200 }, { role: 'C', x: 400, y: 300 }, { role: 'RW', x: 350, y: 400 } ]; const awayTeamPositions = [ { role: 'G', x: 970, y: 300 }, { role: 'LD', x: 800, y: 220 }, { role: 'RD', x: 800, y: 380 }, { role: 'LW', x: 650, y: 200 }, { role: 'C', x: 600, y: 300 }, { role: 'RW', x: 650, y: 400 } ]; homeTeamPositions.forEach((pos, index) => { const player = new Player( `home_${index}`, `Player ${index + 1}`, 'home', pos.role, pos.x, pos.y ); this.players.push(player); }); awayTeamPositions.forEach((pos, index) => { const player = new Player( `away_${index}`, `Player ${index + 7}`, 'away', pos.role, pos.x, pos.y ); this.players.push(player); }); } setupEventListeners() { this.gameState.on('goal', (data) => { this.addEffect({ type: 'goal', position: this.puck.position.copy(), duration: 2000, startTime: Date.now() }); setTimeout(() => { this.startFaceoff(); }, 2000); }); this.gameState.on('save', (data) => { this.addEffect({ type: 'save', position: this.puck.position.copy(), duration: 1000, startTime: Date.now() }); }); this.gameState.on('period-end', () => { }); this.gameState.on('faceoff-start', (data) => { this.puckActive = false; }); this.gameState.on('faceoff-drop', () => { this.puckActive = true; }); this.gameState.on('faceoff-complete', (data) => { this.puck.faceoffDrop(data.winner, data.location, this.gameState.faceoff.participants); }); } setupControls() { document.getElementById('play-pause').addEventListener('click', () => { this.gameState.togglePause(); }); document.getElementById('speed-control').addEventListener('click', (e) => { const speeds = [0.5, 1, 2, 4]; const currentIndex = speeds.indexOf(this.gameState.gameSpeed); const nextIndex = (currentIndex + 1) % speeds.length; this.gameState.setSpeed(speeds[nextIndex]); e.target.textContent = `Speed: ${speeds[nextIndex]}x`; }); document.getElementById('reset-game').addEventListener('click', () => { this.resetGame(); }); window.addEventListener('keydown', (e) => { switch (e.key) { case ' ': e.preventDefault(); this.gameState.togglePause(); break; case 'd': window.debugMode = !window.debugMode; break; case 'r': this.resetGame(); break; } }); // Zoom controls disabled for fixed camera view } start() { this.isRunning = true; this.lastTime = performance.now(); this.gameLoop(); } stop() { this.isRunning = false; } gameLoop(currentTime = performance.now()) { if (!this.isRunning) return; this.deltaTime = (currentTime - this.lastTime) / 1000; this.lastTime = currentTime; this.deltaTime = Math.min(this.deltaTime, 1/30); this.update(this.deltaTime); this.render(); requestAnimationFrame((time) => this.gameLoop(time)); } update(deltaTime) { if (this.gameState.isPaused) return; this.gameState.updateTime(deltaTime); this.gameState.updateFaceoff(deltaTime); this.players.forEach(player => { player.update(deltaTime, this.gameState, this.puck, this.players); }); if (this.puckActive) { this.puck.update(deltaTime, this.gameState, this.players); this.updateCollisions(); } this.updateEffects(deltaTime); } updateCollisions() { for (let i = 0; i < this.players.length; i++) { for (let j = i + 1; j < this.players.length; j++) { const player1 = this.players[i]; const player2 = this.players[j]; if (Physics.checkCircleCollision( player1.position, player1.radius, player2.position, player2.radius )) { Physics.resolveCircleCollision(player1, player2); if (player1.team !== player2.team && (player1.velocity.magnitude() > 100 || player2.velocity.magnitude() > 100)) { this.handlePlayerCollision(player1, player2); } } } } } handlePlayerCollision(player1, player2) { const speed1 = player1.velocity.magnitude(); const speed2 = player2.velocity.magnitude(); if (speed1 > 150 || speed2 > 150) { this.addEffect({ type: 'hit', position: player1.position.lerp(player2.position, 0.5), duration: 500, startTime: Date.now() }); } } render() { this.renderer.clear(); this.renderer.drawRink(this.gameState); this.renderer.drawPlayers(this.players); if (this.puckActive) { this.renderer.drawPuck(this.puck); } this.renderEffects(); this.renderer.drawUI(this.gameState); const selectedPlayer = this.debugSystem ? this.debugSystem.selectedPlayer : null; this.renderer.drawDebugInfo(this.gameState, this.players, this.puck, selectedPlayer); } renderEffects() { this.effects.forEach(effect => { const elapsed = Date.now() - effect.startTime; const progress = elapsed / effect.duration; if (progress < 1) { this.renderer.drawParticleEffect(effect.position, effect.type); } }); } updateEffects(deltaTime) { this.effects = this.effects.filter(effect => { const elapsed = Date.now() - effect.startTime; return elapsed < effect.duration; }); } addEffect(effect) { this.effects.push(effect); } startFaceoff(location = null) { if (!location) { location = { x: this.gameState.rink.centerX, y: this.gameState.rink.centerY }; } console.log('GameEngine.startFaceoff called with location:', location); // Reset puck position but keep it inactive this.puck.reset(location.x, location.y); this.puckActive = false; // Start the faceoff sequence this.gameState.startFaceoff(location); } resetGame() { this.gameState.reset(); this.effects = []; this.puckActive = false; // Clear all player states first this.players.forEach(player => { player.position = player.homePosition.copy(); player.velocity = new Vector2(0, 0); player.state.hasPuck = false; player.state.energy = 100; player.aiState.lastAction = 0; }); // Reset puck after players this.puck.reset(); // Start faceoff after a short delay setTimeout(() => { this.startFaceoff(); }, 1000); } getGameData() { return { gameState: this.gameState.getGameState(), players: this.players.map(p => ({ id: p.id, name: p.name, team: p.team, position: p.position, role: p.role, state: p.state })), puck: { position: this.puck.position, velocity: this.puck.velocity, speed: this.puck.getSpeed() } }; } loadGameData(data) { // Implementation for loading saved game state // This would restore the game from a saved state } }