import { h, render } from 'preact'; import { signal } from '@preact/signals-core'; import { useEffect, useState } from 'preact/hooks'; import Phaser from 'phaser'; import { createGameContext } from 'boardgame-core'; import { GameUI, PromptDialog, CommandLog } from 'boardgame-phaser'; import { createInitialState, registry, type TicTacToeState } from './game/tic-tac-toe'; import { GameScene } from './scenes/GameScene'; import './style.css'; const gameContext = createGameContext(registry, createInitialState); const promptSignal = signal>>(null); const commandLog = signal>([]); // 监听 prompt 事件 gameContext.commands.on('prompt', (event) => { promptSignal.value = event; }); // 包装 run 方法以记录命令日志 const originalRun = gameContext.commands.run.bind(gameContext.commands); (gameContext.commands as any).run = async (input: string) => { const result = await originalRun(input); commandLog.value = [ ...commandLog.value, { input, result: result.success ? `OK: ${JSON.stringify(result.result)}` : `ERR: ${result.error}`, timestamp: Date.now(), }, ]; return result; }; function App() { const [phaserReady, setPhaserReady] = useState(false); const [game, setGame] = useState(null); useEffect(() => { const phaserConfig: Phaser.Types.Core.GameConfig = { type: Phaser.AUTO, width: 560, height: 560, parent: 'phaser-container', backgroundColor: '#f9fafb', scene: [], }; const phaserGame = new Phaser.Game(phaserConfig); // 通过 init 传递 gameContext phaserGame.scene.add('GameScene', GameScene, true, { gameContext }); setGame(phaserGame); setPhaserReady(true); return () => { phaserGame.destroy(true); }; }, []); useEffect(() => { if (phaserReady) { gameContext.commands.run('setup'); } }, [phaserReady]); return (
{ gameContext.commands._tryCommit(input); promptSignal.value = null; }} onCancel={() => { gameContext.commands._cancel('cancelled'); promptSignal.value = null; }} />
); } const ui = new GameUI({ container: document.getElementById('ui-root')!, root: , }); ui.mount();