Commit Graph

3 Commits

Author SHA1 Message Date
aevgarik
cff8656f0b Sprite sync hardening, fix double-centering, extract Bumper outward-force to testable helper
## Codex review on 6bb1c81

### #1 Critical (corrected): visible ball not syncing

Codex заявил что ball.syncSprite() нигде не вызывается. Это неверно —
syncSprite вызывается каждый update tick на MatchScene.ts:216 (grep
подтверждает). Но описанный симптом (ball визуально не двигается) —
реальная проблема и требует hardening.

Hardening:
- Ball.setPosition() теперь immediate-sync sprite вместе с physics body.
  Раньше при teleport (stuck nudge, hard respawn) sprite оставался на
  старой позиции до следующего update tick — теоретическая 1-frame
  рассинхронизация устранена.
- Ball sprite получил setDepth(30) — выше fixed/setup bumper'ов чтобы
  не быть случайно перекрытым в render order.

### #2 High: double-centering canvas

Корень: #game-container использовал display:flex justify-content:center,
И Phaser Scale.CENTER_BOTH добавлял margin-left на canvas. Оба
центрирования складывались → canvas сдвинут вправо.

Fix: убрал flex из #game-container, оставил только Phaser CENTER_BOTH
(он надёжно центрирует через computed margin'ы).

### #3 Medium: physics fix не тестируется

Extract Bumper outward-force logic в pure helper src/game/bumperPhysics.ts
(computeOutwardForce). Возвращает new velocity или null если apply не
нужен.

src/game/bumperPhysics.test.ts — 10 unit-тестов:
- happy paths: fast outward, fast diagonal outward → null
- force apply: slow outward (still apply min speed), fast inward,
  zero velocity, fast tangential (radial<threshold)
- direction correctness: ball over bumper → outward up; ball diagonal
  → outward по диагонали 45°
- degenerate: ball точно в центре bumper → fallback вверх
- REAL stuck regression: low speed + radial nearly zero → force outward

Bumper.handleBallHit рефактор: вызывает computeOutwardForce, applies
если non-null.

117/117 tests (было 107). typecheck/lint/build .

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 13:24:47 +03:00
aevgarik
bb9f7209ae Post-codex-review-2: mobile controls, turbo bug, AI diff, favicon
- Mobile match controls (codex #1 High): 3 touch zones внизу MatchScene
  (L / BOOST / R). Visible semi-transparent overlay'и; работает и на mouse,
  и на touch. Keyboard input теперь optional (this.keys?), не падает на
  headless mobile.
- Turbo first-hit bug (codex #2): guard на lastHitTime > 0 — иначе первый
  удар по turbo в первую секунду давал 0 очков (now < 0 + 1000).
- AI behavior diff (codex #3): добавлен PersonalityModifier (triggerDistBonus,
  reliabilityMul, reactionMul). Defensive: +reliability, -reaction.
  Aggressive: +trigger distance, -reliability. Ghost: 15% «эхо-double-swing»
  (обе стороны одновременно). Trickster уже имел jitter modifier.
  Поведенческие отличия теперь должны быть различимы за 5 матчей.
- Favicon 404 (codex #4 Low): inline SVG favicon в index.html, no more
  console noise.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 03:59:41 +03:00
dc53623001 Phase 0-2: Vite/Phaser 4/TS boilerplate + Platform Adapter + core match (vs 4 AI personalities)
Phase 0 (foundation):
- package.json, tsconfig.json (strict), vite.config.ts (base: './'), .eslintrc.cjs
- index.html, src/main.ts (Phaser game init + platform detection)
- src/config/defaults.ts (Remote Config defaults, palette, constants)
- src/types/index.ts (все schemas из data-contracts: SaveState, MatchResult, RemoteConfig, etc.)
- src/platform/: PlatformAdapter interface + MockPlatformAdapter + YgPlatformAdapter

Phase 1 (core mechanics):
- src/scenes/: Boot, Preload, MainMenu (Quick Match selector), Setup, Match, Result
- src/game/: Table (геометрия + walls + ворота), Ball (last-touch + color tracking), Flipper (player + AI, swing + cooldown), Bumper (4 типа: standard/slingshot/curve/turbo)
- src/scoring/: MatchTracker (last-touch + bumper points), calculateScores (unified scoring pipeline per data-contracts v3.8 requirement)
- src/ai/: AIPlayer interface + DefensiveAI Easy/Medium

Phase 2 (setup + AI personalities):
- src/scenes/SetupScene (5 active slots, click-cycle bumper types, 30s timer)
- src/ai/personalities/: AggressiveAI, TricksterAI, GhostAI (Easy/Medium; Hard cradle-aim = Phase 3)
- src/ai/factory.ts (createAIPlayer)
- MainMenuScene: выбор AI-личности + сложности
- MatchScene использует factory вместо хардкода

Anti-A2W enforcement: calculateScores применяет penalty per v3.5 model
(Continue × 0.5, Campaign Skip × 0.7, +1 заряд × 0.9, реролл × 0.85,
Boost active × 0.7; ×2 sezon очки только в local).

Что НЕ в этом commit'е (следующие фазы):
- Phase 3: бустер «Захват» (cradle + slow-mo), Hard AI (cradle-aim solver), Ghost adaptation, YG Player API cloud-save, achievements
- Phase 4: Campaign (12 матчей), Tournament (8/16 bracket), шейдеры (CRT + bloom + chromatic aberration), 29 AI-арт ассетов, музыка
- Phase 5: реальная YG SDK интеграция (ads + payments), Remote Config Nakama RPC
- Phase 6: YG submission

Pre-greenlit concept-пакет — ~/Knowledge/Projects/pinball-duel/ (19 файлов, 10 audit-раундов).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 03:25:17 +03:00