boardgame-phaser/packages/boop-game/src/scenes/GameScene.ts

87 lines
2.5 KiB
TypeScript
Raw Normal View History

import type { BoopState } from '@/game';
2026-04-04 14:22:35 +08:00
import { GameHostScene } from 'boardgame-phaser';
import { commands } from '@/game';
2026-04-04 16:25:36 +08:00
import { BoardRenderer } from './BoardRenderer';
import { createPieceSpawner } from './PieceSpawner';
import { SupplyUI } from './SupplyUI';
import { PieceTypeSelector } from './PieceTypeSelector';
import { WinnerOverlay } from './WinnerOverlay';
2026-04-05 00:12:05 +08:00
import { StartOverlay } from './StartOverlay';
2026-04-04 14:22:35 +08:00
export class GameScene extends GameHostScene<BoopState> {
2026-04-04 16:25:36 +08:00
private boardRenderer!: BoardRenderer;
private supplyUI!: SupplyUI;
private pieceTypeSelector!: PieceTypeSelector;
private winnerOverlay!: WinnerOverlay;
2026-04-05 00:12:05 +08:00
private startOverlay!: StartOverlay;
2026-04-04 14:22:35 +08:00
constructor() {
super('GameScene');
}
create(): void {
super.create();
2026-04-04 16:25:36 +08:00
// 初始化 UI 组件
this.boardRenderer = new BoardRenderer(this);
this.supplyUI = new SupplyUI(this);
this.pieceTypeSelector = new PieceTypeSelector(this);
this.winnerOverlay = new WinnerOverlay(this, () => this.restartGame());
2026-04-05 00:12:05 +08:00
this.startOverlay = new StartOverlay(this, () => this.startGame());
2026-04-04 16:25:36 +08:00
// 设置棋子生成器
this.disposables.add(createPieceSpawner(this));
2026-04-04 14:22:35 +08:00
2026-04-04 16:25:36 +08:00
// 设置输入处理
2026-04-04 23:25:43 +08:00
this.boardRenderer.setupInput(
() => this.state,
(row, col) => this.handleCellClick(row, col),
2026-04-05 00:12:05 +08:00
() => this.gameHost.status.value !== 'running' || !!this.state.winner
2026-04-04 23:25:43 +08:00
);
2026-04-04 14:22:35 +08:00
2026-04-05 00:12:05 +08:00
// 监听游戏状态变化
this.addEffect(() => {
const status = this.gameHost.status.value;
if (status === 'running') {
this.startOverlay.hide();
} else if (status === 'created') {
this.startOverlay.show();
}
});
// 监听胜负状态
2026-04-04 16:34:17 +08:00
this.addEffect(() => {
2026-04-04 14:22:35 +08:00
const winner = this.state.winner;
if (winner) {
2026-04-04 16:25:36 +08:00
this.winnerOverlay.show(winner);
} else {
this.winnerOverlay.hide();
2026-04-04 14:22:35 +08:00
}
});
2026-04-04 16:34:17 +08:00
this.addEffect(() => {
2026-04-04 14:22:35 +08:00
const currentPlayer = this.state.currentPlayer;
2026-04-04 16:25:36 +08:00
this.boardRenderer.updateTurnText(currentPlayer, this.state);
this.supplyUI.update(this.state);
this.pieceTypeSelector.update(this.state);
2026-04-04 14:22:35 +08:00
});
}
2026-04-04 16:25:36 +08:00
private handleCellClick(row: number, col: number): void {
const selectedType = this.pieceTypeSelector.getSelectedType();
const cmd = commands.play(this.state.currentPlayer, row, col, selectedType);
const error = this.gameHost.onInput(cmd);
if (error) {
console.warn('Invalid move:', error);
2026-04-04 14:22:35 +08:00
}
}
2026-04-05 00:12:05 +08:00
private startGame(): void {
this.gameHost.setup('setup');
}
2026-04-04 16:25:36 +08:00
private restartGame(): void {
this.gameHost.setup('setup');
2026-04-04 14:22:35 +08:00
}
}