update: various improvements

This commit is contained in:
2026-04-03 19:39:07 +08:00
parent cb7f492bea
commit 656c33cb59
5 changed files with 164 additions and 37 deletions
+36 -4
View File
@@ -1,6 +1,5 @@
import Phaser from 'phaser';
import type { TicTacToeState, TicTacToePart, PlayerType } from '@/game/tic-tac-toe';
import { isCellOccupied } from 'boardgame-core';
import { ReactiveScene, bindRegion, createInputMapper, createPromptHandler } from 'boardgame-phaser';
import type { PromptEvent } from 'boardgame-core';
@@ -48,7 +47,7 @@ export class GameScene extends ReactiveScene<TicTacToeState> {
bindRegion<TicTacToeState, { player: PlayerType }>(
this.state,
(state) => state.parts,
this.state.value.board,
(state) => state.board,
{
cellSize: { x: CELL_SIZE, y: CELL_SIZE },
offset: BOARD_OFFSET,
@@ -59,6 +58,15 @@ export class GameScene extends ReactiveScene<TicTacToeState> {
color: part.player === 'X' ? '#3b82f6' : '#ef4444',
}).setOrigin(0.5);
// 添加落子动画
text.setScale(0);
this.tweens.add({
targets: text,
scale: 1,
duration: 200,
ease: 'Back.easeOut',
});
return text;
},
update: (part, obj) => {
@@ -69,8 +77,32 @@ export class GameScene extends ReactiveScene<TicTacToeState> {
);
}
private isCellOccupied(row: number, col: number): boolean {
const state = this.state.value;
return !!state.board.partMap[`${row},${col}`];
}
private setupInput(): void {
this.inputMapper = createInputMapper(this, this.commands);
const scene = this;
const activePromptRef = {
get current() { return scene.activePrompt; }
};
this.inputMapper = createInputMapper(
this,
this.commands,
activePromptRef,
(cmd: string) => {
const activePrompt = this.activePrompt;
if (!activePrompt) return 'No active prompt';
const error = activePrompt.tryCommit(cmd);
if (error === null) {
this.activePrompt = null;
this.promptHandler.start();
}
return error;
}
);
this.inputMapper.mapGridClick(
{ x: CELL_SIZE, y: CELL_SIZE },
@@ -80,7 +112,7 @@ export class GameScene extends ReactiveScene<TicTacToeState> {
if (this.state.value.winner) return null;
const currentPlayer = this.state.value.currentPlayer;
if (isCellOccupied(this.state.value.parts, 'board', [row, col])) return null;
if (this.isCellOccupied(row, col)) return null;
return `play ${currentPlayer} ${row} ${col}`;
},