fix: more issues with ui
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
import Phaser from 'phaser';
|
||||
import type { OnitamaState, PlayerType, Pawn } from '@/game/onitama';
|
||||
import { prompts } from '@/game/onitama';
|
||||
import type { OnitamaState, Pawn } from '@/game/onitama';
|
||||
import {getAvailableMoves, prompts} from '@/game/onitama';
|
||||
import { GameHostScene } from 'boardgame-phaser';
|
||||
import { spawnEffect } from 'boardgame-phaser';
|
||||
import { effect } from '@preact/signals-core';
|
||||
import type { MutableSignal } from 'boardgame-core';
|
||||
import { PawnSpawner, CardSpawner, BOARD_OFFSET, CELL_SIZE, CARD_WIDTH, CARD_HEIGHT, boardToScreen, BOARD_SIZE } from '@/spawners';
|
||||
import {
|
||||
PawnSpawner, CardSpawner, BOARD_OFFSET, CELL_SIZE, CARD_WIDTH, CARD_HEIGHT, boardToScreen, BOARD_SIZE,
|
||||
HighlightSpawner
|
||||
} from '@/spawners';
|
||||
import type { HighlightData } from '@/spawners/HighlightSpawner';
|
||||
import { createOnitamaUIState, clearSelection, selectPiece, selectCard, deselectCard, setValidMoves } from '@/state';
|
||||
import {createUIState, clearSelection, selectPiece, selectCard, createValidMoves} from '@/state';
|
||||
import type { OnitamaUIState, ValidMove } from '@/state';
|
||||
|
||||
export class OnitamaScene extends GameHostScene<OnitamaState> {
|
||||
@@ -19,8 +21,6 @@ export class OnitamaScene extends GameHostScene<OnitamaState> {
|
||||
|
||||
// UI State managed by MutableSignal
|
||||
public uiState!: MutableSignal<OnitamaUIState>;
|
||||
private highlightContainers: Map<string, Phaser.GameObjects.GameObject> = new Map();
|
||||
private highlightDispose?: () => void;
|
||||
|
||||
constructor() {
|
||||
super('OnitamaScene');
|
||||
@@ -30,14 +30,7 @@ export class OnitamaScene extends GameHostScene<OnitamaState> {
|
||||
super.create();
|
||||
|
||||
// Create UI state signal
|
||||
this.uiState = createOnitamaUIState();
|
||||
|
||||
// Cleanup effect on scene shutdown
|
||||
this.events.once('shutdown', () => {
|
||||
if (this.highlightDispose) {
|
||||
this.highlightDispose();
|
||||
}
|
||||
});
|
||||
this.uiState = createUIState();
|
||||
|
||||
this.boardContainer = this.add.container(0, 0);
|
||||
this.gridGraphics = this.add.graphics();
|
||||
@@ -46,16 +39,11 @@ export class OnitamaScene extends GameHostScene<OnitamaState> {
|
||||
// Add spawners
|
||||
this.disposables.add(spawnEffect(new PawnSpawner(this)));
|
||||
this.disposables.add(spawnEffect(new CardSpawner(this)));
|
||||
this.disposables.add(spawnEffect(new HighlightSpawner(this)));
|
||||
|
||||
// Create card labels
|
||||
this.createCardLabels();
|
||||
|
||||
// Setup highlight effect - react to validMoves changes
|
||||
this.highlightDispose = effect(() => {
|
||||
const validMoves = this.uiState.value.validMoves;
|
||||
this.updateHighlights(validMoves);
|
||||
});
|
||||
|
||||
// Winner overlay effect
|
||||
this.addEffect(() => {
|
||||
const winner = this.state.winner;
|
||||
@@ -201,43 +189,10 @@ export class OnitamaScene extends GameHostScene<OnitamaState> {
|
||||
|
||||
private handleCellClick(x: number, y: number): void {
|
||||
const pawn = this.getPawnAtPosition(x, y);
|
||||
|
||||
// 如果没有选中卡牌,提示先选卡牌
|
||||
if (!this.uiState.value.selectedCard) {
|
||||
console.log('请先选择一张卡牌');
|
||||
if(pawn?.owner !== this.state.currentPlayer){
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.uiState.value.selectedPiece) {
|
||||
// 已经选中了棋子
|
||||
if (pawn && pawn.owner === this.state.currentPlayer) {
|
||||
// 点击了自己的另一个棋子,更新选择
|
||||
selectPiece(this.uiState, x, y);
|
||||
this.updateValidMoves();
|
||||
return;
|
||||
}
|
||||
|
||||
const fromX = this.uiState.value.selectedPiece.x;
|
||||
const fromY = this.uiState.value.selectedPiece.y;
|
||||
|
||||
if (pawn && pawn.owner === this.state.currentPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 尝试移动到目标位置,必须使用选中的卡牌
|
||||
const validMoves = this.getValidMovesForPiece(fromX, fromY, [this.uiState.value.selectedCard]);
|
||||
|
||||
const targetMove = validMoves.find(m => m.toX === x && m.toY === y);
|
||||
if (targetMove) {
|
||||
this.executeMove(targetMove);
|
||||
}
|
||||
} else {
|
||||
// 还没有选中棋子
|
||||
if (pawn && pawn.owner === this.state.currentPlayer) {
|
||||
selectPiece(this.uiState, x, y);
|
||||
this.updateValidMoves();
|
||||
}
|
||||
}
|
||||
selectPiece(this.uiState, x, y);
|
||||
}
|
||||
|
||||
public onCardClick(cardId: string): void {
|
||||
@@ -250,23 +205,6 @@ export class OnitamaScene extends GameHostScene<OnitamaState> {
|
||||
}
|
||||
|
||||
selectCard(this.uiState, cardId);
|
||||
// 如果已经选中了棋子,更新有效移动
|
||||
if (this.uiState.value.selectedPiece) {
|
||||
this.updateValidMoves();
|
||||
}
|
||||
}
|
||||
|
||||
private updateValidMoves(): void {
|
||||
const selectedPiece = this.uiState.value.selectedPiece;
|
||||
const selectedCard = this.uiState.value.selectedCard;
|
||||
|
||||
if (!selectedPiece || !selectedCard) {
|
||||
setValidMoves(this.uiState, []);
|
||||
return;
|
||||
}
|
||||
|
||||
const moves = this.getValidMovesForPiece(selectedPiece.x, selectedPiece.y, [selectedCard]);
|
||||
setValidMoves(this.uiState, moves);
|
||||
}
|
||||
|
||||
public onHighlightClick(data: HighlightData): void {
|
||||
@@ -295,80 +233,6 @@ export class OnitamaScene extends GameHostScene<OnitamaState> {
|
||||
}
|
||||
}
|
||||
|
||||
private updateHighlights(validMoves: ValidMove[]): void {
|
||||
// Clear old highlights
|
||||
for (const [, circle] of this.highlightContainers) {
|
||||
circle.destroy();
|
||||
}
|
||||
this.highlightContainers.clear();
|
||||
|
||||
// Create new highlights
|
||||
for (const move of validMoves) {
|
||||
const key = `${move.card}-${move.toX}-${move.toY}`;
|
||||
const pos = boardToScreen(move.toX, move.toY);
|
||||
|
||||
const circle = this.add.circle(pos.x, pos.y, CELL_SIZE / 3, 0x3b82f6, 0.3).setDepth(100);
|
||||
circle.setInteractive({ useHandCursor: true });
|
||||
circle.on('pointerdown', () => {
|
||||
this.onHighlightClick({
|
||||
key,
|
||||
x: pos.x,
|
||||
y: pos.y,
|
||||
card: move.card,
|
||||
fromX: move.fromX,
|
||||
fromY: move.fromY,
|
||||
toX: move.toX,
|
||||
toY: move.toY,
|
||||
});
|
||||
});
|
||||
|
||||
this.highlightContainers.set(key, circle as Phaser.GameObjects.GameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private getValidMovesForPiece(
|
||||
fromX: number,
|
||||
fromY: number,
|
||||
cardNames: string[]
|
||||
): ValidMove[] {
|
||||
const moves: ValidMove[] = [];
|
||||
const player = this.state.currentPlayer;
|
||||
|
||||
for (const cardName of cardNames) {
|
||||
const card = this.state.cards[cardName];
|
||||
if (!card) continue;
|
||||
|
||||
for (const move of card.moveCandidates) {
|
||||
const toX = fromX + move.dx;
|
||||
const toY = fromY + move.dy;
|
||||
|
||||
if (this.isValidMove(fromX, fromY, toX, toY, player)) {
|
||||
moves.push({ card: cardName, fromX, fromY, toX, toY });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return moves;
|
||||
}
|
||||
|
||||
private isValidMove(fromX: number, fromY: number, toX: number, toY: number, player: PlayerType): boolean {
|
||||
if (toX < 0 || toX >= BOARD_SIZE || toY < 0 || toY >= BOARD_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const targetPawn = this.getPawnAtPosition(toX, toY);
|
||||
if (targetPawn && targetPawn.owner === player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const pawn = this.getPawnAtPosition(fromX, fromY);
|
||||
if (!pawn || pawn.owner !== player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private getPawnAtPosition(x: number, y: number): Pawn | null {
|
||||
const key = `${x},${y}`;
|
||||
const pawnId = this.state.regions.board.partMap[key];
|
||||
|
||||
Reference in New Issue
Block a user