Pierre Wessman 581574fa1c Move goal-scored logic to behavior system with faceoff positioning
- 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>
2025-10-06 07:24:35 +02:00

434 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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