class DebugSystem {
constructor(gameEngine) {
this.gameEngine = gameEngine;
this.isVisible = false;
this.selectedPlayer = null;
this.updateInterval = null;
this.setupEventListeners();
this.setupGlobalDebugFunctions();
}
setupEventListeners() {
// Debug toggle button
document.getElementById('debug-toggle').addEventListener('click', () => {
this.toggleDebugPanel();
});
// Close debug panel
document.getElementById('debug-close').addEventListener('click', () => {
this.hideDebugPanel();
});
// Canvas click for player selection
this.gameEngine.canvas.addEventListener('click', (e) => {
if (this.isVisible) {
this.handleCanvasClick(e);
}
});
// Monitor debug mode changes (triggered by existing D key handler)
let lastDebugMode = window.debugMode;
setInterval(() => {
if (window.debugMode !== lastDebugMode) {
if (window.debugMode && !this.isVisible) {
this.showDebugPanel();
} else if (!window.debugMode && this.isVisible) {
this.hideDebugPanel();
}
lastDebugMode = window.debugMode;
}
}, 100);
}
toggleDebugPanel() {
if (this.isVisible) {
this.hideDebugPanel();
} else {
this.showDebugPanel();
}
}
showDebugPanel() {
this.isVisible = true;
document.getElementById('debug-panel').classList.remove('hidden');
// Start real-time updates
this.updateInterval = setInterval(() => {
this.updateDebugInfo();
}, 100); // Update 10 times per second
// Initial update
this.updateDebugInfo();
}
hideDebugPanel() {
this.isVisible = false;
document.getElementById('debug-panel').classList.add('hidden');
// Stop real-time updates
if (this.updateInterval) {
clearInterval(this.updateInterval);
this.updateInterval = null;
}
}
handleCanvasClick(e) {
const rect = this.gameEngine.canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// Find closest player to click position
let closestPlayer = null;
let closestDistance = Infinity;
this.gameEngine.players.forEach(player => {
const distance = Math.sqrt(
Math.pow(player.position.x - x, 2) +
Math.pow(player.position.y - y, 2)
);
if (distance < player.radius + 10 && distance < closestDistance) {
closestPlayer = player;
closestDistance = distance;
}
});
if (closestPlayer) {
this.selectPlayer(closestPlayer);
}
}
selectPlayer(player) {
// Remove previous selection styling
document.querySelectorAll('.debug-player').forEach(el => {
el.classList.remove('selected');
});
this.selectedPlayer = player;
// Add selection styling to the clicked player
const playerElement = document.querySelector(`[data-player-id="${player.id}"]`);
if (playerElement) {
playerElement.classList.add('selected');
}
this.updateSelectedPlayerInfo();
}
updateDebugInfo() {
if (!this.isVisible) return;
this.updateGameStateInfo();
this.updatePuckInfo();
this.updatePlayersInfo();
if (this.selectedPlayer) {
this.updateSelectedPlayerInfo();
}
}
updateGameStateInfo() {
const gameState = this.gameEngine.gameState;
const info = `
Period:
${gameState.getPeriodName()}
Time:
${gameState.formatTime(gameState.timeRemaining)}
Score:
${gameState.homeScore} - ${gameState.awayScore}
Paused:
${gameState.isPaused}
Speed:
${gameState.gameSpeed}x
Faceoff Active:
${gameState.faceoff.isActive}
`;
document.getElementById('debug-game-state').innerHTML = info;
}
updatePuckInfo() {
const puck = this.gameEngine.puck;
const info = `
Position:
(${puck.position.x.toFixed(1)}, ${puck.position.y.toFixed(1)})
Velocity:
(${puck.velocity.x.toFixed(1)}, ${puck.velocity.y.toFixed(1)})
Speed:
${puck.getSpeed().toFixed(1)}
Active:
${this.gameEngine.puckActive}
Owner:
${puck.lastTouchedBy || 'None'}
`;
document.getElementById('debug-puck').innerHTML = info;
}
updatePlayersInfo() {
const homePlayers = this.gameEngine.players.filter(p => p.team === 'home');
const awayPlayers = this.gameEngine.players.filter(p => p.team === 'away');
this.renderPlayersList('debug-home-players', homePlayers);
this.renderPlayersList('debug-away-players', awayPlayers);
}
renderPlayersList(containerId, players) {
const container = document.getElementById(containerId);
// Only create elements if they don't exist yet (prevent flickering)
if (container.children.length === 0) {
this.createPlayerElements(container, players);
}
// Update existing elements instead of recreating them
players.forEach((player, index) => {
const playerDiv = container.children[index];
if (!playerDiv) return;
// Update selection state
if (this.selectedPlayer && this.selectedPlayer.id === player.id) {
playerDiv.classList.add('selected');
} else {
playerDiv.classList.remove('selected');
}
// Update dynamic content only
const coordsElement = playerDiv.querySelector('.debug-coords');
const speedElement = playerDiv.querySelector('.debug-speed');
const puckElement = playerDiv.querySelector('.debug-puck');
const behaviorElement = playerDiv.querySelector('.debug-behavior');
if (coordsElement) coordsElement.textContent = `Pos: (${player.position.x.toFixed(0)}, ${player.position.y.toFixed(0)})`;
if (speedElement) speedElement.textContent = player.velocity.magnitude().toFixed(1);
if (puckElement) puckElement.textContent = player.state.hasPuck;
if (behaviorElement) behaviorElement.textContent = player.aiState.behavior;
});
}
createPlayerElements(container, players) {
players.forEach(player => {
const playerDiv = document.createElement('div');
playerDiv.className = 'debug-player';
playerDiv.setAttribute('data-player-id', player.id);
playerDiv.innerHTML = `
Pos: (${player.position.x.toFixed(0)}, ${player.position.y.toFixed(0)})
Speed: ${player.velocity.magnitude().toFixed(1)}
Has Puck: ${player.state.hasPuck}
Behavior: ${player.aiState.behavior}
`;
// Make the entire div clickable with better event handling
playerDiv.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
this.selectPlayer(player);
});
// Add mouse events for better feedback
playerDiv.addEventListener('mouseenter', (e) => {
if (!playerDiv.classList.contains('selected')) {
playerDiv.style.background = 'rgba(255, 255, 255, 0.15)';
}
});
playerDiv.addEventListener('mouseleave', (e) => {
if (!playerDiv.classList.contains('selected')) {
playerDiv.style.background = '';
}
});
playerDiv.addEventListener('mousedown', (e) => {
e.preventDefault();
playerDiv.style.transform = 'scale(0.98)';
});
playerDiv.addEventListener('mouseup', (e) => {
e.preventDefault();
playerDiv.style.transform = '';
});
container.appendChild(playerDiv);
});
}
updateSelectedPlayerInfo() {
if (!this.selectedPlayer) return;
const player = this.selectedPlayer;
const info = `
${player.name} (${player.role})
Team: ${player.team.toUpperCase()}
Position & Physics
Position:
(${player.position.x.toFixed(1)}, ${player.position.y.toFixed(1)})
Velocity:
(${player.velocity.x.toFixed(1)}, ${player.velocity.y.toFixed(1)})
Speed:
${player.velocity.magnitude().toFixed(1)}
Target:
(${player.targetPosition.x.toFixed(1)}, ${player.targetPosition.y.toFixed(1)})
Game State
Has Puck:
${player.state.hasPuck}
Checking:
${player.state.checking}
Injured:
${player.state.injured}
AI State
Behavior:
${player.aiState.behavior}
Target:
${player.aiState.target ? player.aiState.target.constructor.name : 'None'}
Last Action:
${player.aiState.lastAction.toFixed(0)}ms ago
Reaction Time:
${player.aiState.reactionTime.toFixed(0)}ms
Attributes
Speed:
${player.attributes.speed.toFixed(0)}
Shooting:
${player.attributes.shooting.toFixed(0)}
Passing:
${player.attributes.passing.toFixed(0)}
Defense:
${player.attributes.defense.toFixed(0)}
Checking:
${player.attributes.checking.toFixed(0)}
Puck Handling:
${player.attributes.puckHandling.toFixed(0)}
Awareness:
${player.attributes.awareness.toFixed(0)}
`;
document.getElementById('debug-selected-player').innerHTML = info;
}
setupGlobalDebugFunctions() {
// Add global debug helper functions to window object
window.debugHelpers = {
// Get all players
getPlayers: () => this.gameEngine.players,
// Get players by team
getHomeTeam: () => this.gameEngine.players.filter(p => p.team === 'home'),
getAwayTeam: () => this.gameEngine.players.filter(p => p.team === 'away'),
// Get players by position
getPlayersByPosition: (position) => this.gameEngine.players.filter(p => p.role === position),
getGoalies: () => this.gameEngine.players.filter(p => p.role === 'G'),
getDefense: () => this.gameEngine.players.filter(p => p.role === 'LD' || p.role === 'RD'),
getForwards: () => this.gameEngine.players.filter(p => ['LW', 'C', 'RW'].includes(p.role)),
// Get specific player
getPlayer: (id) => this.gameEngine.players.find(p => p.id === id),
// Get puck
getPuck: () => this.gameEngine.puck,
// Get game state
getGameState: () => this.gameEngine.gameState,
// Get player with puck
getPuckCarrier: () => this.gameEngine.players.find(p => p.state.hasPuck),
// Export game state for debugging
exportGameState: () => {
const state = {
gameState: this.gameEngine.gameState.getGameState(),
players: this.gameEngine.players.map(p => ({
id: p.id,
name: p.name,
team: p.team,
role: p.role,
position: { x: p.position.x, y: p.position.y },
velocity: { x: p.velocity.x, y: p.velocity.y },
targetPosition: { x: p.targetPosition.x, y: p.targetPosition.y },
state: { ...p.state },
aiState: { ...p.aiState },
attributes: { ...p.attributes }
})),
puck: {
position: { x: this.gameEngine.puck.position.x, y: this.gameEngine.puck.position.y },
velocity: { x: this.gameEngine.puck.velocity.x, y: this.gameEngine.puck.velocity.y },
speed: this.gameEngine.puck.getSpeed(),
lastTouchedBy: this.gameEngine.puck.lastTouchedBy
}
};
console.log('Game State Export:', state);
return state;
},
// Show debug panel
showDebug: () => this.showDebugPanel(),
// Hide debug panel
hideDebug: () => this.hideDebugPanel()
};
// Log available debug functions
console.log('Debug Helper Functions Available:');
console.log('- debugHelpers.getPlayers() - Get all players');
console.log('- debugHelpers.getHomeTeam() - Get home team players');
console.log('- debugHelpers.getAwayTeam() - Get away team players');
console.log('- debugHelpers.getPlayersByPosition(pos) - Get players by position');
console.log('- debugHelpers.getPlayer(id) - Get specific player by ID');
console.log('- debugHelpers.getPuck() - Get puck object');
console.log('- debugHelpers.getGameState() - Get game state');
console.log('- debugHelpers.getPuckCarrier() - Get player with puck');
console.log('- debugHelpers.exportGameState() - Export full game state');
console.log('- debugHelpers.showDebug() - Show debug panel');
console.log('- debugHelpers.hideDebug() - Hide debug panel');
}
}