init
This commit is contained in:
commit
6b881b34b1
64
NOTES.md
Normal file
64
NOTES.md
Normal file
@ -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
|
||||
|
||||
401
PLAN.md
Normal file
401
PLAN.md
Normal file
@ -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! 🏒
|
||||
12
package.json
Normal file
12
package.json
Normal file
@ -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"
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user