Restructure player AI from individual to
This commit is contained in:
parent
af1cbf8110
commit
f7cec84973
@ -134,7 +134,7 @@ class Player {
|
||||
|
||||
/**
|
||||
* Main AI decision making system - handles reaction timing, faceoffs, and behavioral switching
|
||||
* Delegates to specific behavior methods based on puck possession
|
||||
* Delegates to specific behavior methods based on team puck possession
|
||||
* @param {Object} gameState - Current game state including faceoff status
|
||||
* @param {Object} puck - Puck object with position and velocity
|
||||
* @param {Array} players - Array of all players on the ice
|
||||
@ -157,22 +157,93 @@ class Player {
|
||||
const teammates = players.filter(p => p.team === this.team && p.id !== this.id);
|
||||
const opponents = players.filter(p => p.team !== this.team);
|
||||
|
||||
if (this.state.hasPuck) {
|
||||
this.behaviorWithPuck(gameState, puck, teammates, opponents);
|
||||
// Determine team possession
|
||||
const teammatePuckCarrier = teammates.find(p => p.state.hasPuck);
|
||||
const opponentPuckCarrier = opponents.find(p => p.state.hasPuck);
|
||||
const myTeamHasPuck = this.state.hasPuck || teammatePuckCarrier;
|
||||
|
||||
if (myTeamHasPuck) {
|
||||
this.behaviorWhenTeamHasPuck(gameState, puck, teammates, opponents, distanceToPuck);
|
||||
} else if (opponentPuckCarrier) {
|
||||
this.behaviorWhenOpponentHasPuck(gameState, puck, teammates, opponents, opponentPuckCarrier);
|
||||
} else {
|
||||
this.behaviorWithoutPuck(gameState, puck, teammates, opponents, distanceToPuck);
|
||||
this.behaviorWhenPuckIsLoose(gameState, puck, teammates, opponents, distanceToPuck);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Offensive AI behavior when player has possession of the puck
|
||||
* AI behavior when this player's team has possession of the puck
|
||||
* Handles both when this player has the puck and when a teammate has it
|
||||
* @param {Object} gameState - Current game state with rink dimensions
|
||||
* @param {Object} puck - Puck object with position and velocity
|
||||
* @param {Array} teammates - Array of teammate player objects
|
||||
* @param {Array} opponents - Array of opposing player objects
|
||||
* @param {number} distanceToPuck - Pre-calculated distance to puck
|
||||
*/
|
||||
behaviorWhenTeamHasPuck(gameState, puck, teammates, opponents, distanceToPuck) {
|
||||
if (this.state.hasPuck) {
|
||||
// This player has the puck - offensive behavior
|
||||
this.offensiveBehaviorWithPuck(gameState, puck, teammates, opponents);
|
||||
} else {
|
||||
// Teammate has the puck - support behavior
|
||||
this.supportOffensiveBehavior(gameState, puck, teammates, opponents);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AI behavior when the opponent team has possession of the puck
|
||||
* All players focus on defensive positioning and pressure
|
||||
* @param {Object} gameState - Current game state
|
||||
* @param {Object} puck - Puck object with position
|
||||
* @param {Array} teammates - Array of teammate player objects
|
||||
* @param {Array} opponents - Array of opposing player objects
|
||||
* @param {Object} opponentPuckCarrier - The opponent player who has the puck
|
||||
*/
|
||||
behaviorWhenOpponentHasPuck(gameState, puck, teammates, opponents, opponentPuckCarrier) {
|
||||
// Check if this player is the closest defender to the puck carrier
|
||||
const isClosestDefender = this.isClosestDefenderToPuckCarrier(opponentPuckCarrier, teammates);
|
||||
|
||||
if (isClosestDefender) {
|
||||
// Closest defender aggressively targets the puck carrier
|
||||
this.moveToPosition(opponentPuckCarrier.position);
|
||||
this.aiState.behavior = 'aggressive_pressure';
|
||||
} else {
|
||||
// Other players position defensively
|
||||
this.defendPosition(gameState, opponentPuckCarrier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AI behavior when the puck is loose (no one has possession)
|
||||
* Players compete to gain control while maintaining team structure
|
||||
* @param {Object} gameState - Current game state
|
||||
* @param {Object} puck - Puck object with position
|
||||
* @param {Array} teammates - Array of teammate player objects
|
||||
* @param {Array} opponents - Array of opposing player objects
|
||||
* @param {number} distanceToPuck - Pre-calculated distance to puck
|
||||
*/
|
||||
behaviorWhenPuckIsLoose(gameState, puck, teammates, opponents, distanceToPuck) {
|
||||
const isClosestToPuck = this.isClosestPlayerToPuck(puck, teammates);
|
||||
const allPlayers = [...teammates, ...opponents, this];
|
||||
|
||||
if (isClosestToPuck && distanceToPuck < 200) {
|
||||
// Only chase if this player is closest to the puck on their team
|
||||
this.chasePuck(puck);
|
||||
} else {
|
||||
// Maintain formation position while puck is contested
|
||||
this.moveToFormationPosition(gameState, puck, allPlayers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Offensive behavior when this specific player has the puck
|
||||
* Prioritizes shooting, then passing under pressure, then advancing toward goal
|
||||
* @param {Object} gameState - Current game state with rink dimensions
|
||||
* @param {Object} puck - Puck object to shoot or pass
|
||||
* @param {Array} teammates - Array of teammate player objects
|
||||
* @param {Array} opponents - Array of opposing player objects
|
||||
*/
|
||||
behaviorWithPuck(gameState, puck, teammates, opponents) {
|
||||
offensiveBehaviorWithPuck(gameState, puck, teammates, opponents) {
|
||||
const enemyGoal = this.team === 'home' ?
|
||||
new Vector2(gameState.rink.width - 50, gameState.rink.centerY) :
|
||||
new Vector2(50, gameState.rink.centerY);
|
||||
@ -203,38 +274,21 @@ class Player {
|
||||
}
|
||||
|
||||
/**
|
||||
* Defensive AI behavior when player doesn't have puck possession
|
||||
* Chooses between chasing loose puck, defending against opponents, or maintaining formation
|
||||
* Support behavior when a teammate has the puck
|
||||
* Positions for passes, creates scoring opportunities, and maintains offensive formation
|
||||
* @param {Object} gameState - Current game state
|
||||
* @param {Object} puck - Puck object with position
|
||||
* @param {Array} teammates - Array of teammate player objects
|
||||
* @param {Array} opponents - Array of opposing player objects
|
||||
* @param {number} distanceToPuck - Pre-calculated distance to puck
|
||||
*/
|
||||
behaviorWithoutPuck(gameState, puck, teammates, opponents, distanceToPuck) {
|
||||
const puckOwner = opponents.find(p => p.state.hasPuck) || teammates.find(p => p.state.hasPuck);
|
||||
const isClosestToPuck = this.isClosestPlayerToPuck(puck, teammates);
|
||||
supportOffensiveBehavior(gameState, puck, teammates, opponents) {
|
||||
const allPlayers = [...teammates, ...opponents, this];
|
||||
const puckCarrier = teammates.find(p => p.state.hasPuck);
|
||||
|
||||
if (!puckOwner && isClosestToPuck && distanceToPuck < 200) {
|
||||
// Only chase if this player is closest to the puck on their team
|
||||
this.chasePuck(puck);
|
||||
} else if (puckOwner && puckOwner.team !== this.team) {
|
||||
// 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);
|
||||
}
|
||||
} else {
|
||||
this.moveToFormationPosition(gameState, puck, allPlayers);
|
||||
}
|
||||
// Move to an offensive formation position that supports the puck carrier
|
||||
const supportPosition = this.getOffensiveSupportPosition(gameState, puck, puckCarrier, opponents);
|
||||
this.moveToPosition(supportPosition);
|
||||
this.aiState.behavior = 'offensive_support';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -392,6 +446,75 @@ class Player {
|
||||
return this.getContextualPosition(rink, side, isAttacking, puck);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates offensive support position when a teammate has the puck
|
||||
* Positions player to receive passes, create scoring chances, and maintain offensive pressure
|
||||
* @param {Object} gameState - Current game state with rink dimensions
|
||||
* @param {Object} puck - Puck object with position
|
||||
* @param {Object} puckCarrier - Teammate who has the puck
|
||||
* @param {Array} opponents - Array of opposing player objects
|
||||
* @returns {Vector2} Calculated offensive support position
|
||||
*/
|
||||
getOffensiveSupportPosition(gameState, puck, puckCarrier, opponents) {
|
||||
const rink = gameState.rink;
|
||||
const enemyGoal = this.team === 'home' ?
|
||||
new Vector2(rink.width - 50, rink.centerY) :
|
||||
new Vector2(50, rink.centerY);
|
||||
|
||||
// Base position is an aggressive offensive formation
|
||||
const side = this.team === 'home' ? 1 : -1;
|
||||
const attackZone = this.team === 'home' ? rink.width * 0.75 : rink.width * 0.25;
|
||||
|
||||
let baseX, baseY;
|
||||
|
||||
switch (this.role) {
|
||||
case 'C':
|
||||
// Center positions for rebounds and passes
|
||||
baseX = attackZone;
|
||||
baseY = rink.centerY + (puck.position.y > rink.centerY ? -60 : 60);
|
||||
break;
|
||||
case 'LW':
|
||||
// Left wing positions for cross-ice passes and wraparounds
|
||||
baseX = attackZone - 30;
|
||||
baseY = rink.centerY - 140;
|
||||
break;
|
||||
case 'RW':
|
||||
// Right wing positions for cross-ice passes and wraparounds
|
||||
baseX = attackZone - 30;
|
||||
baseY = rink.centerY + 140;
|
||||
break;
|
||||
case 'LD':
|
||||
// Left defense supports from the point
|
||||
baseX = attackZone - 120;
|
||||
baseY = rink.centerY - 100;
|
||||
break;
|
||||
case 'RD':
|
||||
// Right defense supports from the point
|
||||
baseX = attackZone - 120;
|
||||
baseY = rink.centerY + 100;
|
||||
break;
|
||||
default:
|
||||
return this.getFormationPosition(gameState, puck, [puckCarrier, ...opponents, this]);
|
||||
}
|
||||
|
||||
// Adjust position to avoid clustering with puck carrier
|
||||
if (puckCarrier) {
|
||||
const distanceToPuckCarrier = new Vector2(baseX, baseY).distance(puckCarrier.position);
|
||||
if (distanceToPuckCarrier < 80) {
|
||||
// Spread out from puck carrier
|
||||
const awayFromCarrier = new Vector2(baseX, baseY).subtract(puckCarrier.position).normalize();
|
||||
baseX += awayFromCarrier.x * 50;
|
||||
baseY += awayFromCarrier.y * 50;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep positions within rink bounds
|
||||
baseX = Math.max(50, Math.min(rink.width - 50, baseX));
|
||||
baseY = Math.max(50, Math.min(rink.height - 50, baseY));
|
||||
|
||||
return new Vector2(baseX, baseY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this player's team is in attacking or defending mode
|
||||
* Based on puck possession and puck location on the rink
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user