Compare commits

...

2 Commits

Author SHA1 Message Date
hypercross 82df3f2a2f docs: update game patterns documentation 2026-04-19 13:10:09 +08:00
hypercross 4d34f9fa78 refactor(framework): use callback instead of events in
dragDropEventEffect

Replace Phaser event emissions with a `DragDropCallback` in
`dragDropEventEffect` to provide a more explicit and type-safe API
for handling drag-and-drop interactions.
2026-04-19 13:04:53 +08:00
4 changed files with 18 additions and 11 deletions

View File

@ -13,7 +13,7 @@ packages/my-game/
│ ├── game/ # Pure game logic (re-exported from boardgame-core)
│ ├── scenes/ # Phaser scenes (MenuScene, GameScene)
│ ├── spawners/ # Data-driven object lifecycle
│ ├── renderers/ # Renderers for game objects
│ ├── gameobjects/ # Phaser GameObject or Container extensions
│ ├── state/ # UI-only reactive state
│ ├── config.ts # Centralized layout & style constants
│ └── ui/App.tsx # Preact root component
@ -24,7 +24,7 @@ packages/my-game/
| `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 |
| `gameobjects/` | Phaser GameObjects or containers |
| `state/` | UI-only reactive state (selection, hover, etc.) |
| `ui/` | Preact components bridging Phaser and DOM |
@ -51,9 +51,9 @@ Use `MutableSignal` for UI-only state, separate from game state.
- Clean up effects on object `'destroy'` to prevent leaks.
- See: `packages/onitama-game/src/state/ui.ts`
### 4. Custom Containers
### 4. Custom GameObjects / Containers
Extend `Phaser.GameObjects.Container` to encapsulate visuals and state.
- Store logical state as private signals.
- Use signals from `states/`, avoid relying on complex interal state.
- Use `effect()` for reactive highlights/selections.
### 5. Tween Interruption
@ -66,6 +66,12 @@ Otherwise the game logic will hang.
Use `await this.sceneController.launch('SceneKey')`.
Register scenes in `App.tsx` via `<PhaserScene>`. Pass data via `data` prop.
### 7. Central Config
Use `src/config/layout.ts` for shared constants like `CELL_SIZE`, `BOARD_OFFSET`, etc.
Use `src/config/colors.ts` for shared colors.
Use `src/config/text.ts` for text styles.
## Best Practices
- **Centralize Config**: Keep `CELL_SIZE`, `BOARD_OFFSET`, colors, etc., in `src/config.ts` with `as const`. Avoid magic numbers.

View File

@ -4,7 +4,7 @@ export type { IDisposable, DisposableItem } from "./utils";
// Drag & drop utilities
export { dragDropEventEffect, DragDropEventType } from "./utils";
export type { DragDropEvent } from "./utils";
export type { DragDropEvent, DragDropCallback } from "./utils";
// Data-driven object spawning
export { spawnEffect } from "./spawner";

View File

@ -18,8 +18,11 @@ export type DragDropEvent = {
deltaY: number;
};
export type DragDropCallback = (event: DragDropEvent) => void;
export function dragDropEventEffect(
gameObject: Phaser.GameObjects.GameObject,
callback: DragDropCallback,
disposables?: DisposableBag,
): () => void {
let isDragging = false;
@ -35,8 +38,7 @@ export function dragDropEventEffect(
deltaX: 0,
deltaY: 0,
};
gameObject.emit("drag", event);
gameObject.emit("dragstart", event);
callback(event);
}
function onPointerUp(pointer: Phaser.Input.Pointer) {
@ -46,8 +48,7 @@ export function dragDropEventEffect(
const deltaX = pointer.x - down.x;
const deltaY = pointer.y - down.y;
const event: DragDropEvent = { type: DragDropEventType.UP, deltaX, deltaY };
gameObject.emit("drag", event);
gameObject.emit("dragend", event);
callback(event);
down = null;
}
@ -61,8 +62,7 @@ export function dragDropEventEffect(
deltaX,
deltaY,
};
gameObject.emit("drag", event);
gameObject.emit("dragmove", event);
callback(event);
}
gameObject.on("pointerdown", onPointerDown);

View File

@ -4,4 +4,5 @@ export {
dragDropEventEffect,
DragDropEventType,
type DragDropEvent,
type DragDropCallback,
} from "./dnd";