feat: error reporting
This commit is contained in:
parent
c678974489
commit
2f0fb2bca8
|
|
@ -30,7 +30,7 @@ async function place(game: BoopGame, row: number, col: number, player: PlayerTyp
|
|||
const part = findPartInRegion(game, player, type);
|
||||
|
||||
if (!part) {
|
||||
throw new Error(`No ${type} available in ${player}'s supply`);
|
||||
throw new Error(`${player} 的 supply 中没有可用的 ${type}`);
|
||||
}
|
||||
|
||||
const partId = part.id;
|
||||
|
|
@ -180,15 +180,15 @@ async function checkFullBoard(game: BoopGame, turnPlayer: PlayerType){
|
|||
(command: Command) => {
|
||||
const [player, row, col] = command.params as [PlayerType, number, number];
|
||||
if (player !== turnPlayer) {
|
||||
throw `Invalid player: ${player}. Expected ${turnPlayer}.`;
|
||||
throw `无效的玩家: ${player},期望的是 ${turnPlayer}。`;
|
||||
}
|
||||
if (!isInBounds(row, col)) {
|
||||
throw `Invalid position: (${row}, ${col}). Must be between 0 and ${BOARD_SIZE - 1}.`;
|
||||
throw `无效的位置: (${row}, ${col}),必须在 0 到 ${BOARD_SIZE - 1} 之间。`;
|
||||
}
|
||||
|
||||
const part = findPartAtPosition(game, row, col);
|
||||
if (!part || part.player !== turnPlayer) {
|
||||
throw `No ${player} piece at (${row}, ${col}).`;
|
||||
throw `(${row}, ${col}) 位置没有 ${player} 的棋子。`;
|
||||
}
|
||||
|
||||
return part.id;
|
||||
|
|
@ -211,18 +211,18 @@ async function turn(game: BoopGame, turnPlayer: PlayerType) {
|
|||
const pieceType = type === 'cat' ? 'cat' : 'kitten';
|
||||
|
||||
if (player !== turnPlayer) {
|
||||
throw `Invalid player: ${player}. Expected ${turnPlayer}.`;
|
||||
throw `无效的玩家: ${player},期望的是 ${turnPlayer}。`;
|
||||
}
|
||||
if (!isInBounds(row, col)) {
|
||||
throw `Invalid position: (${row}, ${col}). Must be between 0 and ${BOARD_SIZE - 1}.`;
|
||||
throw `无效的位置: (${row}, ${col}),必须在 0 到 ${BOARD_SIZE - 1} 之间。`;
|
||||
}
|
||||
if (isCellOccupied(game, row, col)) {
|
||||
throw `Cell (${row}, ${col}) is already occupied.`;
|
||||
throw `单元格 (${row}, ${col}) 已被占用。`;
|
||||
}
|
||||
|
||||
const found = findPartInRegion(game, player, pieceType);
|
||||
if (!found) {
|
||||
throw `No ${pieceType}s left in ${player}'s supply.`;
|
||||
throw `${player} 的 supply 中没有 ${pieceType === 'cat' ? '大猫' : '小猫'} 了。`;
|
||||
}
|
||||
return {player, row,col,type};
|
||||
},
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export class BoardRenderer {
|
|||
this.infoText = this.scene.add.text(
|
||||
BOARD_OFFSET.x + (BOARD_SIZE * CELL_SIZE) / 2,
|
||||
BOARD_OFFSET.y + BOARD_SIZE * CELL_SIZE + 60,
|
||||
'Click to place kitten. Cats win with 3 in a row!',
|
||||
'点击空白处放置小猫,三个大猫连线获胜!',
|
||||
{
|
||||
fontSize: '16px',
|
||||
fontFamily: 'Arial',
|
||||
|
|
@ -91,31 +91,6 @@ export class BoardRenderer {
|
|||
setupInput(
|
||||
getState: () => BoopState,
|
||||
onCellClick: (row: number, col: number) => void,
|
||||
checkWinner: () => boolean
|
||||
): void {
|
||||
for (let row = 0; row < BOARD_SIZE; row++) {
|
||||
for (let col = 0; col < BOARD_SIZE; col++) {
|
||||
const x = BOARD_OFFSET.x + col * CELL_SIZE + CELL_SIZE / 2;
|
||||
const y = BOARD_OFFSET.y + row * CELL_SIZE + CELL_SIZE / 2;
|
||||
|
||||
const zone = this.scene.add.zone(x, y, CELL_SIZE, CELL_SIZE).setInteractive();
|
||||
|
||||
zone.on('pointerdown', () => {
|
||||
const state = getState();
|
||||
const isOccupied = !!state.regions.board.partMap[`${row},${col}`];
|
||||
if (!isOccupied && !checkWinner()) {
|
||||
onCellClick(row, col);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置棋盘上棋子的点击处理(用于选择要升级的棋子)
|
||||
*/
|
||||
setupPieceInput(
|
||||
getState: () => BoopState,
|
||||
onPieceClick: (row: number, col: number) => void,
|
||||
checkWinner: () => boolean
|
||||
): void {
|
||||
|
|
@ -129,22 +104,18 @@ export class BoardRenderer {
|
|||
zone.on('pointerdown', () => {
|
||||
const state = getState();
|
||||
const isOccupied = !!state.regions.board.partMap[`${row},${col}`];
|
||||
if (isOccupied && !checkWinner()) {
|
||||
if (checkWinner()) return;
|
||||
|
||||
if (isOccupied) {
|
||||
onPieceClick(row, col);
|
||||
} else {
|
||||
onCellClick(row, col);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新棋盘上棋子的交互状态
|
||||
*/
|
||||
updatePieceInteraction(enabled: boolean): void {
|
||||
// 可以通过此方法启用/禁用棋子点击
|
||||
// 暂时通过重新设置 zone 的 interactive 状态来实现
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
this.container.destroy();
|
||||
this.gridGraphics.destroy();
|
||||
|
|
|
|||
|
|
@ -36,30 +36,28 @@ export class ErrorOverlay {
|
|||
|
||||
this.overlay.add(bg);
|
||||
|
||||
// 错误提示框
|
||||
const errorBoxY = BOARD_OFFSET.y + (BOARD_SIZE * CELL_SIZE) / 2 - 60;
|
||||
const errorBox = this.scene.add.container(
|
||||
BOARD_OFFSET.x + (BOARD_SIZE * CELL_SIZE) / 2,
|
||||
errorBoxY
|
||||
);
|
||||
// 错误提示框(居中显示)
|
||||
const centerX = BOARD_OFFSET.x + (BOARD_SIZE * CELL_SIZE) / 2;
|
||||
const centerY = BOARD_OFFSET.y + (BOARD_SIZE * CELL_SIZE) / 2;
|
||||
const errorBox = this.scene.add.container(centerX, centerY);
|
||||
|
||||
// 错误框背景
|
||||
const boxBg = this.scene.add.rectangle(0, 0, 450, 100, 0xef4444, 0.95)
|
||||
.setStrokeStyle(4, 0xdc2626);
|
||||
|
||||
// 错误图标
|
||||
const iconText = this.scene.add.text(-180, 0, '❌', {
|
||||
const iconText = this.scene.add.text(-140, 0, '❌', {
|
||||
fontSize: '36px',
|
||||
}).setOrigin(0.5);
|
||||
|
||||
// 错误文本
|
||||
const errorText = this.scene.add.text(30, 0, message, {
|
||||
const errorText = this.scene.add.text(60, 0, message, {
|
||||
fontSize: '22px',
|
||||
fontFamily: 'Arial',
|
||||
color: '#ffffff',
|
||||
align: 'center',
|
||||
wordWrap: { width: 380 },
|
||||
}).setOrigin(0, 0.5);
|
||||
wordWrap: { width: 300 },
|
||||
}).setOrigin(0.5);
|
||||
|
||||
errorBox.add([boxBg, iconText, errorText]);
|
||||
this.overlay.add(errorBox);
|
||||
|
|
|
|||
|
|
@ -35,16 +35,10 @@ export class GameScene extends GameHostScene<BoopState> {
|
|||
// 设置棋子生成器
|
||||
this.disposables.add(createPieceSpawner(this));
|
||||
|
||||
// 设置输入处理
|
||||
// 设置输入处理(空单元格和已有棋子统一处理)
|
||||
this.boardRenderer.setupInput(
|
||||
() => this.state,
|
||||
(row, col) => this.handleCellClick(row, col),
|
||||
() => this.gameHost.status.value !== 'running' || !!this.state.winner
|
||||
);
|
||||
|
||||
// 设置棋子点击处理(用于棋盘满时选择要升级的棋子)
|
||||
this.boardRenderer.setupPieceInput(
|
||||
() => this.state,
|
||||
(row, col) => this.handlePieceClick(row, col),
|
||||
() => this.gameHost.status.value !== 'running' || !!this.state.winner
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue