feat: add game start overlay
This commit is contained in:
parent
6ebfcc6c4d
commit
df1c0cbb81
|
|
@ -6,12 +6,14 @@ import { createPieceSpawner } from './PieceSpawner';
|
||||||
import { SupplyUI } from './SupplyUI';
|
import { SupplyUI } from './SupplyUI';
|
||||||
import { PieceTypeSelector } from './PieceTypeSelector';
|
import { PieceTypeSelector } from './PieceTypeSelector';
|
||||||
import { WinnerOverlay } from './WinnerOverlay';
|
import { WinnerOverlay } from './WinnerOverlay';
|
||||||
|
import { StartOverlay } from './StartOverlay';
|
||||||
|
|
||||||
export class GameScene extends GameHostScene<BoopState> {
|
export class GameScene extends GameHostScene<BoopState> {
|
||||||
private boardRenderer!: BoardRenderer;
|
private boardRenderer!: BoardRenderer;
|
||||||
private supplyUI!: SupplyUI;
|
private supplyUI!: SupplyUI;
|
||||||
private pieceTypeSelector!: PieceTypeSelector;
|
private pieceTypeSelector!: PieceTypeSelector;
|
||||||
private winnerOverlay!: WinnerOverlay;
|
private winnerOverlay!: WinnerOverlay;
|
||||||
|
private startOverlay!: StartOverlay;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super('GameScene');
|
super('GameScene');
|
||||||
|
|
@ -25,6 +27,7 @@ export class GameScene extends GameHostScene<BoopState> {
|
||||||
this.supplyUI = new SupplyUI(this);
|
this.supplyUI = new SupplyUI(this);
|
||||||
this.pieceTypeSelector = new PieceTypeSelector(this);
|
this.pieceTypeSelector = new PieceTypeSelector(this);
|
||||||
this.winnerOverlay = new WinnerOverlay(this, () => this.restartGame());
|
this.winnerOverlay = new WinnerOverlay(this, () => this.restartGame());
|
||||||
|
this.startOverlay = new StartOverlay(this, () => this.startGame());
|
||||||
|
|
||||||
// 设置棋子生成器
|
// 设置棋子生成器
|
||||||
this.disposables.add(createPieceSpawner(this));
|
this.disposables.add(createPieceSpawner(this));
|
||||||
|
|
@ -33,10 +36,20 @@ export class GameScene extends GameHostScene<BoopState> {
|
||||||
this.boardRenderer.setupInput(
|
this.boardRenderer.setupInput(
|
||||||
() => this.state,
|
() => this.state,
|
||||||
(row, col) => this.handleCellClick(row, col),
|
(row, col) => this.handleCellClick(row, col),
|
||||||
() => !!this.state.winner
|
() => this.gameHost.status.value !== 'running' || !!this.state.winner
|
||||||
);
|
);
|
||||||
|
|
||||||
// 监听状态变化
|
// 监听游戏状态变化
|
||||||
|
this.addEffect(() => {
|
||||||
|
const status = this.gameHost.status.value;
|
||||||
|
if (status === 'running') {
|
||||||
|
this.startOverlay.hide();
|
||||||
|
} else if (status === 'created') {
|
||||||
|
this.startOverlay.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听胜负状态
|
||||||
this.addEffect(() => {
|
this.addEffect(() => {
|
||||||
const winner = this.state.winner;
|
const winner = this.state.winner;
|
||||||
if (winner) {
|
if (winner) {
|
||||||
|
|
@ -52,9 +65,6 @@ export class GameScene extends GameHostScene<BoopState> {
|
||||||
this.supplyUI.update(this.state);
|
this.supplyUI.update(this.state);
|
||||||
this.pieceTypeSelector.update(this.state);
|
this.pieceTypeSelector.update(this.state);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 设置棋子类型选择器回调
|
|
||||||
// 可以在这里添加类型改变时的额外逻辑
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleCellClick(row: number, col: number): void {
|
private handleCellClick(row: number, col: number): void {
|
||||||
|
|
@ -66,6 +76,10 @@ export class GameScene extends GameHostScene<BoopState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private startGame(): void {
|
||||||
|
this.gameHost.setup('setup');
|
||||||
|
}
|
||||||
|
|
||||||
private restartGame(): void {
|
private restartGame(): void {
|
||||||
this.gameHost.setup('setup');
|
this.gameHost.setup('setup');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
import Phaser from 'phaser';
|
||||||
|
import { BOARD_OFFSET, CELL_SIZE, BOARD_SIZE } from './BoardRenderer';
|
||||||
|
|
||||||
|
export class StartOverlay {
|
||||||
|
private overlay?: Phaser.GameObjects.Container;
|
||||||
|
private onStartCallback?: () => void;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private scene: Phaser.Scene,
|
||||||
|
onStart: () => void
|
||||||
|
) {
|
||||||
|
this.onStartCallback = onStart;
|
||||||
|
this.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
show(): void {
|
||||||
|
if (this.overlay) {
|
||||||
|
this.overlay.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.overlay = this.scene.add.container();
|
||||||
|
|
||||||
|
// 背景遮罩
|
||||||
|
const bg = this.scene.add.rectangle(
|
||||||
|
BOARD_OFFSET.x + (BOARD_SIZE * CELL_SIZE) / 2,
|
||||||
|
BOARD_OFFSET.y + (BOARD_SIZE * CELL_SIZE) / 2,
|
||||||
|
BOARD_SIZE * CELL_SIZE + 200,
|
||||||
|
BOARD_SIZE * CELL_SIZE + 200,
|
||||||
|
0x000000,
|
||||||
|
0.7,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.overlay.add(bg);
|
||||||
|
|
||||||
|
// 游戏标题
|
||||||
|
const titleText = this.scene.add.text(
|
||||||
|
BOARD_OFFSET.x + (BOARD_SIZE * CELL_SIZE) / 2,
|
||||||
|
BOARD_OFFSET.y + (BOARD_SIZE * CELL_SIZE) / 2 - 80,
|
||||||
|
'🐱 BOOP 🐾',
|
||||||
|
{
|
||||||
|
fontSize: '60px',
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
color: '#fbbf24',
|
||||||
|
fontStyle: 'bold',
|
||||||
|
},
|
||||||
|
).setOrigin(0.5);
|
||||||
|
|
||||||
|
this.overlay.add(titleText);
|
||||||
|
|
||||||
|
// 游戏说明
|
||||||
|
const rulesText = this.scene.add.text(
|
||||||
|
BOARD_OFFSET.x + (BOARD_SIZE * CELL_SIZE) / 2,
|
||||||
|
BOARD_OFFSET.y + (BOARD_SIZE * CELL_SIZE) / 2 - 10,
|
||||||
|
'将小猫或大猫放在棋盘上\n推动周围的小猫\n先连成3个猫的玩家获胜!',
|
||||||
|
{
|
||||||
|
fontSize: '20px',
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
color: '#e5e7eb',
|
||||||
|
align: 'center',
|
||||||
|
lineSpacing: 10,
|
||||||
|
},
|
||||||
|
).setOrigin(0.5);
|
||||||
|
|
||||||
|
this.overlay.add(rulesText);
|
||||||
|
|
||||||
|
// 开始按钮
|
||||||
|
const buttonY = BOARD_OFFSET.y + (BOARD_SIZE * CELL_SIZE) / 2 + 80;
|
||||||
|
const startButton = this.scene.add.container(
|
||||||
|
BOARD_OFFSET.x + (BOARD_SIZE * CELL_SIZE) / 2,
|
||||||
|
buttonY
|
||||||
|
);
|
||||||
|
|
||||||
|
const buttonBg = this.scene.add.rectangle(0, 0, 200, 60, 0xfbbf24)
|
||||||
|
.setStrokeStyle(3, 0xf59e0b)
|
||||||
|
.setInteractive({ useHandCursor: true });
|
||||||
|
|
||||||
|
const buttonText = this.scene.add.text(0, 0, '开始游戏', {
|
||||||
|
fontSize: '24px',
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
color: '#1f2937',
|
||||||
|
fontStyle: 'bold',
|
||||||
|
}).setOrigin(0.5);
|
||||||
|
|
||||||
|
startButton.add([buttonBg, buttonText]);
|
||||||
|
this.overlay.add(startButton);
|
||||||
|
|
||||||
|
// 按钮交互效果
|
||||||
|
buttonBg.on('pointerover', () => {
|
||||||
|
buttonBg.setFillStyle(0xfcd34d);
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonBg.on('pointerout', () => {
|
||||||
|
buttonBg.setFillStyle(0xfbbf24);
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonBg.on('pointerdown', () => {
|
||||||
|
buttonBg.setFillStyle(0xf59e0b);
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonBg.on('pointerup', () => {
|
||||||
|
buttonBg.setFillStyle(0xfcd34d);
|
||||||
|
this.onStartCallback?.();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 标题呼吸动画
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: titleText,
|
||||||
|
scale: 1.1,
|
||||||
|
duration: 1000,
|
||||||
|
yoyo: true,
|
||||||
|
repeat: -1,
|
||||||
|
ease: 'Sine.easeInOut',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
hide(): void {
|
||||||
|
if (this.overlay) {
|
||||||
|
this.overlay.destroy();
|
||||||
|
this.overlay = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(): void {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue