# Hockey Match Engine MVP - Implementation Plan ## Overview A minimal hockey match engine using PhaserJS with continuous positioning and behavior trees. The goal is to validate the architecture with the simplest working implementation. ## Technical Stack - **Framework**: PhaserJS 3 - **Language**: TypeScript - **Coordinate System**: International rink (60x30m), origin at center (0,0) - **Update Rate**: 60 FPS (Phaser's default game loop) ## Core Architecture ### 1. Game State ``` GameState { puck: { x, y, possession: PlayerID|null, carrier: PlayerID|null } teams: [homeTeam, awayTeam] score: { home: 0, away: 0 } gameTime: elapsed seconds } ``` ### 2. Player Structure ``` Player { id: string team: 'home'|'away' position: 'LW'|'C'|'RW'|'LD'|'RD'|'G' x, y: float (current position) targetX, targetY: float (desired position) attributes: { speed: 0-100 (movement speed) skill: 0-100 (pass/shot accuracy, decision quality) } state: 'offensive'|'defensive' } ``` ### 3. Behavior Tree (Simplified) ``` Root ├─ Is Player Goalie? │ └─ Goalie Behavior (stay near net, track puck) │ ├─ Does Player Have Puck? │ ├─ Can Shoot? → Shoot │ ├─ Can Pass? → Pass to best teammate │ └─ Else → Skate toward opponent net │ ├─ Is Puck Loose? │ └─ Move toward puck (chase) │ └─ Team Has Puck? (offensive state) ├─ Move to offensive support position └─ Else → Move to defensive coverage position ``` --- ## Implementation Phases ### Phase 1: Environment Setup **Goal**: Get PhaserJS running with a hockey rink displayed **Tasks**: 1. Initialize npm project with package.json 2. Install dependencies: `phaser` (and optionally `typescript`, `vite` for dev server) 3. Create basic project structure: ``` /src /game main.js (Phaser game configuration) GameScene.js (main game scene) /entities Player.js Puck.js /systems BehaviorTree.js PositioningSystem.js PuckSystem.js /config constants.js (rink dimensions, game constants) index.html ``` 4. Draw the rink: - Rectangle 60x30m (scale for display, e.g., 1m = 10px → 600x300px) - Center red line - Blue lines at ±18.3m - Goal creases (simple rectangles at x=±26, y=0) - Optional: boards/corners (rounded rectangle) **Validation**: Browser displays a hockey rink with proper markings --- ### Phase 2: Player Entities & Basic Movement **Goal**: Render 12 players (10 skaters + 2 goalies) and move them to target positions **Tasks**: 1. Create Player class: - Visual: colored circle (10px radius) - Home team: blue circles - Away team: red circles - Goalies: larger circles or different shade - Render at x,y coordinates - Add text label with position (LW, C, RW, LD, RD, G) 2. Create initial formations (5v5 setup): - **Home team** (left side, attacking right): - G: (-26, 0) - LD: (-15, -5), RD: (-15, 5) - LW: (-10, -8), C: (-10, 0), RW: (-10, 8) - **Away team** (right side, attacking left): - G: (26, 0) - LD: (15, 5), RD: (15, -5) - LW: (10, 8), C: (10, 0), RW: (10, -8) 3. Implement interpolated movement: - Each player has `targetX, targetY` - Each frame: move toward target using easing (lerp or Phaser tweens) - Movement speed based on `speed` attribute (e.g., speed=80 → 8 m/s) 4. Test: Set random target positions and watch players smoothly move **Validation**: 12 colored circles on ice, moving smoothly when targets change --- ### Phase 3: Puck & Basic Possession **Goal**: Add puck entity and implement possession mechanics **Tasks**: 1. Create Puck class: - Visual: small black circle (5px radius) - Position: x, y - State: `loose`, `carried`, `passing`, `shot` - `possession`: which team has control - `carrier`: specific PlayerID holding puck 2. Implement puck carrying: - When player has puck: puck.x = player.x, puck.y = player.y - Puck "sticks" to carrier position each frame 3. Implement loose puck pickup: - Calculate distance from each player to puck - If player within pickup radius (1.5m) and puck is loose: - Pickup chance = f(player.skill, player.speed) - Assign carrier, set possession 4. Faceoff system: - Place puck at (0, 0) - Set state = `loose` - Both centers skate to center, first to arrive picks up **Validation**: Puck spawns at center, players skate to it, one picks it up --- ### Phase 4: Basic Behavior Tree - Puck Carrier Actions **Goal**: Player with puck makes decisions (shoot, pass, carry) **Tasks**: 1. Create BehaviorTree evaluator: - Input: player, gameState - Output: action {type: 'move'|'pass'|'shoot', target: ...} 2. Implement carrier behaviors: - **Shoot decision**: - If within shooting range (x > 15m from opponent net) and clear lane: - Shoot chance = f(skill, distance to net) - Action: `{type: 'shoot', targetX: opponentNet.x, targetY: random(-2, 2)}` - **Pass decision**: - Find all teammates - Filter: not covered by opponent (simple distance check) - Rate by: distance to net, openness - If good option exists: `{type: 'pass', target: teammateID}` - **Carry decision** (default): - Move toward opponent net - Target: (opponentNet.x - 5, y + random(-3, 3)) 3. Action execution: - **Shoot**: - Travel time = distance / shotSpeed (e.g., 30 m/s) - Goalie save chance = f(goalie.skill, shot distance, shot accuracy) - Outcome: goal (puck to net, score++, faceoff) or save (puck loose near net) - **Pass**: - Travel time = distance / passSpeed (15 m/s) - Success chance = f(passer.skill, distance, pressure) - If success: receiver becomes carrier - If fail: puck becomes loose at midpoint - **Carry**: player skates with puck **Validation**: Player with puck skates toward net, occasionally passes or shoots --- ### Phase 5: Team Positioning System (Offensive) **Goal**: Players without puck move to support positions **Tasks**: 1. Create simple heat map / positioning zones: - **Offensive formation** (team has puck): - Wingers: spread wide (y = ±10) - Center: support puck carrier (x = carrier.x - 5, y = 0) - Defense: hold blue line (x = offensiveZone - 15) 2. Implement positioning logic: - Each non-carrier calculates ideal position based on: - Puck location - Their position role (LW, C, RW, LD, RD) - Teammate spacing (avoid clustering) - Set targetX, targetY to ideal position - Player moves there using Phase 2 movement system 3. Dynamic adjustment: - If puck changes possession, recalculate all positions **Validation**: When one team has puck, their players spread into offensive formation --- ### Phase 6: Defensive Behaviors **Goal**: Defending team pressures puck carrier and covers passing lanes **Tasks**: 1. Add defensive state detection: - If opponent has puck: all players on team → state = 'defensive' 2. Implement defensive positioning: - **Forecheck** (1 nearest forward): - Chase puck carrier (targetX = carrier.x, targetY = carrier.y) - Apply "pressure" when within 2m - **Coverage** (other forwards): - Cover closest opponent forward - Stay between opponent and own net - **Defensive zone** (defense): - Protect net-front (x = -20 to -25, y = ±4) - Box out opponent forwards 3. Pressure mechanic: - When defender within 2m of carrier: - Reduce carrier's pass/shot success chance - Increase turnover chance (puck becomes loose) **Validation**: Defending team chases puck carrier and covers opponents --- ### Phase 7: Goalie Behavior **Goal**: Goalies track puck and make saves **Tasks**: 1. Goalie positioning: - Stay in crease: x = ±27 (near net) - Track puck Y position: targetY = clamp(puck.y, -3, 3) - Interpolate to target (slower than skaters) 2. Save mechanics: - On shot toward net: - Calculate if shot trajectory intersects goalie position (±1m tolerance) - Save chance = f(goalie.skill, shot speed, shot accuracy) - Save: puck becomes loose in crease - Goal: puck "enters net", score increments 3. Visual feedback: - Flash goalie when making save - Puck bounce animation on save **Validation**: Goalies move laterally to track puck, stop some shots --- ### Phase 8: Game Flow & Reset **Goal**: Handle goals and faceoffs, basic game loop **Tasks**: 1. Goal detection: - Check if puck crosses goal line (x > 29.5 or x < -29.5, y within net width) - Increment score - Trigger celebration pause (1 second) - Reset to faceoff 2. Faceoff logic: - Reset all players to formation positions (Phase 2) - Place puck at (0, 0) - Set puck.state = 'loose' - Resume game 3. Game clock (optional for MVP): - Display elapsed time - No periods/end game for now (continuous) 4. Simple HUD: - Score display: "Home 2 - 1 Away" - Optional: possession indicator **Validation**: Full game loop - faceoff → play → goal → faceoff → repeat --- ### Phase 9: Polish & Tuning **Goal**: Make it feel like hockey **Tasks**: 1. Tune movement speeds: - Skater speed: ~8-10 m/s - Puck pass speed: 15 m/s - Puck shot speed: 30 m/s 2. Tune AI probabilities: - Shot frequency: should see ~5-15 shots per team per minute - Pass success: ~70-80% for uncontested passes - Turnover frequency: balance offense/defense 3. Visual polish: - Puck trail (line showing recent path) - Player orientation (rotate sprite toward movement direction) - Smooth animations for passes/shots 4. Balancing: - Adjust skill/speed ranges so games are competitive - Test with different attribute values **Validation**: Game looks and feels reasonably like hockey --- ## Success Criteria for MVP - ✅ 12 players (10 skaters + 2 goalies) on ice - ✅ Players move smoothly in formations - ✅ Puck possession and carrying works - ✅ Players pass, shoot, and score goals - ✅ Basic offensive positioning (spread out, support) - ✅ Basic defensive pressure (chase carrier) - ✅ Goalies make saves - ✅ Goals trigger faceoffs and score updates - ✅ Game runs continuously without crashes --- ## Future Iterations (Post-MVP) **Phase 10+**: Additional features to consider after MVP validation: - Offsides/icing rules - Line changes and stamina system - More strategies (1-2-2 forecheck, trap, etc.) - Penalties and power plays - More player attributes (checking, passing accuracy, shot power) - Better AI decision trees (risk assessment, situational awareness) - Replay system - Match statistics tracking - 3D visualization or better sprites --- ## Development Tips 1. **Test incrementally**: After each phase, test thoroughly before moving on 2. **Use constants file**: Store all magic numbers (rink size, speeds, probabilities) in one place 3. **Debug visualization**: Add toggleable overlays (target positions, pressure zones, etc.) 4. **Start simple**: Don't add complexity until basic mechanics work 5. **Iterate on feel**: The numbers in this plan are starting points - tune them based on what looks/feels right --- ## Estimated Timeline (Solo Developer) - Phase 1: 2-4 hours (setup + rink rendering) - Phase 2: 3-4 hours (player entities + movement) - Phase 3: 2-3 hours (puck + possession) - Phase 4: 4-6 hours (behavior tree + carrier actions) - Phase 5: 3-4 hours (offensive positioning) - Phase 6: 4-5 hours (defensive behaviors) - Phase 7: 2-3 hours (goalie AI) - Phase 8: 2-3 hours (game flow) - Phase 9: 4-6 hours (tuning + polish) **Total: ~26-38 hours** for a working MVP --- ## Next Steps 1. Set up development environment (Phase 1) 2. Get rink rendering working 3. Proceed through phases sequentially 4. Test and validate each phase before moving forward 5. Document any architectural changes or insights in NOTES.md Good luck! 🏒