diff --git a/CLAUDE.md b/CLAUDE.md index 7463c59..cd3fed2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,74 +37,397 @@ pnpm run preview ``` src/ config/ - constants.ts # All game constants (rink dimensions, colors, speeds) + 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) - Goal.ts # Goal structure with physics bodies - entities/ # Player and Puck classes (planned) - systems/ # BehaviorTree, PositioningSystem, PuckSystem (planned) + 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 Phases (from PLAN.md) +### Implementation Status -The project follows a phased approach: -1. **Phase 1** (āœ“): Environment setup, rink rendering -2. **Phase 2** (Next): Player entities (12 players: 10 skaters + 2 goalies) with smooth movement -3. **Phase 3**: Puck entity and possession mechanics -4. **Phase 4**: Behavior tree for puck carrier decisions (shoot/pass/carry) -5. **Phase 5**: Team offensive positioning system -6. **Phase 6**: Defensive behaviors and pressure mechanics -7. **Phase 7**: Goalie AI -8. **Phase 8**: Game flow (goals, faceoffs, scoring) -9. **Phase 9**: Polish and tuning +**āœ“ 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 -### Key Systems (Planned) +**🚧 In Progress / Partial:** +- **Phase 5**: Offensive support (placeholder only) +- Tackle mechanics (implemented but needs tuning) +- Puck reception (implemented with skill-based probability) -**Behavior Trees**: Decision-making engine that runs every tick -- Evaluates game state (possession, positions, threats) -- Weights actions by player attributes (Hockey IQ, Skill, Speed) -- Outputs: move, pass, shoot, or defensive actions +**šŸ“‹ Planned:** +- Passing AI (identify and execute passes) +- Advanced offensive positioning (heat maps, formations) +- Faceoffs and game flow states +- Save mechanics for goalies -**Tactical Positioning**: Heat map-based positioning -- Different formations based on game situation (offense/defense) -- Players move toward ideal positions modified by: - - Puck location - - Teammate spacing - - Opponent positions - - Player stamina/speed +--- -**Puck Movement**: -- Pass success = f(passer skill, distance, pressure, receiver skill) -- Shots use trajectory calculation with goalie save probability -- Smooth interpolation for visual feedback +## Core Systems Documentation -## Technical Details +### 1. Behavior Tree System -- **Framework**: Phaser 3.90.0 (with Arcade Physics) +**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 (constant in constants.ts) +- **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 -## Configuration +--- -All magic numbers and game constants are centralized in `src/config/constants.ts`: -- Rink dimensions and zone lines -- Goal dimensions -- Colors (ice, boards, lines) -- Scale factor (meters to pixels) -- Game settings (FPS) +## Debug Features -Future constants will include: -- Player speeds, shot speeds, pass speeds -- AI decision probabilities -- Attribute ranges +**Toggle:** Set `DEBUG = true` in [constants.ts](src/config/constants.ts) -## Development Notes +**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 -- **Incremental testing**: Test each phase thoroughly before proceeding -- **Debug visualization**: Add toggleable overlays for targets, zones, etc. -- **Tuning over precision**: Numbers are starting points; tune based on feel -- Refer to PLAN.md for detailed phase requirements and validation criteria -- Refer to NOTES.md for architectural decisions and design notes +**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 diff --git a/src/game/GameScene.ts b/src/game/GameScene.ts index 3d3b8de..984f05a 100644 --- a/src/game/GameScene.ts +++ b/src/game/GameScene.ts @@ -348,7 +348,8 @@ export class GameScene extends Phaser.Scene { this.events.off('goal'); this.scene.restart(); } - return; // Don't update anything while waiting for reset + // Continue updating with isGoalScored flag set + // This allows behavior trees to handle the freeze logic } this.updatePuck(); @@ -362,10 +363,11 @@ export class GameScene extends Phaser.Scene { } private updatePlayers(delta: number) { - // Build game state + // Build game state with goal freeze status const gameState = { puck: this.puck, - allPlayers: this.players + allPlayers: this.players, + isGoalScored: this.isWaitingForReset }; // Update all players with behavior tree decisions diff --git a/src/systems/behaviors/GoalieBehavior.ts b/src/systems/behaviors/GoalieBehavior.ts index 39eec2d..59def58 100644 --- a/src/systems/behaviors/GoalieBehavior.ts +++ b/src/systems/behaviors/GoalieBehavior.ts @@ -7,6 +7,7 @@ import { GOAL_LINE_OFFSET, GOALIE_RANGE } from '../../config/constants'; * Goalie-specific behavior tree * * Goalies have unique behaviors: + * - Return to center of goal when goal scored (highest priority) * - Stay near goal line * - Track puck Y position * - Challenge shooters (future) @@ -14,6 +15,16 @@ import { GOAL_LINE_OFFSET, GOALIE_RANGE } from '../../config/constants'; */ export class GoalieBehavior extends BehaviorNode { tick(player: Player, gameState: GameState): PlayerAction { + // Priority check: If goal was scored, return to center of goal + if (gameState.isGoalScored) { + const goalX = player.team === 'home' ? -GOAL_LINE_OFFSET : GOAL_LINE_OFFSET; + return { + type: 'move', + targetX: goalX, + targetY: 0 // Center of goal + }; + } + // Stay near goal line const goalX = player.team === 'home' ? -GOAL_LINE_OFFSET : GOAL_LINE_OFFSET; diff --git a/src/systems/behaviors/SkaterBehavior.ts b/src/systems/behaviors/SkaterBehavior.ts index 3ac2ad5..b826f59 100644 --- a/src/systems/behaviors/SkaterBehavior.ts +++ b/src/systems/behaviors/SkaterBehavior.ts @@ -10,7 +10,8 @@ import { TransitionBehavior } from './TransitionBehavior'; * Skater behavior tree - Context-based decision making * * The selector evaluates children in priority order: - * 1. PuckCarrier - If this player has the puck (highest priority) + * 0. Goal Scored - Return to center faceoff circle (highest priority) + * 1. PuckCarrier - If this player has the puck * 2. OffensiveSupport - If teammate has puck (support offense) * 3. Defensive - If opponent has puck (play defense) * 4. Transition - Loose puck or neutral situations (fallback) @@ -34,6 +35,15 @@ export class SkaterBehavior extends BehaviorNode { } tick(player: Player, gameState: GameState): PlayerAction { + // Priority check: If goal was scored, skate to center faceoff circle + if (gameState.isGoalScored) { + return { + type: 'move', + targetX: 0, // Center ice + targetY: 0 // Center ice + }; + } + return this.tree.tick(player, gameState) as PlayerAction; } } diff --git a/src/types/game.ts b/src/types/game.ts index ebc37c6..827948e 100644 --- a/src/types/game.ts +++ b/src/types/game.ts @@ -38,6 +38,7 @@ export interface PlayerAttributes { export interface GameState { puck: Puck; allPlayers: Player[]; + isGoalScored: boolean; // True when goal scored and game frozen } /**