remove energy mechanism
This commit is contained in:
parent
89b473aecf
commit
4bf182c2a9
@ -2,7 +2,9 @@
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(find:*)",
|
||||
"Bash(node:*)"
|
||||
"Bash(node:*)",
|
||||
"Bash(git add:*)",
|
||||
"Bash(git commit:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
||||
319
PLAYER-AI.md
319
PLAYER-AI.md
@ -1,319 +0,0 @@
|
||||
# Player AI System Documentation
|
||||
|
||||
This document provides a comprehensive overview of the AI decision-making system for hockey players in the game, including detailed flowcharts showing how player states and behaviors are determined.
|
||||
|
||||
## Overview
|
||||
|
||||
The Player AI system uses a sophisticated Entity-Component-System (ECS) pattern with context-aware decision making. Each player has multiple layers of state management:
|
||||
|
||||
- **Physical State**: Position, velocity, energy, puck possession
|
||||
- **AI State**: Current behavior, target, reaction timing
|
||||
- **Game Context**: Team possession, puck location, game situation
|
||||
|
||||
## Core AI Decision Flow
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Player Update Called] --> B{Is Goalie?}
|
||||
B -->|Yes| C[Update Goalie AI]
|
||||
B -->|No| D[Check Reaction Time]
|
||||
D --> E{Reaction Time Met?}
|
||||
E -->|No| F[Skip AI Update]
|
||||
E -->|Yes| G{Is Faceoff Active?}
|
||||
G -->|Yes| H[Handle Faceoff Positioning]
|
||||
G -->|No| I[Determine Puck Possession]
|
||||
I --> J{Who Has Puck?}
|
||||
J -->|My Team| K[Team Has Puck Behavior]
|
||||
J -->|Opponent Team| L[Opponent Has Puck Behavior]
|
||||
J -->|Loose Puck| M[Loose Puck Behavior]
|
||||
|
||||
C --> N[Position in Crease]
|
||||
H --> O[Move to Faceoff Position]
|
||||
K --> P[Offensive Strategy]
|
||||
L --> Q[Defensive Strategy]
|
||||
M --> R[Puck Competition]
|
||||
|
||||
F --> S[End Update]
|
||||
N --> S
|
||||
O --> S
|
||||
P --> S
|
||||
Q --> S
|
||||
R --> S
|
||||
```
|
||||
|
||||
## Team Possession States
|
||||
|
||||
### When Team Has Puck
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Team Has Puck] --> B{Do I Have Puck?}
|
||||
B -->|Yes| C[Offensive Behavior With Puck]
|
||||
B -->|No| D[Support Offensive Behavior]
|
||||
|
||||
C --> E{Distance to Goal < 250?}
|
||||
E -->|Yes| F{Good Shooting Angle?}
|
||||
F -->|Yes| G{Distance < 150 OR Random < 0.5?}
|
||||
G -->|Yes| H[SHOOT]
|
||||
G -->|No| I[Consider Pass]
|
||||
F -->|No| I
|
||||
E -->|No| I
|
||||
|
||||
I --> J{Teammate Closer to Goal?}
|
||||
J -->|Yes| K{Random < 0.7?}
|
||||
K -->|Yes| L[PASS to Closer Teammate]
|
||||
K -->|No| M[Check Pressure]
|
||||
J -->|No| M
|
||||
|
||||
M --> N{Opponent Distance < 100?}
|
||||
N -->|Yes| O{Find Good Pass Target?}
|
||||
O -->|Yes| P{Random < 0.8?}
|
||||
P -->|Yes| Q[PASS to Best Target]
|
||||
P -->|No| R[ADVANCE to Goal]
|
||||
O -->|No| R
|
||||
N -->|No| R
|
||||
|
||||
D --> S[Calculate Support Position]
|
||||
S --> T[Move to Support Position]
|
||||
|
||||
H --> U[End Turn]
|
||||
L --> U
|
||||
Q --> U
|
||||
R --> U
|
||||
T --> U
|
||||
```
|
||||
|
||||
### When Opponent Has Puck
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Opponent Has Puck] --> B{Am I Closest Defender?}
|
||||
B -->|Yes| C[Aggressive Pressure]
|
||||
B -->|No| D[Defensive Positioning]
|
||||
|
||||
C --> E[Target Puck Carrier]
|
||||
C --> F[Set Behavior: aggressive_pressure]
|
||||
|
||||
D --> G[Calculate Defend Position]
|
||||
D --> H[Set Behavior: defending]
|
||||
|
||||
E --> I[End Turn]
|
||||
F --> I
|
||||
G --> I
|
||||
H --> I
|
||||
```
|
||||
|
||||
### When Puck is Loose
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Puck is Loose] --> B{Am I Closest to Puck?}
|
||||
B -->|Yes| C{Distance < 200?}
|
||||
C -->|Yes| D[Chase Puck]
|
||||
C -->|No| E[Formation Position]
|
||||
B -->|No| E
|
||||
|
||||
D --> F[Set Behavior: chasing]
|
||||
E --> G[Calculate Formation Position]
|
||||
E --> H[Set Behavior: formation]
|
||||
|
||||
F --> I[End Turn]
|
||||
G --> I
|
||||
H --> I
|
||||
```
|
||||
|
||||
## Formation System
|
||||
|
||||
### Team State Determination
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Determine Team State] --> B{Does Teammate Have Puck?}
|
||||
B -->|Yes| C[ATTACKING]
|
||||
B -->|No| D{Does Opponent Have Puck?}
|
||||
D -->|Yes| E[DEFENDING]
|
||||
D -->|No| F[Check Puck Location]
|
||||
|
||||
F --> G{Team Side}
|
||||
G -->|Home| H{Puck X > 67% Width?}
|
||||
G -->|Away| I{Puck X < 33% Width?}
|
||||
|
||||
H -->|Yes| C
|
||||
H -->|No| E
|
||||
I -->|Yes| C
|
||||
I -->|No| E
|
||||
```
|
||||
|
||||
### Position Calculation by Role
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Calculate Position] --> B{Team State}
|
||||
B -->|Attacking| C[Attacking Formation]
|
||||
B -->|Defending| D[Defending Formation]
|
||||
|
||||
C --> E{Player Role}
|
||||
E -->|Center| F[Attack Zone, Center Y]
|
||||
E -->|Left Wing| G[Attack Zone - 50, Center Y - 120]
|
||||
E -->|Right Wing| H[Attack Zone - 50, Center Y + 120]
|
||||
E -->|Left Defense| I[Attack Zone - 150, Center Y - 80]
|
||||
E -->|Right Defense| J[Attack Zone - 150, Center Y + 80]
|
||||
|
||||
D --> K{Player Role}
|
||||
K -->|Center| L[Defense Zone, Center Y]
|
||||
K -->|Left Wing| M[Defense Zone + Side*50, Center Y - 100]
|
||||
K -->|Right Wing| N[Defense Zone + Side*50, Center Y + 100]
|
||||
K -->|Left Defense| O[Defense Zone + Side*100, Center Y - 60]
|
||||
K -->|Right Defense| P[Defense Zone + Side*100, Center Y + 60]
|
||||
|
||||
F --> Q[Apply Puck Influence]
|
||||
G --> Q
|
||||
H --> Q
|
||||
I --> Q
|
||||
J --> Q
|
||||
L --> Q
|
||||
M --> Q
|
||||
N --> Q
|
||||
O --> Q
|
||||
P --> Q
|
||||
|
||||
Q --> R[Clamp to Rink Bounds]
|
||||
R --> S[Final Position]
|
||||
```
|
||||
|
||||
## Decision Making Algorithms
|
||||
|
||||
### Pass Target Selection
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Find Best Pass Target] --> B[Loop Through Teammates]
|
||||
B --> C{Distance 50-300?}
|
||||
C -->|No| D[Skip Teammate]
|
||||
C -->|Yes| E[Check Pass Blocking]
|
||||
|
||||
E --> F[Loop Through Opponents]
|
||||
F --> G{Opponent Blocks Pass Line?}
|
||||
G -->|Yes| H[Mark as Blocked]
|
||||
G -->|No| I[Continue Check]
|
||||
|
||||
I --> J{More Opponents?}
|
||||
J -->|Yes| F
|
||||
J -->|No| K{Pass Blocked?}
|
||||
|
||||
K -->|Yes| D
|
||||
K -->|No| L[Calculate Score]
|
||||
L --> M[Score = Skill / Distance]
|
||||
M --> N{Best Score So Far?}
|
||||
N -->|Yes| O[Update Best Target]
|
||||
N -->|No| P[Continue]
|
||||
|
||||
D --> Q{More Teammates?}
|
||||
P --> Q
|
||||
O --> Q
|
||||
Q -->|Yes| B
|
||||
Q -->|No| R[Return Best Target]
|
||||
|
||||
H --> D
|
||||
```
|
||||
|
||||
### Shooting Decision
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Check Shooting Angle] --> B[Calculate Direction to Goal]
|
||||
B --> C[Loop Through Opponents]
|
||||
C --> D{Opponent Distance < 150?}
|
||||
D -->|No| E[Skip Opponent]
|
||||
D -->|Yes| F[Calculate Direction to Opponent]
|
||||
F --> G[Calculate Dot Product]
|
||||
G --> H{Dot > 0.8 AND Distance < 80?}
|
||||
H -->|Yes| I[Shot Blocked]
|
||||
H -->|No| J{More Opponents?}
|
||||
|
||||
E --> J
|
||||
J -->|Yes| C
|
||||
J -->|No| K[Clear Shot]
|
||||
|
||||
I --> L[Return False]
|
||||
K --> M[Return True]
|
||||
```
|
||||
|
||||
## Goalie AI System
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Goalie Update] --> B[Calculate Goal Position]
|
||||
B --> C[Define Crease Area]
|
||||
C --> D{Puck Distance < 80?}
|
||||
D -->|Yes| E[Aggressive Position]
|
||||
D -->|No| F[Standard Position]
|
||||
|
||||
E --> G[Lerp Between Puck and Goal (0.3)]
|
||||
F --> H[Goal + Offset Based on Puck Y]
|
||||
|
||||
G --> I[Clamp to Crease Bounds]
|
||||
H --> I
|
||||
I --> J[Set Target Position]
|
||||
```
|
||||
|
||||
## Faceoff Positioning
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Faceoff Active] --> B{Player Role}
|
||||
B -->|Center| C[Position at Faceoff Dot]
|
||||
B -->|Left Wing| D[Outside Circle + Buffer, Left Side]
|
||||
B -->|Right Wing| E[Outside Circle + Buffer, Right Side]
|
||||
B -->|Left Defense| F[Well Outside, Left Side]
|
||||
B -->|Right Defense| G[Well Outside, Right Side]
|
||||
B -->|Goalie| H[Stay in Net]
|
||||
|
||||
C --> I[Set as Faceoff Participant]
|
||||
D --> J[Legal Position Outside Circle]
|
||||
E --> J
|
||||
F --> J
|
||||
G --> J
|
||||
H --> J
|
||||
|
||||
I --> K[Set Behavior: faceoff]
|
||||
J --> K
|
||||
```
|
||||
|
||||
## AI Behavior States
|
||||
|
||||
The AI system uses several behavior states to track what each player is currently doing:
|
||||
|
||||
- **`aggressive_pressure`**: Actively pursuing the puck carrier
|
||||
- **`defending`**: Positioning defensively between opponent and goal
|
||||
- **`chasing`**: Moving directly toward loose puck
|
||||
- **`formation`**: Moving to calculated formation position
|
||||
- **`offensive_support`**: Supporting teammate with puck
|
||||
- **`checking`**: Performing body check on opponent
|
||||
- **`faceoff`**: Positioned for faceoff situation
|
||||
|
||||
## Key AI Features
|
||||
|
||||
### Reaction Time System
|
||||
- Each player has a unique reaction time (50-150ms)
|
||||
- Prevents all players from reacting simultaneously
|
||||
- Creates more realistic, staggered decision making
|
||||
|
||||
### Energy Management
|
||||
- Energy affects maximum speed
|
||||
- Players with low energy (< 20) move 30% slower
|
||||
- Energy recovers when moving slowly
|
||||
- Creates realistic fatigue simulation
|
||||
|
||||
### Contextual Decision Making
|
||||
- Decisions based on multiple factors: distance, player attributes, game situation
|
||||
- Probabilistic choices add unpredictability
|
||||
- Different strategies for different scenarios
|
||||
|
||||
### Formation Intelligence
|
||||
- Dynamic formations based on puck possession
|
||||
- Role-specific positioning (forwards vs defensemen)
|
||||
- Puck influence affects positioning slightly
|
||||
- Maintains team structure while allowing individual decisions
|
||||
|
||||
This AI system creates realistic hockey gameplay with players that react intelligently to game situations while maintaining team strategy and individual characteristics.
|
||||
@ -289,7 +289,6 @@ class GameEngine {
|
||||
player.position = player.homePosition.copy();
|
||||
player.velocity = new Vector2(0, 0);
|
||||
player.state.hasPuck = false;
|
||||
player.state.energy = 100;
|
||||
player.aiState.lastAction = 0;
|
||||
});
|
||||
|
||||
|
||||
@ -35,7 +35,6 @@ class Player {
|
||||
|
||||
this.state = {
|
||||
hasPuck: false,
|
||||
energy: 100,
|
||||
checking: false,
|
||||
injured: false
|
||||
};
|
||||
@ -53,14 +52,13 @@ class Player {
|
||||
}
|
||||
|
||||
/**
|
||||
* Main update loop for the player - handles energy, movement, rotation, and AI behavior
|
||||
* Main update loop for the player - handles movement, rotation, and AI behavior
|
||||
* @param {number} deltaTime - Time elapsed since last frame in seconds
|
||||
* @param {Object} gameState - Current game state including rink dimensions and game status
|
||||
* @param {Object} puck - Puck object with position and velocity
|
||||
* @param {Array} players - Array of all players on the ice
|
||||
*/
|
||||
update(deltaTime, gameState, puck, players) {
|
||||
this.updateEnergy(deltaTime);
|
||||
this.updateMovement(deltaTime);
|
||||
this.updateAngle(deltaTime);
|
||||
|
||||
@ -71,24 +69,6 @@ class Player {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates player energy/stamina based on movement and provides recovery when stationary
|
||||
* Energy affects max speed - tired players move slower
|
||||
* @param {number} deltaTime - Time elapsed since last frame in seconds
|
||||
*/
|
||||
updateEnergy(deltaTime) {
|
||||
const energyDrain = this.velocity.magnitude() / this.maxSpeed * 10 * deltaTime;
|
||||
this.state.energy = Math.max(0, this.state.energy - energyDrain);
|
||||
|
||||
if (this.state.energy < 20) {
|
||||
this.maxSpeed *= 0.7;
|
||||
}
|
||||
|
||||
if (this.velocity.magnitude() < 50) {
|
||||
this.state.energy = Math.min(100, this.state.energy + 15 * deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates player physics including movement toward target, velocity limits, and collision bounds
|
||||
* Applies acceleration toward target position with deceleration when close
|
||||
@ -106,8 +86,7 @@ class Player {
|
||||
this.velocity = this.velocity.multiply(0.8);
|
||||
}
|
||||
|
||||
const speedMultiplier = Math.min(1, this.state.energy / 100);
|
||||
this.velocity = this.velocity.limit(this.maxSpeed * speedMultiplier);
|
||||
this.velocity = this.velocity.limit(this.maxSpeed);
|
||||
|
||||
// Reduced friction for more responsive movement
|
||||
this.velocity = Physics.applyFriction(this.velocity, 2, deltaTime);
|
||||
|
||||
@ -216,13 +216,11 @@ class DebugSystem {
|
||||
// Update dynamic content only
|
||||
const coordsElement = playerDiv.querySelector('.debug-coords');
|
||||
const speedElement = playerDiv.querySelector('.debug-speed');
|
||||
const energyElement = playerDiv.querySelector('.debug-energy');
|
||||
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 (energyElement) energyElement.textContent = `${player.state.energy.toFixed(0)}%`;
|
||||
if (puckElement) puckElement.textContent = player.state.hasPuck;
|
||||
if (behaviorElement) behaviorElement.textContent = player.aiState.behavior;
|
||||
});
|
||||
@ -239,7 +237,6 @@ class DebugSystem {
|
||||
<div class="debug-player-info">
|
||||
<div class="debug-coords">Pos: (${player.position.x.toFixed(0)}, ${player.position.y.toFixed(0)})</div>
|
||||
<div>Speed: <span class="debug-value debug-speed">${player.velocity.magnitude().toFixed(1)}</span></div>
|
||||
<div>Energy: <span class="debug-value debug-energy">${player.state.energy.toFixed(0)}%</span></div>
|
||||
<div>Has Puck: <span class="debug-value debug-puck">${player.state.hasPuck}</span></div>
|
||||
<div>Behavior: <span class="debug-value debug-behavior">${player.aiState.behavior}</span></div>
|
||||
</div>
|
||||
@ -315,10 +312,6 @@ class DebugSystem {
|
||||
<span class="debug-attribute-name">Has Puck:</span>
|
||||
<span class="debug-attribute-value">${player.state.hasPuck}</span>
|
||||
</div>
|
||||
<div class="debug-attribute">
|
||||
<span class="debug-attribute-name">Energy:</span>
|
||||
<span class="debug-attribute-value">${player.state.energy.toFixed(1)}%</span>
|
||||
</div>
|
||||
<div class="debug-attribute">
|
||||
<span class="debug-attribute-name">Checking:</span>
|
||||
<span class="debug-attribute-value">${player.state.checking}</span>
|
||||
|
||||
@ -372,21 +372,10 @@ class Renderer {
|
||||
const x = player.position.x;
|
||||
const y = player.position.y - player.radius - 5;
|
||||
|
||||
// Draw player ID and energy
|
||||
// Draw player ID
|
||||
this.ctx.fillStyle = player.team === 'home' ? '#ff4444' : '#4444ff';
|
||||
this.ctx.fillText(`${player.role}`, x - 10, y);
|
||||
|
||||
// Draw energy bar
|
||||
const barWidth = 20;
|
||||
const barHeight = 3;
|
||||
const energyPercent = player.state.energy / 100;
|
||||
|
||||
this.ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
|
||||
this.ctx.fillRect(x - barWidth/2, y - 15, barWidth, barHeight);
|
||||
|
||||
this.ctx.fillStyle = energyPercent > 0.5 ? '#44ff44' : energyPercent > 0.25 ? '#ffff44' : '#ff4444';
|
||||
this.ctx.fillRect(x - barWidth/2, y - 15, barWidth * energyPercent, barHeight);
|
||||
|
||||
// Highlight puck carrier
|
||||
if (player.state.hasPuck) {
|
||||
this.ctx.strokeStyle = '#ffff00';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user