diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 3f833ba..3a58bf5 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -16,14 +16,14 @@ Requirements for initial release. Each maps to roadmap phases. - [ ] **CORE-05**: Player scores a point when ball passes opponent's paddle - [ ] **CORE-06**: Match ends when a player reaches the target score (first to N points) - [x] **CORE-07**: Player 1 controls paddle with keyboard (W/S keys) -- [ ] **CORE-08**: Player 2 controls paddle with keyboard (Up/Down arrow keys) +- [x] **CORE-08**: Player 2 controls paddle with keyboard (Up/Down arrow keys) ### AI Opponent -- [ ] **AI-01**: AI opponent tracks and intercepts the ball -- [ ] **AI-02**: Easy difficulty: AI reacts slowly with error margin — beatable by any player -- [ ] **AI-03**: Medium difficulty: AI reacts at moderate speed — provides fair challenge -- [ ] **AI-04**: Hard difficulty: AI reacts fast but not perfectly — requires skill to beat +- [x] **AI-01**: AI opponent tracks and intercepts the ball +- [x] **AI-02**: Easy difficulty: AI reacts slowly with error margin — beatable by any player +- [x] **AI-03**: Medium difficulty: AI reacts at moderate speed — provides fair challenge +- [x] **AI-04**: Hard difficulty: AI reacts fast but not perfectly — requires skill to beat ### Screens @@ -105,11 +105,11 @@ Which phases cover which requirements. Updated during roadmap creation. | CORE-05 | 2 | Pending | | CORE-06 | 2 | Pending | | CORE-07 | 1 | Complete | -| CORE-08 | 2 | Pending | -| AI-01 | 2 | Pending | -| AI-02 | 2 | Pending | -| AI-03 | 2 | Pending | -| AI-04 | 2 | Pending | +| CORE-08 | 2 | Complete | +| AI-01 | 2 | Complete | +| AI-02 | 2 | Complete | +| AI-03 | 2 | Complete | +| AI-04 | 2 | Complete | | SCRN-01 | 3 | Pending | | SCRN-02 | 3 | Pending | | SCRN-03 | 3 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 2411265..5ca1c36 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -60,7 +60,7 @@ Plans: 5. Match ends when a player reaches target score with clear game-over state 6. No memory leaks or event listener cleanup issues after multiple rounds -**Plans:** 2 plans +**Plans:** 1/2 plans executed Plans: - [ ] 02-01-PLAN.md — Paddle2, AI system (predictive interception + 3 difficulty levels), extended Input/Physics @@ -142,7 +142,7 @@ Plans: | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| | 1. Foundation | 1/2 | In Progress | — | -| 2. Core Gameplay | 0/2 | Not started | — | +| 2. Core Gameplay | 1/2 | In Progress| | | 3. Complete Experience | 0/? | Not started | — | | 4. Polish & Depth | 0/? | Not started | — | | 5. Release | 0/? | Not started | — | diff --git a/.planning/STATE.md b/.planning/STATE.md index 6461c08..179ecc3 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,13 +3,13 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: unknown -stopped_at: Phase 2 context gathered -last_updated: "2026-03-10T19:50:48.489Z" +stopped_at: Completed 02-01-PLAN.md +last_updated: "2026-03-10T20:07:22.163Z" progress: total_phases: 5 completed_phases: 1 - total_plans: 2 - completed_plans: 2 + total_plans: 4 + completed_plans: 3 --- # STATE: Super Pong Next Gen @@ -25,13 +25,13 @@ progress: | Attribute | Value | |-----------|-------| -| **Phase** | 01-foundation | -| **Plan** | Plan 2/2 — COMPLETE | -| **Status** | Phase 01 complete — ball physics, wall bounce, zone deflection, speed increment, serve logic done | -| **Progress** | 10% (2/2 plans complete in Phase 1; Phase 1 of 5 complete) | +| **Phase** | 02-core-gameplay | +| **Plan** | Plan 1/2 — COMPLETE | +| **Status** | Phase 02 in progress — paddle2, AI module, predictive ray-cast, 3 difficulty levels done | +| **Progress** | 75% (3/4 plans complete; Phase 1 complete, Phase 2 plan 1 complete) | ``` -[== ] 10% — Phase 1: Complete (2/2 plans) +[████████░░] 75% — Phase 2: 1/2 plans complete ``` --- @@ -48,6 +48,7 @@ progress: | **01-02 Duration** | — | 1 min (2 tasks, 1 file) | --- +| Phase 02-core-gameplay P01 | 2min | 2 tasks | 1 files | ## Accumulated Context @@ -83,6 +84,14 @@ progress: 10. **vx/vy recomputed from speed+angle each paddle hit:** Prevents compound rounding drift from repeated scaling; speed and direction always cleanly separated. +11. **AI uses predictive ray-cast with wall bounce simulation:** _predictBallY steps forward in time (up to 500 steps) simulating wall bounces — far more accurate than linear Y interpolation. + +12. **AI difficulty presets as config objects:** { speed, reactionDelay, errorMargin } in GameConfig — all three dimensions of difficulty tunable without touching AI logic. + +13. **AI waits when ball moves toward player (vx < 0):** Resets reaction timer and returns early — AI only acts when ball is heading toward its paddle, avoiding premature repositioning. + +14. **Physics.onResize() calls init() for full reposition:** Ensures paddle2 (and paddle1) are properly repositioned on window resize rather than just updating width/height dimensions. + ### Coverage Validation **Total v1 Requirements:** 37 @@ -111,11 +120,11 @@ progress: ### What Just Happened -Phase 01 complete. Plan 01-02 executed: Ball physics added to index.html — ball serves from center at 220px/s in random direction, bounces off top/bottom walls, deflects off Player 1 paddle with 5-zone angle control (-60 to +60 degrees), and accelerates by 18px/s per paddle hit. On-canvas speed debug display confirms speed increments and resets. Requirements CORE-01, CORE-02, CORE-03, CORE-04 satisfied. All 6 Phase 1 success criteria met. +Phase 02 Plan 01 executed: paddle2 added to GameState (mirrors paddle1 structure), Input extended with ArrowUp/ArrowDown + named handler refs + cleanup(), AI module added with predictive ray-cast interception (wall-bounce simulation) and 3 difficulty presets (AI_EASY/MEDIUM/HARD). Physics._checkPaddle2Collision() added with 5-zone deflection sending ball LEFT. Physics.update() extended with paddle2 movement branch. Requirements CORE-08, AI-01, AI-02, AI-03, AI-04 satisfied. ### What Comes Next -1. Execute Phase 2 — Second paddle (Player 2 / AI), scoring system, ball tunneling safeguards +1. Execute Phase 2 Plan 02 — mode selection UI, scoring system, win/game-over states, ball tunneling safeguards 2. Continue through phases 3-5 after Phase 2 complete ### Known Blockers @@ -128,7 +137,7 @@ None. ### Last Session -Stopped at: Phase 2 context gathered +Stopped at: Completed 02-01-PLAN.md --- diff --git a/.planning/phases/02-core-gameplay/02-01-SUMMARY.md b/.planning/phases/02-core-gameplay/02-01-SUMMARY.md new file mode 100644 index 0000000..65b5ab6 --- /dev/null +++ b/.planning/phases/02-core-gameplay/02-01-SUMMARY.md @@ -0,0 +1,106 @@ +--- +phase: 02-core-gameplay +plan: 01 +subsystem: gameplay +tags: [canvas, vanilla-js, ai, physics, input, pong] + +# Dependency graph +requires: + - phase: 01-foundation + provides: GameConfig, GameState.paddle1, GameState.ball, Physics (update/collide/serve), Input (W/S), Renderer, GameLoop +provides: + - GameState.paddle2 object (mirrors paddle1 structure, positioned on right side) + - GameConfig.WIN_SCORE and AI_EASY/AI_MEDIUM/AI_HARD difficulty presets + - Input.getVerticalInput2() for ArrowUp/ArrowDown keys + - Input.cleanup() with named handler refs for event listener removal + - AI object with predictive ray-cast interception (wall-bounce simulation) + - Physics._checkPaddle2Collision() with 5-zone deflection sending ball LEFT + - Physics.update() extended with paddle2 movement branch (mode: '2p' or 'ai') + - GameState.score1, score2, mode, difficulty, gameState, winner fields +affects: [02-02, 02-core-gameplay] + +# Tech tracking +tech-stack: + added: [] + patterns: + - "AI module as plain object with init/update/_predictBallY — same module-object pattern as Physics/Input" + - "Predictive ray-cast AI: steps through future positions with wall bounces instead of linear interpolation" + - "Difficulty preset as config object: { speed, reactionDelay, errorMargin } — all tunable from GameConfig" + - "Named event handler refs on Input (_handleKeyDown/_handleKeyUp) enable cleanup() for memory management" + +key-files: + created: [] + modified: + - index.html + +key-decisions: + - "AI waits when ball moves toward player (vx < 0), reacts only when ball approaches (vx > 0) — avoids premature repositioning" + - "Deadzone of 3px in AI movement prevents micro-jitter when paddle center is already near target" + - "Physics.onResize() now calls this.init() to fully reposition both paddles on window resize" + - "Paddle2 collision pushes ball.x = paddle.x - ball.radius - 1 (mirrored from paddle1's right-push)" + +patterns-established: + - "Mode guard in Physics.update(): GameState.mode === '2p' branches to human input, 'ai' branches to AI.update()" + - "Collision guards: ball.vx < 0 for paddle1, ball.vx > 0 for paddle2 — prevents wrong-direction collision checks" + +requirements-completed: [CORE-08, AI-01, AI-02, AI-03, AI-04] + +# Metrics +duration: 2min +completed: 2026-03-10 +--- + +# Phase 2 Plan 01: Paddle2 and AI Opponent Summary + +**GameState.paddle2 + full AI opponent module with predictive ray-cast interception and three tunable difficulty levels (easy/medium/hard)** + +## Performance + +- **Duration:** ~2 min +- **Started:** 2026-03-10T20:04:26Z +- **Completed:** 2026-03-10T20:06:12Z +- **Tasks:** 2 +- **Files modified:** 1 + +## Accomplishments +- Added paddle2 to GameState (mirrors paddle1 structure) and positioned it on right side in Physics.init() +- Extended Input with ArrowUp/ArrowDown support, named handler refs, and cleanup() method +- Added AI module with predictive ray-cast (_predictBallY simulates wall bounces) plus reaction delay and error margin per difficulty +- Added Physics._checkPaddle2Collision() using same 5-zone deflection as paddle1 but sends ball leftward +- Extended Physics.update() with paddle2 movement branch (2p human or ai mode) + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Extend GameConfig, GameState, and Input for two-player support** - `a2f0bc3` (feat) +2. **Task 2: Add AI module and extend Physics for paddle2 movement and collision** - `398bc4a` (feat) + +## Files Created/Modified +- `/home/dabit/projects/gijs/index.html` - Added WIN_SCORE/AI presets to GameConfig; paddle2/score/mode/difficulty/gameState/winner to GameState; refactored Input with named handlers + getVerticalInput2(); extended Physics.init() and onResize(); added _checkPaddle2Collision(); extended Physics.update() for paddle2; added AI object; added AI.init() to init block + +## Decisions Made +- Physics.onResize() now calls this.init() instead of just updating width/height, so paddle2 gets repositioned on resize +- AI reaction timer resets to 0 whenever ball.vx < 0 (ball moving toward player) — AI fully waits before reacting again once ball returns +- Deadzone of 3px prevents AI paddle jitter when already near target + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered + +None. + +## User Setup Required + +None - no external service configuration required. + +## Next Phase Readiness +- paddle2 exists with valid x/y/width/height/speed/color — ready for Renderer to draw it in Plan 02-02 +- AI.update() fires when GameState.mode === 'ai' — mode selection UI needed (Plan 02-02) +- Score tracking fields (score1, score2) and gameState state machine fields are wired and ready for Plan 02-02 scoring logic + +--- +*Phase: 02-core-gameplay* +*Completed: 2026-03-10*