import * as Phaser from "phaser"; import { GameOverPanel } from "./GameOverPanel"; import { LevelManager } from "../../levels/LevelManager"; import { AUTO_NEXT_LEVEL_ON_WIN, CHALLENGE_LEVEL_MODE, } from "../../DebugConfig"; import { clearActiveRunContext } from "../../run/RunContextRuntime"; import { safePlaySound } from "../../utils/SoundUtils"; /** * 描述 LevelLifecycle 从 Game 场景中所需内容的最小接口。 * 避免模块级别的循环导入。 */ export interface LevelLifecycleGameRef extends Phaser.Scene { level: any; // ParsedLevel | null currentLives: number; maxLives: number; topUI: any; // GameTopUI | null gameOverPanel: GameOverPanel | undefined; isInputLocked: boolean; isTestMode: boolean; runFlags: { kind: string; affectsProgression: boolean }; settings: any; winProcessing: boolean; removedPaths: Set; nomoveHintSprite: Phaser.GameObjects.Image | null; nomoveHintTween: Phaser.Tweens.Tween | null; } /** * 关卡生命周期管理器。 * 负责处理生命值、游戏结束、胜利、自动进入下一关等逻辑。 */ export class LevelLifecycle { private scene: LevelLifecycleGameRef; constructor(scene: LevelLifecycleGameRef) { this.scene = scene; } // ── 扣除生命值 ── /** 扣除一条生命值。如果生命值归零,触发游戏结束流程。 */ loseLife(): void { const s = this.scene; if (s.currentLives <= 0) { return; } s.currentLives = Math.max(0, s.currentLives - 1); if (s.topUI) { s.topUI.setLives(s.currentLives); } if (s.currentLives <= 0) { // 失去最后一条命后,先播放提示效果 safePlaySound(s, "fail", { volume: 2.0 }); // 然后延迟显示面板,锁定输入以防误触 s.isInputLocked = true; s.time.delayedCall(400, () => { this.handleOutOfLives(); s.isInputLocked = false; }); } else { safePlaySound(s, "mistake", { volume: 2.0 }); } } // ── 处理生命值耗尽 ── /** 生命值耗尽时的处理逻辑,延迟后显示游戏结束面板。 */ private handleOutOfLives(): void { const s = this.scene; if (s.gameOverPanel) { return; } s.isInputLocked = true; s.time.delayedCall(300, () => { this.showGameOverPanel(); s.isInputLocked = false; }); } // ── 显示游戏结束面板 ── /** 显示失败类型的游戏结束面板。 */ showGameOverPanel(): void { const s = this.scene; if (s.gameOverPanel) { return; } s.gameOverPanel = new GameOverPanel(s as any, { type: "lose", onClose: () => { s.gameOverPanel = undefined; if (!s.runFlags.affectsProgression) { clearActiveRunContext(); } if (s.isTestMode) { s.scene.start("Editor"); } else { s.scene.start("Game"); } }, }); } // ── 显示挑战模式胜利面板 ── /** 显示挑战模式的胜利面板,并停止背景音乐。 */ showChallengeWinPanel(): void { const s = this.scene; if (s.gameOverPanel) { return; } s.settings.stopBgm(); s.gameOverPanel = new GameOverPanel(s as any, { type: "win", onClose: () => { s.gameOverPanel = undefined; }, }); } // ── 处理关卡通关 ── /** 处理关卡通关逻辑,防止重复处理。 */ handleLevelSuccess(): void { const s = this.scene; if (s.winProcessing) { return; } s.winProcessing = true; void this.processWinAndShowSuccessPanel().finally(() => { s.winProcessing = false; }); } // ── 处理胜利并显示成功面板 ── /** 异步处理胜利逻辑:测试模式返回编辑器,自动进入下一关或显示胜利面板。 */ private async processWinAndShowSuccessPanel(): Promise { const s = this.scene; // 测试/预览模式:胜利后返回编辑器 if (s.isTestMode) { console.log("[Game] 预览模式胜利 - 返回编辑器"); clearActiveRunContext(); s.scene.start("Editor"); return; } // 如果启用了自动进入下一关,跳过显示面板 if (AUTO_NEXT_LEVEL_ON_WIN) { // 挑战模式:改为显示胜利面板 if (CHALLENGE_LEVEL_MODE !== 0) { this.showChallengeWinPanel(); return; } this.autoProgressToNextLevel(); return; } // 挑战模式:显示胜利面板 if (CHALLENGE_LEVEL_MODE !== 0) { this.showChallengeWinPanel(); return; } } // ── 自动进入下一关 ── /** 自动进入下一关,重置生命值并重启场景。 */ autoProgressToNextLevel(): void { const s = this.scene; const mgr = LevelManager.instance; const nextIndex = mgr.getNextIndex(); mgr.setCurrentIndex(nextIndex); s.currentLives = s.maxLives; s.scene.restart(); } // ── 播放危险闪烁帧 ── /** 播放危险闪烁帧效果(红色边框闪烁),用于错误操作时的视觉反馈。 */ playDangerFrame(): void { const s = this.scene; const sprite = s.nomoveHintSprite; if (!sprite) return; if (s.nomoveHintTween) { s.nomoveHintTween.stop(); s.nomoveHintTween = null; } const cam = s.cameras.main; const centerX = cam.width / 2; const centerY = cam.height / 2; sprite.setPosition(centerX, centerY); sprite.setDisplaySize(cam.width, cam.height); sprite.setAlpha(0); sprite.setVisible(true); s.nomoveHintTween = s.tweens.add({ targets: sprite, alpha: { from: 0, to: 1 }, duration: 150, ease: "Linear", yoyo: true, repeat: 0, onComplete: () => { sprite.setVisible(false); sprite.setAlpha(0); s.nomoveHintTween = null; }, }); } // ── 处理超时 ── /** 处理计时器超时,显示游戏结束面板。 */ handleTimeOut(): void { this.showGameOverPanel(); } }