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