refactor(sts-like-viewer): simplify scene management and config

- Move configuration to `src/config/index.ts`
- Simplify `App.tsx` by passing scene classes directly to `PhaserScene`
- Update `GameUI` initialization to use string ID for container
- Update documentation to mention `initData` for `ReactiveScene`
- Standardize quote usage and formatting in config files
This commit is contained in:
hypercross 2026-04-20 15:24:07 +08:00
parent 2d412eedb5
commit 1d803dd219
4 changed files with 40 additions and 58 deletions

View File

@ -32,8 +32,8 @@ packages/my-game/
### 1. ReactiveScene / GameHostScene ### 1. ReactiveScene / GameHostScene
Extend `ReactiveScene`(`packages\framework\src\scenes\ReactiveScene.ts`) to use reactive integration features. 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. - Use `this.disposables` for auto-cleanup on shutdown.
- Use `initData` for context data passed from the `<PhaserScene/>` preact component.
### 2. Spawner Pattern ### 2. Spawner Pattern
Implement `Spawner<TData, TObj>` for data-driven objects. Implement `Spawner<TData, TObj>` for data-driven objects.

View File

@ -3,6 +3,8 @@
* All magic numbers should be defined here and imported where needed. * All magic numbers should be defined here and imported where needed.
*/ */
import { PhaserGameProps } from "boardgame-phaser";
// ── Map Layout ────────────────────────────────────────────────────────────── // ── Map Layout ──────────────────────────────────────────────────────────────
export const MAP_CONFIG = { export const MAP_CONFIG = {
@ -83,9 +85,9 @@ export const UI_CONFIG = {
/** Button border color */ /** Button border color */
BUTTON_BORDER: 0x7777aa, BUTTON_BORDER: 0x7777aa,
/** Button text color */ /** Button text color */
BUTTON_TEXT_COLOR: '#ffffff', BUTTON_TEXT_COLOR: "#ffffff",
/** Button font size */ /** Button font size */
BUTTON_FONT_SIZE: '16px', BUTTON_FONT_SIZE: "16px",
} as const; } as const;
// ── Colors ────────────────────────────────────────────────────────────────── // ── Colors ──────────────────────────────────────────────────────────────────
@ -102,14 +104,14 @@ export const NODE_COLORS = {
} as const; } as const;
export const NODE_LABELS = { export const NODE_LABELS = {
start: '起点', start: "起点",
end: '终点', end: "终点",
minion: '战斗', minion: "战斗",
elite: '精英', elite: "精英",
event: '事件', event: "事件",
camp: '营地', camp: "营地",
shop: '商店', shop: "商店",
curio: '奇遇', curio: "奇遇",
} as const; } as const;
export const ITEM_COLORS = [ export const ITEM_COLORS = [
@ -118,5 +120,20 @@ export const ITEM_COLORS = [
// ── Positive/Negative Effects (for buff icons) ────────────────────────────── // ── Positive/Negative Effects (for buff icons) ──────────────────────────────
export const POSITIVE_EFFECTS = new Set(['block', 'strength', 'dexterity', 'regen']); export const POSITIVE_EFFECTS = new Set([
export const NEGATIVE_EFFECTS = new Set(['weak', 'vulnerable', 'frail', 'poison']); "block",
"strength",
"dexterity",
"regen",
]);
export const NEGATIVE_EFFECTS = new Set([
"weak",
"vulnerable",
"frail",
"poison",
]);
export const GAME_CONFIG: Phaser.Types.Core.GameConfig = {
width: 1920,
height: 1080,
};

View File

@ -1,10 +1,9 @@
import { h } from 'preact'; import { GameUI } from "boardgame-phaser";
import { GameUI } from 'boardgame-phaser'; import "./style.css";
import './style.css';
import App from "@/ui/App"; import App from "@/ui/App";
const ui = new GameUI({ const ui = new GameUI({
container: document.getElementById('ui-root')!, container: "ui-root",
root: <App />, root: <App />,
}); });

View File

@ -1,53 +1,19 @@
import { h } from "preact";
import { PhaserGame, PhaserScene } from "boardgame-phaser"; import { PhaserGame, PhaserScene } from "boardgame-phaser";
import { useMemo } from "preact/hooks";
import { IndexScene } from "@/scenes/IndexScene"; import { IndexScene } from "@/scenes/IndexScene";
import { MapViewerScene } from "@/scenes/MapViewerScene"; import { MapViewerScene } from "@/scenes/MapViewerScene";
import { GridViewerScene } from "@/scenes/GridViewerScene"; import { GridViewerScene } from "@/scenes/GridViewerScene";
import { ShapeViewerScene } from "@/scenes/ShapeViewerScene"; import { ShapeViewerScene } from "@/scenes/ShapeViewerScene";
import { GameFlowScene } from "@/scenes/GameFlowScene"; import { GAME_CONFIG } from "@/config";
import { PlaceholderEncounterScene } from "@/scenes/PlaceholderEncounterScene";
import { createGameState } from "@/state/gameState";
// 全局游戏状态单例
const gameState = createGameState();
export default function App() { export default function App() {
const indexScene = useMemo(() => new IndexScene(), []);
const mapViewerScene = useMemo(() => new MapViewerScene(), []);
const gridViewerScene = useMemo(() => new GridViewerScene(), []);
const shapeViewerScene = useMemo(() => new ShapeViewerScene(), []);
const gameFlowScene = useMemo(() => new GameFlowScene(gameState), []);
const placeholderEncounterScene = useMemo(
() => new PlaceholderEncounterScene(gameState),
[],
);
return ( return (
<div className="flex flex-col h-screen"> <div className="flex flex-col h-screen">
<div className="flex-1 flex relative justify-center items-center"> <div className="flex-1 flex relative justify-center items-center">
<PhaserGame <PhaserGame initialScene="IndexScene" config={GAME_CONFIG}>
initialScene="IndexScene" <PhaserScene scene={IndexScene} />
config={{ width: 1920, height: 1080 }} <PhaserScene scene={MapViewerScene} />
> <PhaserScene scene={GridViewerScene} />
<PhaserScene sceneKey="IndexScene" scene={indexScene as any} /> <PhaserScene scene={ShapeViewerScene} />
<PhaserScene
sceneKey="MapViewerScene"
scene={mapViewerScene as any}
/>
<PhaserScene
sceneKey="GridViewerScene"
scene={gridViewerScene as any}
/>
<PhaserScene
sceneKey="ShapeViewerScene"
scene={shapeViewerScene as any}
/>
<PhaserScene sceneKey="GameFlowScene" scene={gameFlowScene as any} />
<PhaserScene
sceneKey="PlaceholderEncounterScene"
scene={placeholderEncounterScene as any}
/>
</PhaserGame> </PhaserGame>
</div> </div>
</div> </div>