diff --git a/docs/OnitamaGamePatterns.md b/docs/OnitamaGamePatterns.md new file mode 100644 index 0000000..c626602 --- /dev/null +++ b/docs/OnitamaGamePatterns.md @@ -0,0 +1,105 @@ +# Game Architecture Patterns & Practices + +> Reference guide for implementing board games using `boardgame-phaser` framework. +> Explore `packages/onitama-game/` and `packages/sample-game/` for concrete implementations. + +## Architecture Overview + +Games follow a layered architecture separating logic, presentation, and UI state: + +``` +packages/my-game/ +├── src/ +│ ├── game/ # Pure game logic (re-exported from boardgame-core) +│ ├── scenes/ # Phaser scenes (MenuScene, GameScene) +│ ├── spawners/ # Data-driven object lifecycle +│ ├── renderers/ # Renderers for game objects +│ ├── state/ # UI-only reactive state +│ ├── config.ts # Centralized layout & style constants +│ └── ui/App.tsx # Preact root component +``` + +| Layer | Responsibility | +|-------|----------------| +| `game/` | State, commands, prompts, validation (pure logic) | +| `scenes/` | Phaser lifecycle, input handling, visual composition | +| `spawners/` | Reactive game object spawn/update/despawn | +| `renderers/` | Phaser visual representation of game objects | +| `state/` | UI-only reactive state (selection, hover, etc.) | +| `ui/` | Preact components bridging Phaser and DOM | + +## Core Patterns + +### 1. ReactiveScene / GameHostScene +Extend `ReactiveScene`(`packages\framework\src\scenes\ReactiveScene.ts`) to use reactive integration features. +- Access game context for scene navigation +- Use `this.disposables` for auto-cleanup on shutdown. + +### 2. Spawner Pattern +Implement `Spawner` for data-driven objects. +- `*getData()`: Yield objects that should exist. +- `getKey()`: Unique identifier for diffing. +- `onSpawn()`: Create Phaser objects. +- `onUpdate()`: Handle data changes (animate if needed). +- `onDespawn()`: Clean up with optional animation. +- See: `packages/onitama-game/src/spawners/` + +### 3. Reactive UI State +Use `MutableSignal` for UI-only state, separate from game state. +- Mutate via `.produce()`. +- React via `effect()` from `@preact/signals-core`. +- Clean up effects on object `'destroy'` to prevent leaks. +- See: `packages/onitama-game/src/state/ui.ts` + +### 4. Custom Containers +Extend `Phaser.GameObjects.Container` to encapsulate visuals and state. +- Store logical state as private signals. +- Use `effect()` for reactive highlights/selections. + +### 5. Tween Interruption +Always register state-related tweens: `this.scene.addTweenInterruption(tween)`. +Prevents visual glitches when game state changes mid-animation. + +### 6. Scene Navigation +Use `await this.sceneController.launch('SceneKey')`. +Register scenes in `App.tsx` via ``. Pass data via `data` prop. + +## Best Practices + +- **Centralize Config**: Keep `CELL_SIZE`, `BOARD_OFFSET`, colors, etc., in `src/config.ts` with `as const`. Avoid magic numbers. +- **Type Imports**: Use `import type { Foo } from 'bar'` for type-only imports. +- **Input Handling**: Use `this.add.zone()` for grid/cell-based input zones. +- **Cleanup**: Always dispose `effect()` on `'destroy'`. Use `this.disposables.add()` for scene-level resources. + +## Common Pitfalls + +| Pitfall | Solution | +|---------|----------| +| Duplicate constants across files | Export from single `config.ts` or shared spawner | +| Missing tween interruptions | Always call `addTweenInterruption()` | +| Effect memory leaks | `this.on('destroy', () => dispose())` | +| Hardcoded magic numbers | Extract to `src/config.ts` | +| UI state staleness | Clear related selections on state change | + +## Testing +Add Vitest for UI state transitions, coordinate conversions, and spawner logic. +See `packages/framework/` for test setup examples. + +## Quick Reference + +| Pattern | Purpose | +|---------|---------| +| `GameHostScene` | Connect Phaser to game host | +| `Spawner` | Reactive object lifecycle | +| `MutableSignal` | UI-only reactive state | +| `effect()` | React to signal changes in Phaser objects | +| `addTweenInterruption()` | Prevent animation race conditions | +| `sceneController.launch()` | Navigate between scenes | +| `spawnEffect()` | Register spawners | +| `this.disposables.add()` | Auto-cleanup resources | + +## Related Documents +- `AGENTS.md` — Project overview, commands, and code style +- `docs/GameModule.md` — GameModule implementation guide +- `packages/framework/src/` — `boardgame-phaser` source code +- `packages/onitama-game/src/` — Complete game implementation reference \ No newline at end of file