From b8ba572ffbee617f72f2db103d4da919ab19732d Mon Sep 17 00:00:00 2001 From: Cloud Bot Date: Tue, 24 Mar 2026 09:13:14 +0000 Subject: [PATCH] =?UTF-8?q?feat(game):=20=E6=B7=BB=E5=8A=A0=E5=BC=80?= =?UTF-8?q?=E4=BC=9A=E6=9A=82=E5=81=9C=E7=B3=BB=E7=BB=9F=E2=80=94=E2=80=94?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E5=BC=80=E4=BC=9A=E6=8C=89=E9=92=AE=E6=9A=82?= =?UTF-8?q?=E5=81=9C=E6=B8=B8=E6=88=8F=EF=BC=8C=E5=8F=AF=E5=AE=89=E5=BF=83?= =?UTF-8?q?=E5=8F=91=E6=BF=80=E5=8A=B1=EF=BC=8C=E7=BB=93=E6=9D=9F=E5=BC=80?= =?UTF-8?q?=E4=BC=9A=E5=90=8E=E6=81=A2=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/game/page.tsx | 107 ++++++++++++++++++++++++++++++++++---------- app/globals.css | 5 +++ game/GameManager.ts | 16 +++++++ game/GameScene.ts | 62 +++++++++++++++++++++---- 4 files changed, 157 insertions(+), 33 deletions(-) diff --git a/app/game/page.tsx b/app/game/page.tsx index 4f2e86a..5f5439b 100644 --- a/app/game/page.tsx +++ b/app/game/page.tsx @@ -474,13 +474,24 @@ export default function GamePage() { const [selectedTower, setSelectedTower] = useState(null) const [gameReady, setGameReady] = useState(false) const [waveStarted, setWaveStarted] = useState(false) - // 召唤按钮状态(由 HUD 通过 window.__gameSetWaveBtn 驱动) + const [inMeeting, setInMeeting] = useState(false) // 开会=游戏暂停 const [waveBtn, setWaveBtn] = useState<{ text: string; disabled: boolean }>({ text: '▶ 召唤下一波', disabled: false, }) const selectedTowerRef = useRef(null) + const handleMeeting = useCallback(() => { + if (!gameReady) return + if (!inMeeting) { + const ok = typeof window !== 'undefined' && (window as any).__gamePause?.() + if (ok) setInMeeting(true) + } else { + const ok = typeof window !== 'undefined' && (window as any).__gameResume?.() + if (ok) setInMeeting(false) + } + }, [gameReady, inMeeting]) + const handleSelectTower = useCallback((type: TowerType) => { const next = selectedTowerRef.current === type ? null : type selectedTowerRef.current = next @@ -545,7 +556,8 @@ export default function GamePage() { ;['__gameOnHCChange','__gameOnTowerDeselect','__gameSelectTower', '__gameReady','__gameDifficulty','__gamePuaBuff', '__gameGetHC','__gameSpendHC','__gameWaveStarted', - '__gameSetWaveBtn','__gameWaveBtnState','__gameOnWaveClick'].forEach(k => { + '__gameSetWaveBtn','__gameWaveBtnState','__gameOnWaveClick', + '__gamePause','__gameResume','__gameIsPaused'].forEach(k => { delete (window as any)[k] }) } @@ -565,79 +577,126 @@ export default function GamePage() { style={{ backgroundColor: '#0A1628' }} /> - {/* 右侧面板:HC + 召唤按钮 + PUA激励台 */} + {/* 右侧面板:HC + 开会按钮 + 召唤按钮 + PUA激励台 */}
- {/* HC 数量显示 */} + {/* HC 数量 + 开会按钮(同一行) */}
-
- +
+
人才储备 - - +
{hc} HC - +
+ {/* 开会按钮 */} +
- {/* 召唤下一波按钮 */} -
+ {/* 开会中提示条 */} + {inMeeting && ( +
+ + 游戏已暂停,可安心激励 +
+ )} + + {/* 召唤下一波按钮(开会时禁用) */} +
{/* PUA 激励台 */} - +
diff --git a/app/globals.css b/app/globals.css index 4bdbd66..edb8cd5 100644 --- a/app/globals.css +++ b/app/globals.css @@ -725,3 +725,8 @@ /* 深色背景(终端/代码块)保留不覆盖:bg-slate-900 bg-slate-950 */ } + +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.3; } +} diff --git a/game/GameManager.ts b/game/GameManager.ts index 416f7f8..4111aba 100644 --- a/game/GameManager.ts +++ b/game/GameManager.ts @@ -102,6 +102,22 @@ export class GameManager { this.onKPIChange.forEach(cb => cb(this.kpi)) } + /** 暂停游戏(仅 playing 状态下有效) */ + pause(): boolean { + if (this.gameState !== 'playing') return false + this.gameState = 'paused' + return true + } + + /** 恢复游戏(仅 paused 状态下有效) */ + resume(): boolean { + if (this.gameState !== 'paused') return false + this.gameState = 'playing' + return true + } + + get isPaused(): boolean { return this.gameState === 'paused' } + /** 触发胜利 */ triggerVictory(): void { if (this.gameState === 'playing') { diff --git a/game/GameScene.ts b/game/GameScene.ts index 05f64ff..93dcede 100644 --- a/game/GameScene.ts +++ b/game/GameScene.ts @@ -64,6 +64,10 @@ export function createGameScene(PhaserLib: typeof Phaser): typeof Phaser.Scene { private bgObject: Phaser.GameObjects.Image | null = null private mapInTransition: boolean = false + // 暂停遮罩 + private pauseOverlay: Phaser.GameObjects.Graphics | null = null + private pauseText: Phaser.GameObjects.Text | null = null + constructor() { super({ key: 'GameScene' }) } preload(): void { @@ -124,19 +128,34 @@ export function createGameScene(PhaserLib: typeof Phaser): typeof Phaser.Scene { audio.startBGM() }) - // 注册 PUA buff 接口 + HC 查询/扣除接口供 React 层调用 + // 注册 PUA buff 接口 + HC 查询/扣除接口 + 暂停/恢复接口 if (typeof window !== 'undefined') { ;(window as any).__gamePuaBuff = ( effect: string, score: number, title: string - ) => { - this.applyPuaBuff(effect, score, title) - } - // 查询当前 HC + ) => { this.applyPuaBuff(effect, score, title) } + ;(window as any).__gameGetHC = () => this.manager.hc - // 尝试扣除 HC,成功返回 true,不足返回 false - ;(window as any).__gameSpendHC = (amount: number): boolean => { - return this.manager.spendHC(amount) + ;(window as any).__gameSpendHC = (amount: number): boolean => + this.manager.spendHC(amount) + + ;(window as any).__gamePause = (): boolean => { + if (!this.manager.pause()) return false + this.showPauseOverlay() + // 暂停 Phaser 物理与 Tween + this.physics.pause() + this.tweens.pauseAll() + return true } + + ;(window as any).__gameResume = (): boolean => { + if (!this.manager.resume()) return false + this.hidePauseOverlay() + this.physics.resume() + this.tweens.resumeAll() + return true + } + + ;(window as any).__gameIsPaused = (): boolean => this.manager.isPaused } this.setupInteraction() @@ -145,10 +164,34 @@ export function createGameScene(PhaserLib: typeof Phaser): typeof Phaser.Scene { } private createMuteButton(_audio: AudioEngine): void { - // 静音按钮已移除,音乐默认开启 void _audio } + private showPauseOverlay(): void { + const { width, height } = this.scale + // 半透明深色遮罩 + this.pauseOverlay = this.add.graphics().setDepth(90) + this.pauseOverlay.fillStyle(0x000000, 0.6) + this.pauseOverlay.fillRect(0, 0, width, height) + + // "开会中" 提示卡片 + this.pauseText = this.add.text(width / 2, height / 2, '📋 开会中...\n游戏已暂停', { + fontFamily: 'VT323, monospace', + fontSize: '32px', + color: '#FCD34D', + backgroundColor: '#1e3a5f', + padding: { x: 32, y: 18 }, + align: 'center', + }).setOrigin(0.5, 0.5).setDepth(91) + } + + private hidePauseOverlay(): void { + this.pauseOverlay?.destroy() + this.pauseOverlay = null + this.pauseText?.destroy() + this.pauseText = null + } + /** * 应用 PUA buff 效果到游戏 * effect: attack_boost | speed_boost | money_rain | rage_mode | backfire @@ -324,6 +367,7 @@ export function createGameScene(PhaserLib: typeof Phaser): typeof Phaser.Scene { private readonly AUTO_WAVE_DELAY = 2000 // 自动开始等待:3s→2s,缩短喘息时间 update(_time: number, delta: number): void { + if (this.manager.gameState === 'paused') return // 暂停时完全跳过 if (this.manager.gameState !== 'playing' && this.manager.gameState !== 'idle') return if (this.mapInTransition) return