diff --git a/src/entities/player.js b/src/entities/player.js index 7953ab2..a9ad4f2 100644 --- a/src/entities/player.js +++ b/src/entities/player.js @@ -221,7 +221,14 @@ class Player { // Only chase if this player is closest to the puck on their team this.chasePuck(puck); } else if (puckOwner && puckOwner.team !== this.team) { - if (distanceToPuck < 150 && Math.random() < 0.2) { + // Check if this player is the closest defender to the puck carrier + const isClosestDefender = this.isClosestDefenderToPuckCarrier(puckOwner, teammates); + + if (isClosestDefender) { + // Closest defender aggressively targets the puck carrier + this.moveToPosition(puckOwner.position); + this.aiState.behavior = 'aggressive_pressure'; + } else if (distanceToPuck < 150 && Math.random() < 0.2) { this.checkPlayer(puckOwner); } else { this.defendPosition(gameState, puckOwner); @@ -587,6 +594,36 @@ class Player { return closestPlayer === this; } + /** + * Checks if this player is the closest defender to the puck carrier + * @param {Object} puckCarrier - The player who has the puck + * @param {Array} teammates - Array of teammate player objects + * @returns {boolean} True if this player is closest to puck carrier on their team + */ + isClosestDefenderToPuckCarrier(puckCarrier, teammates) { + // Skip goalies + if (this.role === 'G') return false; + + const myDistance = this.position.distance(puckCarrier.position); + + // Include self in the list to compare against (excluding goalies) + const allTeamPlayers = [this, ...teammates.filter(t => t.role !== 'G')]; + + // Find the closest player to the puck carrier + let closestDistance = Infinity; + let closestPlayer = null; + + allTeamPlayers.forEach(player => { + const distance = player.position.distance(puckCarrier.position); + if (distance < closestDistance) { + closestDistance = distance; + closestPlayer = player; + } + }); + + return closestPlayer === this; + } + /** * Evaluates whether player has a clear shooting angle to goal * Checks if opponents are blocking the direct path to goal diff --git a/src/systems/ai-system.js b/src/systems/ai-system.js index 0a09233..53e63d9 100644 --- a/src/systems/ai-system.js +++ b/src/systems/ai-system.js @@ -176,6 +176,9 @@ class AISystem { const distanceToPuck = player.position.distance(context.puckPosition); const isNearPuck = distanceToPuck < 100; const isClosestToPuck = context.closestPlayers[player.team] === player; + const isClosestDefender = context.puckOwner && + context.puckOwner.team !== player.team && + context.closestPlayers[player.team] === player; if (player.state.hasPuck) { player.aiState.behavior = 'puck_carrier'; @@ -183,6 +186,10 @@ class AISystem { } else if (context.puckOwner && context.puckOwner.team === player.team) { player.aiState.behavior = 'support'; this.executeSupportBehavior(player, context); + } else if (isClosestDefender) { + // Closest defender directly targets the puck carrier + player.aiState.behavior = 'aggressive_pressure'; + this.executeAggressivePressureBehavior(player, context); } else if (context.puckOwner && context.puckOwner.team !== player.team) { player.aiState.behavior = 'pressure'; this.executePressureBehavior(player, context); @@ -221,6 +228,14 @@ class AISystem { player.aiState.action = 'support'; } + executeAggressivePressureBehavior(player, context) { + const opponent = context.puckOwner; + + // Closest defender directly targets the puck carrier's position + player.targetPosition = opponent.position.copy(); + player.aiState.action = 'aggressive_pressure'; + } + executePressureBehavior(player, context) { const opponent = context.puckOwner; const pressurePosition = this.calculatePressurePosition(player, opponent, context);