import { h, render } from 'preact'; import { signal, computed } from '@preact/signals-core'; import { useEffect, useState, useCallback } from 'preact/hooks'; import Phaser from 'phaser'; import { createGameContext } from 'boardgame-core'; import { GameUI, PromptDialog, CommandLog, createPromptHandler } 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 commandLog = signal>([]); // 创建 PromptHandler 用于处理 UI 层的 prompt let promptHandler: ReturnType> | null = null; const promptSignal = signal>>(null); // 记录命令日志的辅助函数 function logCommand(input: string, result: { success: boolean; result?: unknown; error?: string }) { commandLog.value = [ ...commandLog.value, { input, result: result.success ? `OK: ${JSON.stringify(result.result)}` : `ERR: ${result.error}`, timestamp: Date.now(), }, ]; } function App() { const [phaserReady, setPhaserReady] = useState(false); const [game, setGame] = useState(null); const [scene, setScene] = useState(null); const [gameState, setGameState] = 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 const gameScene = new GameScene(); phaserGame.scene.add('GameScene', gameScene, true, { gameContext }); setGame(phaserGame); setScene(gameScene); setPhaserReady(true); return () => { phaserGame.destroy(true); }; }, []); useEffect(() => { if (phaserReady && scene) { // 初始化 PromptHandler promptHandler = createPromptHandler(scene, gameContext.commands, { onPrompt: (prompt) => { promptSignal.value = prompt; }, onCancel: () => { promptSignal.value = null; }, }); promptHandler.start(); // 监听状态变化 const dispose = gameContext.state.subscribe(() => { setGameState({ ...gameContext.state.value }); }); // 运行游戏设置 gameContext.commands.run('setup').then(result => { logCommand('setup', result); }); return () => { dispose(); }; } }, [phaserReady, scene]); const handlePromptSubmit = useCallback((input: string) => { if (promptHandler) { const error = promptHandler.submit(input); if (error === null) { logCommand(input, { success: true }); promptSignal.value = null; } else { logCommand(input, { success: false, error }); } } }, []); const handlePromptCancel = useCallback(() => { if (promptHandler) { promptHandler.cancel('User cancelled'); promptSignal.value = null; } }, []); const handleReset = useCallback(() => { gameContext.commands.run('reset').then(result => { logCommand('reset', result); }); }, []); return (
{/* 游戏状态显示 */} {gameState && !gameState.winner && (
{gameState.currentPlayer}'s Turn
)} {gameState?.winner && (
{gameState.winner === 'draw' ? "It's a Draw!" : `${gameState.winner} Wins!`}
)}
Command Log
); } const ui = new GameUI({ container: document.getElementById('ui-root')!, root: , }); ui.mount();