commit 6b881b34b1379abe3338e5609e66c78036756bbf Author: Pierre Date: Wed Oct 1 11:46:38 2025 +0000 init diff --git a/NOTES.md b/NOTES.md new file mode 100644 index 0000000..53df6a3 --- /dev/null +++ b/NOTES.md @@ -0,0 +1,64 @@ +Hockey Manager Match Engine + +Framework: PhaserJS + +Rink size: international (60x30m). Coordinate system: 0,0 = center. +-60, 0 = left side of the rink, etc. 1 = meter. Use floats though. + +Continuous Position + Behavior Trees (Moderate Complexity) +Best for: Realistic tactics, good visual feedback, manageable scope +Core Concept: + +Players have exact X/Y coordinates on a 2D rink +No physics engine, but movement is interpolated curves (bezier/spline) +Each player runs a behavior tree every update tick (60+ times per second) + +Behavior Tree Structure: +Root: Team Strategy (e.g., "Dump and Chase") + ├─ Player Role (e.g., "Left Winger - Offensive Zone") + │ ├─ Offensive Positioning + │ │ ├─ Is puck in our possession? → Move to scoring position + │ │ └─ Is puck loose? → Move to forecheck target + │ └─ Defensive Transition + │ └─ Backcheck to defensive coverage position + └─ Puck Carrier Actions + ├─ Pass decision (weighted by attributes + open teammates) + ├─ Shoot decision (scoring chance % calculation) + └─ Carry decision (move toward better position) +Key Systems: +A) Tactical Positioning System: + +Define "heat maps" for each strategy/situation +Example: 1-2-2 forecheck = F1 pressures puck carrier, F2/F3 position at blue line +Players move toward their heat map "ideal position" modified by: + +Puck location +Teammate positions (spacing) +Opponent threats +Player stamina/speed + + + +B) Puck Movement: + +No physics! Puck "teleports" but with travel time +Pass success = f(passer skill, pass distance, pressure, receiver skill) +Shots = trajectory calculation with goalie save probability + +C) Decision-Making Engine: +javascriptEvery tick: +1. Evaluate situation (game state, ice time, score, etc.) +2. Query behavior tree for action +3. Weight options by: + - Player attributes (Hockey IQ, Creativity) + - Coaching instructions (Risk level, Passing %) + - Fatigue & injury status +4. Execute highest-weighted valid action +5. Apply outcome (deterministic + dice roll) +Visualization: + +Smooth interpolation between positions (easing functions) +Player sprites with orientation/animations +Puck trails for passes/shots +Think: Football Manager 2D but more fluid + diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..ff5ccaf --- /dev/null +++ b/PLAN.md @@ -0,0 +1,401 @@ +# 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! 🏒 diff --git a/package.json b/package.json new file mode 100644 index 0000000..a9ce0dc --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "workspace", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +}