hockey-manager-2/CLAUDE.md
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

14 KiB
Raw Blame History

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

# 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/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:


2. Player Entity System

Location: src/entities/Player.ts

Purpose: Player physics, movement, rotation, and nearby player detection.

Key Features:

Movement System (Player.ts:186-286):

  • 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):

  • 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):

  • 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):

  • 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

Purpose: Puck physics, state management, and possession tracking.

Puck States (types/game.ts:22):

  • 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):

  • 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

Purpose: Tactical decisions when player has possession.

Decision Priority:

  1. Evade if opponent threatens head-on (PuckCarrierBehavior.ts:104-254)
  2. Shoot if good opportunity (PuckCarrierBehavior.ts:262-308)
  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

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

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

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

Key Types:

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

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:

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)
  • 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: Phase-by-phase implementation plan
  • NOTES.md: Architecture decisions and design rationale
  • REVIEW.md: Progress reviews and lessons learned
  • 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
  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