- Add isGoalScored flag to GameState for behavior tree decision-making - Update SkaterBehavior to skate to center ice (0,0) when goal scored - Update GoalieBehavior to return to center of goal when goal scored - Remove update loop freeze from GameScene, now handled by behaviors - Update CLAUDE.md with comprehensive subsystem documentation All player logic now contained within the behavior system instead of GameScene update loop, improving separation of concerns and making post-goal behavior more realistic (players skate to faceoff positions). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
434 lines
14 KiB
Markdown
434 lines
14 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
## Project Overview
|
||
|
||
A hockey match engine simulation built with PhaserJS and TypeScript. The engine uses continuous positioning (exact X/Y coordinates on a 2D rink) combined with behavior trees for AI decision-making to create a realistic hockey match simulation.
|
||
|
||
**Core Concept**: Players have exact positions on a 60x30m international hockey rink, with AI running behavior trees at 60 FPS to make tactical decisions (passing, shooting, positioning, etc.).
|
||
|
||
## Development Commands
|
||
|
||
```bash
|
||
# Start development server (runs on port 3000)
|
||
pnpm run dev
|
||
|
||
# Build for production
|
||
pnpm run build
|
||
|
||
# Preview production build
|
||
pnpm run preview
|
||
```
|
||
|
||
## Coordinate System
|
||
|
||
**Critical**: The rink uses a centered coordinate system:
|
||
- Origin (0, 0) = center of rink
|
||
- Rink dimensions: 60m length × 30m width
|
||
- Left goal: x = -26m, Right goal: x = +26m
|
||
- All positions use **meters as floats** (not integers)
|
||
- Screen rendering: 1 meter = 20 pixels (SCALE constant)
|
||
|
||
## Architecture
|
||
|
||
### Project Structure
|
||
|
||
```
|
||
src/
|
||
config/
|
||
constants.ts # All game constants (rink dimensions, colors, speeds, AI parameters)
|
||
game/
|
||
main.ts # Phaser game initialization and config
|
||
GameScene.ts # Main game scene (rendering, game loop, physics, event handling)
|
||
Goal.ts # Goal structure with physics bodies and scoring detection
|
||
entities/
|
||
Player.ts # Player entity with physics, movement, and detection systems
|
||
Puck.ts # Puck entity with physics and state management
|
||
systems/
|
||
BehaviorTree.ts # Main behavior tree system for AI decision-making
|
||
BehaviorNodes.ts # Base classes (Selector, Sequence, Condition, Action)
|
||
behaviors/
|
||
SkaterBehavior.ts # Top-level skater AI (context selector)
|
||
GoalieBehavior.ts # Goalie-specific AI
|
||
TransitionBehavior.ts # Loose puck / neutral zone behavior
|
||
offensive/
|
||
PuckCarrierBehavior.ts # Shoot/carry/evade decisions
|
||
OffensiveSupportBehavior.ts # Support when teammate has puck (planned)
|
||
defensive/
|
||
DefensiveBehavior.ts # Chase and pressure opponent
|
||
types/
|
||
game.ts # TypeScript types and interfaces
|
||
utils/
|
||
coordinates.ts # Game ↔ screen coordinate conversion
|
||
math.ts # Distance, angle utilities
|
||
```
|
||
|
||
### Implementation Status
|
||
|
||
**✓ Completed Phases:**
|
||
- **Phase 1**: Environment setup, rink rendering
|
||
- **Phase 2**: Player entities with smooth acceleration/deceleration and rotation
|
||
- **Phase 3**: Puck physics and possession mechanics
|
||
- **Phase 4**: Puck carrier behavior (shoot/carry/evade)
|
||
- **Phase 6**: Basic defensive behavior (chase puck carrier)
|
||
- **Phase 7**: Basic goalie AI (track puck position)
|
||
- **Phase 8**: Goal detection, scoring system, pause-aware reset timers
|
||
|
||
**🚧 In Progress / Partial:**
|
||
- **Phase 5**: Offensive support (placeholder only)
|
||
- Tackle mechanics (implemented but needs tuning)
|
||
- Puck reception (implemented with skill-based probability)
|
||
|
||
**📋 Planned:**
|
||
- Passing AI (identify and execute passes)
|
||
- Advanced offensive positioning (heat maps, formations)
|
||
- Faceoffs and game flow states
|
||
- Save mechanics for goalies
|
||
|
||
---
|
||
|
||
## Core Systems Documentation
|
||
|
||
### 1. Behavior Tree System
|
||
|
||
**Location:** [src/systems/BehaviorTree.ts](src/systems/BehaviorTree.ts), [src/systems/BehaviorNodes.ts](src/systems/BehaviorNodes.ts)
|
||
|
||
**Purpose:** AI decision-making engine that runs at 60 FPS for each player.
|
||
|
||
**Architecture:**
|
||
- **BehaviorNode**: Abstract base class for all nodes
|
||
- **Selector**: OR logic - tries children until one succeeds
|
||
- **Sequence**: AND logic - all children must succeed
|
||
- **Condition**: Boolean predicate functions
|
||
- **Action**: Leaf nodes that return PlayerAction
|
||
|
||
**Decision Tree Structure:**
|
||
```
|
||
Root Selector
|
||
├─ Goalie? → GoalieBehavior
|
||
└─ Skater? → SkaterBehavior
|
||
├─ Has puck? → PuckCarrierBehavior (shoot/carry/evade)
|
||
├─ Teammate has puck? → OffensiveSupportBehavior (planned)
|
||
├─ Opponent has puck? → DefensiveBehavior (chase)
|
||
└─ Loose puck → TransitionBehavior (chase loose puck)
|
||
```
|
||
|
||
**Key Files:**
|
||
- [BehaviorTree.ts:26-60](src/systems/BehaviorTree.ts#L26-L60): Main tree evaluation
|
||
- [SkaterBehavior.ts:21-39](src/systems/behaviors/SkaterBehavior.ts#L21-L39): Context-based selector
|
||
|
||
---
|
||
|
||
### 2. Player Entity System
|
||
|
||
**Location:** [src/entities/Player.ts](src/entities/Player.ts)
|
||
|
||
**Purpose:** Player physics, movement, rotation, and nearby player detection.
|
||
|
||
**Key Features:**
|
||
|
||
**Movement System** ([Player.ts:186-286](src/entities/Player.ts#L186-L286)):
|
||
- Smooth acceleration with ease-out curve (PLAYER_ACCELERATION)
|
||
- Speed-dependent rotation (faster = wider turns)
|
||
- Deceleration when near target or after goals
|
||
- Stop threshold to prevent jittering (MOVEMENT_STOP_THRESHOLD)
|
||
|
||
**Player Detection System** ([Player.ts:324-387](src/entities/Player.ts#L324-L387)):
|
||
- Physics-based circular sensor (NEAR_PLAYER_DETECTION_RADIUS = 4m)
|
||
- Field-of-view filtering (NEAR_PLAYER_DETECTION_ANGLE = 180°)
|
||
- Maintains sets: `nearbyPlayers`, `nearbyOpponents`, `nearbyTeammates`
|
||
- Methods: `getDetectedOpponents()`, `getDetectedTeammates()`
|
||
|
||
**Tackle System** ([Player.ts:290-312](src/entities/Player.ts#L290-L312)):
|
||
- Cooldown timer (TACKLE_COOLDOWN = 1000ms)
|
||
- Fall duration when tackled (TACKLE_FALL_DURATION = 500ms)
|
||
- Speed requirement (TACKLE_MIN_SPEED = 2 m/s)
|
||
- Angle-based effectiveness modifiers
|
||
|
||
**Player Attributes** ([types/game.ts:27-33](src/types/game.ts#L27-L33)):
|
||
- `speed`: Movement speed (0-100) → m/s via SPEED_SCALE_FACTOR
|
||
- `skill`: Pass/shot accuracy, decision quality
|
||
- `tackling`: Tackle success probability
|
||
- `balance`: Resist being tackled
|
||
- `handling`: Puck reception and control
|
||
|
||
---
|
||
|
||
### 3. Puck Entity System
|
||
|
||
**Location:** [src/entities/Puck.ts](src/entities/Puck.ts)
|
||
|
||
**Purpose:** Puck physics, state management, and possession tracking.
|
||
|
||
**Puck States** ([types/game.ts:22](src/types/game.ts#L22)):
|
||
- `loose`: Free on ice, physics-driven
|
||
- `carried`: Held by player (carrier ID tracked)
|
||
- `passing`: In flight between players (future)
|
||
- `shot`: Shot toward goal
|
||
|
||
**Physics Configuration** ([Puck.ts:36-56](src/entities/Puck.ts#L36-L56)):
|
||
- Circular collision body (PUCK_RADIUS = 0.2m)
|
||
- Max velocity: MAX_PUCK_VELOCITY = 50 m/s
|
||
- Drag (ice friction): PUCK_DRAG = 200 pixels/s²
|
||
- Bounce coefficient: PUCK_BOUNCE = 0.6 (loses energy)
|
||
- World bounds collision enabled
|
||
|
||
**Key Methods:**
|
||
- `setCarrier(playerId, team)`: Assign possession
|
||
- `setLoose()`: Release to physics simulation
|
||
- `update()`: Sync game coordinates with physics body
|
||
|
||
---
|
||
|
||
### 4. Puck Carrier Behavior
|
||
|
||
**Location:** [src/systems/behaviors/offensive/PuckCarrierBehavior.ts](src/systems/behaviors/offensive/PuckCarrierBehavior.ts)
|
||
|
||
**Purpose:** Tactical decisions when player has possession.
|
||
|
||
**Decision Priority:**
|
||
1. **Evade** if opponent threatens head-on ([PuckCarrierBehavior.ts:104-254](src/systems/behaviors/offensive/PuckCarrierBehavior.ts#L104-L254))
|
||
2. **Shoot** if good opportunity ([PuckCarrierBehavior.ts:262-308](src/systems/behaviors/offensive/PuckCarrierBehavior.ts#L262-L308))
|
||
3. **Carry** toward opponent's net (default)
|
||
|
||
**Evasion System:**
|
||
- Uses physics-based player detection (NEAR_PLAYER_DETECTION_RADIUS)
|
||
- Checks if opponent is within 60° of goal direction
|
||
- Maintains consistent evasion direction per opponent (stored in `activeEvasions` map)
|
||
- Evasion angle: ±60° (EVASION_ANGLE) from goal direction
|
||
- Clears evasion when opponent leaves detection zone
|
||
|
||
**Shooting Logic:**
|
||
- Must be in front of goal (not behind)
|
||
- Distance ≤ SHOOTING_RANGE (10m)
|
||
- Angle-based accuracy:
|
||
- Close range (≤3m): 120° shooting angle allowed
|
||
- Normal range: 60° shooting angle required
|
||
- Aims at center of net (targetY = 0)
|
||
|
||
**Debug Visualization** (when DEBUG = true):
|
||
- Green line to goal
|
||
- Red circle around threats being evaded
|
||
- Yellow arrow showing evasion direction
|
||
- Orange circles for detected opponents
|
||
|
||
---
|
||
|
||
### 5. GameScene System
|
||
|
||
**Location:** [src/game/GameScene.ts](src/game/GameScene.ts)
|
||
|
||
**Purpose:** Main game loop, physics management, collision detection, event handling.
|
||
|
||
**Key Responsibilities:**
|
||
|
||
**Physics Setup:**
|
||
- Player-player collisions (including tackle mechanics)
|
||
- Player-puck overlaps (pickup and reception)
|
||
- Puck-goal post collisions with bounce
|
||
- Detection sensor overlaps (nearby player tracking)
|
||
|
||
**Puck Management:**
|
||
- Carrier positioning: puck stays 1m in front of carrier
|
||
- Pickup radius: PUCK_PICKUP_RADIUS = 1.5m
|
||
- Reception skill checks (PUCK_RECEPTION_BASE_CHANCE)
|
||
- Speed-based reception difficulty
|
||
|
||
**Shooting System:**
|
||
- Shot speed: SHOT_SPEED = 30 m/s (or 0.6× for close range)
|
||
- Post bounce: reduces speed and adds random angle variation
|
||
- Goal detection via overlap with scoring zone
|
||
|
||
**Tackle System:**
|
||
- Cooldown enforcement (TACKLE_COOLDOWN)
|
||
- Angle-based effectiveness (head-on = 100%, side = 70%, etc.)
|
||
- Closing speed modifiers
|
||
- Puck loose probability (TACKLE_PUCK_LOOSE_CHANCE = 60%)
|
||
|
||
**Goal System:**
|
||
- Freeze game on goal event
|
||
- 3-second pause-aware timer
|
||
- Player deceleration (GOAL_DECELERATION_RATE)
|
||
- Reset positions to center ice
|
||
|
||
---
|
||
|
||
### 6. Coordinate System
|
||
|
||
**Location:** [src/utils/coordinates.ts](src/utils/coordinates.ts)
|
||
|
||
**Purpose:** Convert between game coordinates (meters) and screen coordinates (pixels).
|
||
|
||
**Critical Details:**
|
||
- **Game coordinates:** Origin (0, 0) at center of rink, meters as floats
|
||
- **Screen coordinates:** Origin at top-left, pixels
|
||
- **Scale factor:** 1 meter = 20 pixels (SCALE constant)
|
||
- **Y-axis inversion:** Game Y increases upward, screen Y increases downward
|
||
|
||
**Key Methods:**
|
||
- `gameToScreen(scene, gameX, gameY)`: Meters → pixels
|
||
- `screenToGame(scene, screenX, screenY)`: Pixels → meters
|
||
- `getScreenCenter(scene)`: Canvas center in pixels
|
||
|
||
**Rink Layout:**
|
||
- Rink: 60m × 30m
|
||
- Left goal: x = -26m (GOAL_LINE_OFFSET)
|
||
- Right goal: x = +26m
|
||
- Blue lines: x = ±9m (BLUE_LINE_OFFSET)
|
||
- Center ice: (0, 0)
|
||
|
||
---
|
||
|
||
### 7. Constants Configuration
|
||
|
||
**Location:** [src/config/constants.ts](src/config/constants.ts)
|
||
|
||
**Purpose:** Centralized configuration for all game parameters.
|
||
|
||
**Categories:**
|
||
|
||
**Game Settings:**
|
||
- DEBUG, FPS, UI_BOTTOM_PADDING
|
||
|
||
**Rink Dimensions:**
|
||
- RINK_LENGTH, RINK_WIDTH, SCALE, corner radius, zone lines
|
||
|
||
**Player Constants:**
|
||
- Radius (goalie vs skater), rotation speed, acceleration/deceleration
|
||
- Speed scale factor, movement threshold
|
||
|
||
**Puck Constants:**
|
||
- Radius, pickup range, carry distance, max velocity
|
||
- Drag, bounce, shot speed, reception parameters
|
||
|
||
**AI/Behavior:**
|
||
- Shooting range and angle thresholds (normal vs close-range)
|
||
- Goalie range, detection radius and angle
|
||
- Evasion angle
|
||
|
||
**Tackle Mechanics:**
|
||
- Success modifiers, cooldown, fall duration
|
||
- Angle thresholds and modifiers
|
||
- Closing speed thresholds
|
||
|
||
**Collision/Physics:**
|
||
- Post bounce reduction, puck loose chance
|
||
- Reception skill scaling
|
||
|
||
---
|
||
|
||
## Type Definitions
|
||
|
||
**Location:** [src/types/game.ts](src/types/game.ts)
|
||
|
||
**Key Types:**
|
||
|
||
```typescript
|
||
PlayerPosition: 'LW' | 'C' | 'RW' | 'LD' | 'RD' | 'G'
|
||
TeamSide: 'home' | 'away'
|
||
PlayerState: 'offensive' | 'defensive'
|
||
PuckState: 'loose' | 'carried' | 'passing' | 'shot'
|
||
|
||
PlayerAttributes: {
|
||
speed, skill, tackling, balance, handling
|
||
}
|
||
|
||
GameState: {
|
||
puck: Puck
|
||
allPlayers: Player[]
|
||
}
|
||
|
||
PlayerAction: {
|
||
type: 'move' | 'chase_puck' | 'skate_with_puck' | 'shoot' | 'idle'
|
||
targetX?, targetY?
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Technical Stack
|
||
|
||
- **Framework**: Phaser 3.90.0 (Arcade Physics engine)
|
||
- **TypeScript**: Strict mode enabled
|
||
- **Build Tool**: Vite 5.4
|
||
- **Target FPS**: 60 (configured in constants.ts)
|
||
- **Physics**: Arcade physics with zero gravity (top-down view)
|
||
- **Coordinate System**: Centered origin (0,0), meters as float values
|
||
- **Rendering Scale**: 1 meter = 20 pixels
|
||
|
||
---
|
||
|
||
## Debug Features
|
||
|
||
**Toggle:** Set `DEBUG = true` in [constants.ts](src/config/constants.ts)
|
||
|
||
**Visual Overlays:**
|
||
- **Player movement:** Line and marker showing target position
|
||
- **Player detection:** Magenta wedge showing field-of-view sensor
|
||
- **Puck carrier evasion:**
|
||
- Green line to goal
|
||
- Red circles around detected threats
|
||
- Yellow/green arrows showing evasion direction
|
||
- Orange circles for all nearby opponents
|
||
|
||
**Console Logging:**
|
||
- Goal events with team and goal location
|
||
- Shot attempts with player ID
|
||
- Tackle results and success calculations
|
||
|
||
---
|
||
|
||
## Development Workflow
|
||
|
||
**Hot Reload Development:**
|
||
```bash
|
||
pnpm run dev # Starts on localhost:3000 with hot reload
|
||
```
|
||
|
||
**Testing Approach:**
|
||
- Test each subsystem incrementally before integration
|
||
- Use DEBUG mode to visualize AI decision-making
|
||
- Tune constants based on gameplay feel (see [constants.ts](src/config/constants.ts))
|
||
- Validate physics with edge cases (goal posts, rink boundaries)
|
||
|
||
**Key Tuning Parameters:**
|
||
- Player acceleration/deceleration curves → smooth movement feel
|
||
- Detection radius/angle → evasion responsiveness
|
||
- Shooting angles → goal frequency balance
|
||
- Tackle modifiers → physical gameplay intensity
|
||
- Puck drag/bounce → realistic puck physics
|
||
|
||
**Documentation:**
|
||
- **[PLAN.md](PLAN.md)**: Phase-by-phase implementation plan
|
||
- **[NOTES.md](NOTES.md)**: Architecture decisions and design rationale
|
||
- **[REVIEW.md](REVIEW.md)**: Progress reviews and lessons learned
|
||
- **[CLAUDE.md](CLAUDE.md)** (this file): System reference for AI assistant
|
||
|
||
---
|
||
|
||
## Implementation Patterns
|
||
|
||
**Adding New Behaviors:**
|
||
1. Create behavior class extending `BehaviorNode` in `src/systems/behaviors/`
|
||
2. Implement `tick(player, gameState)` method
|
||
3. Add to appropriate selector in `SkaterBehavior` or `GoalieBehavior`
|
||
4. Test in isolation before integration
|
||
|
||
**Adding New Constants:**
|
||
1. Add to appropriate section in [constants.ts](src/config/constants.ts)
|
||
2. Use semantic names (e.g., `SHOOTING_RANGE` not `MAX_DIST`)
|
||
3. Include units in comments (meters, m/s, radians, pixels)
|
||
4. Export for use across codebase
|
||
|
||
**Physics Bodies:**
|
||
- Players: Circular bodies (radius varies by position)
|
||
- Puck: Circular body with drag and bounce
|
||
- Goals: Static rectangular bodies for posts/bars
|
||
- Sensors: Physics zones with `overlap` not `collide`
|
||
|
||
**Coordinate Conversions:**
|
||
- Always use `CoordinateUtils.gameToScreen()` and `screenToGame()`
|
||
- Never mix coordinate systems in calculations
|
||
- Store positions in game coordinates (meters), convert for rendering
|