import { _decorator, Component, Node, Button, find } from 'cc'; import { PopUPAni } from '../../Animations/PopUPAni'; import EventBus, { GameEvents } from '../../Core/EventBus'; import { GameManager, AppState } from '../../LevelSystem/GameManager'; import { SaveDataManager } from '../../LevelSystem/SaveDataManager'; import { GameStartMove } from '../../Animations/GameStartMove'; import { SoundController } from './SoundController'; import { Audio } from '../../AudioManager/AudioManager'; const { ccclass, property } = _decorator; /** * 菜单系统控制器 * 负责管理菜单UI的显示和隐藏 */ @ccclass('MenuController') export class MenuController extends Component { // UI节点引用 @property(Node) menuUI: Node = null; // Canvas/MenuUI @property(Button) menuButton: Button = null; // Canvas/MenuButton (主界面使用) @property(Button) menuButton1: Button = null; // Canvas/MenueButton-001 (游戏中使用) @property(Button) closeButton: Button = null; // Canvas/MenuUI中的关闭按钮 @property(Button) backButton: Button = null; // Canvas/MenuUI/Buttons/BackButton 退出游戏按钮 @property(Button) continueButton: Button = null; // Canvas/MenuUI/Buttons/ContinueButton 继续游戏按钮 // 需要检测的UI节点引用 @property(Node) skillUpUI: Node = null; // Canvas/SkillUpUI @property(Node) upgradeUI: Node = null; // Canvas/UpgradeUI @property(Node) shopUI: Node = null; // Canvas/ShopUI // 动画控制器 @property(PopUPAni) popupAni: PopUPAni = null; // Canvas/MenuUI上的PopUPAni组件 // 音频控制器 @property(SoundController) soundController: SoundController = null; // Canvas/MenuUI上的SoundController组件 // 游戏管理器引用 @property(GameManager) gameManager: GameManager = null; // GameManager组件引用 // 菜单状态 private isMenuOpen: boolean = false; // GameStartMove组件引用,用于重置镜头位置 private gameStartMoveComponent: GameStartMove = null; onLoad() { this.bindEvents(); // 初始化时隐藏菜单 - 使用PopUPAni的场景外位置隐藏方法 if (this.popupAni) { this.popupAni.hidePanelImmediate(); } // 设置界面状态监听 this.setupUIStateListeners(); // 初始化菜单按钮显示状态 this.updateMenuButtonVisibility(); } start() { // 初始化菜单按钮状态 this.updateMenuButtonVisibility(); } /** * 绑定事件 */ private bindEvents() { // 绑定菜单按钮点击事件 (主界面使用) if (this.menuButton) { this.menuButton.node.on(Button.EventType.CLICK, this.onMenuButtonClick, this); } // 绑定菜单按钮1点击事件 (游戏中使用) if (this.menuButton1) { this.menuButton1.node.on(Button.EventType.CLICK, this.onMenuButtonClick, this); } // 绑定关闭按钮点击事件 if (this.closeButton) { this.closeButton.node.on(Button.EventType.CLICK, this.onCloseButtonClick, this); } // 绑定退出游戏按钮点击事件 if (this.backButton) { this.backButton.node.on(Button.EventType.CLICK, this.onBackButtonClick, this); } // 绑定继续游戏按钮点击事件 if (this.continueButton) { this.continueButton.node.on(Button.EventType.CLICK, this.onContinueButtonClick, this); } } /** * 设置UI状态监听器 */ private setupUIStateListeners() { const eventBus = EventBus.getInstance(); // 监听界面切换事件(如果有的话) // 这里可以根据实际的界面切换事件来更新菜单按钮显示状态 eventBus.on(GameEvents.RETURN_TO_MAIN_MENU, this.updateMenuButtonVisibility, this); eventBus.on(GameEvents.UI_PANEL_SWITCHED, this.updateMenuButtonVisibility, this); // 监听应用状态切换事件 eventBus.on(GameEvents.APP_STATE_CHANGED, this.onAppStateChanged, this); } /** * 检测当前是否在需要隐藏菜单按钮的界面 */ private isInHiddenMenuUI(): boolean { // 检查SkillUpUI、UpgradeUI、ShopUI是否激活 const isSkillUpActive = this.skillUpUI && this.skillUpUI.active; const isUpgradeActive = this.upgradeUI && this.upgradeUI.active; const isShopActive = this.shopUI && this.shopUI.active; return isSkillUpActive || isUpgradeActive || isShopActive; } /** * 更新菜单按钮的显示状态 */ private updateMenuButtonVisibility() { // 检查当前应用状态 const currentAppState = this.gameManager ? this.gameManager.getCurrentAppState() : null; // 检查是否为第一关 const isFirstLevel = (() => { try { const save = SaveDataManager.getInstance(); return save && typeof save.getCurrentLevel === 'function' && save.getCurrentLevel() === 1; } catch { return false; } })(); // 在游戏外界面中,检查是否在需要隐藏菜单按钮的界面 if (currentAppState !== AppState.IN_GAME && this.isInHiddenMenuUI()) { // 在SkillUpUI、UpgradeUI、ShopUI界面中隐藏所有菜单按钮 if (this.menuButton) this.menuButton.node.active = false; if (this.menuButton1) this.menuButton1.node.active = false; console.log('[MenuController] 在游戏外界面中隐藏菜单按钮'); } else if (currentAppState === AppState.IN_GAME) { // 第一关隐藏游戏中的菜单按钮 if (isFirstLevel) { if (this.menuButton) this.menuButton.node.active = false; if (this.menuButton1) this.menuButton1.node.active = false; console.log('[MenuController] 第一关隐藏MenueButton-001'); } else { // 非第一关:游戏中显示menuButton1,隐藏menuButton if (this.menuButton) this.menuButton.node.active = false; if (this.menuButton1) this.menuButton1.node.active = true; console.log('[MenuController] 游戏中显示menuButton1'); } } else { // 主界面显示menuButton,隐藏menuButton1 if (this.menuButton) this.menuButton.node.active = true; if (this.menuButton1) this.menuButton1.node.active = false; console.log('[MenuController] 主界面显示menuButton'); } } /** * 菜单按钮点击事件 */ private async onMenuButtonClick() { // 播放UI点击音效 Audio.playUISound('data/弹球音效/ui play'); if (this.isMenuOpen) { await this.closeMenu(); } else { await this.openMenu(); } } /** * 关闭按钮点击事件 */ private async onCloseButtonClick() { // 播放UI点击音效 Audio.playUISound('data/弹球音效/ui play'); await this.closeMenu(); } /** * 继续游戏按钮点击事件 */ private async onContinueButtonClick() { // 播放UI点击音效 Audio.playUISound('data/弹球音效/ui play'); console.log('[MenuController] 继续游戏按钮被点击'); // 检查GameManager组件引用 if (!this.gameManager) { console.error('[MenuController] GameManager组件未通过装饰器挂载,请在Inspector中拖拽GameManager组件'); await this.closeMenu(); return; } const currentAppState = this.gameManager.getCurrentAppState(); console.log(`[MenuController] 当前应用状态: ${currentAppState}`); if (currentAppState === AppState.IN_GAME) { // 在游戏中点击继续,关闭菜单并恢复游戏 console.log('[MenuController] 游戏中点击继续,关闭菜单并恢复游戏'); await this.closeMenu(); } else { // 游戏外点击继续,直接关闭菜单 console.log('[MenuController] 游戏外点击继续,直接关闭菜单'); await this.closeMenu(); } } /** * 退出游戏按钮点击事件 * 只在游戏中有效,游戏外界面不显示菜单按钮 */ private async onBackButtonClick() { // 播放UI点击音效 Audio.playUISound('data/弹球音效/ui play'); console.log('[MenuController] 退出游戏按钮被点击'); // 检查GameManager组件引用 if (!this.gameManager) { console.error('[MenuController] GameManager组件未通过装饰器挂载,请在Inspector中拖拽GameManager组件'); return; } const currentAppState = this.gameManager.getCurrentAppState(); console.log(`[MenuController] 当前应用状态: ${currentAppState}`); // 只处理游戏中的退出逻辑,游戏外界面不显示菜单按钮 if (currentAppState === AppState.IN_GAME) { // 在游戏中退出,应该触发游戏失败事件显示GameEnd面板 console.log('[MenuController] 游戏中退出,触发GAME_DEFEAT事件显示游戏失败UI'); // 先触发游戏失败事件,让GameEnd面板显示 const eventBus = EventBus.getInstance(); eventBus.emit(GameEvents.GAME_DEFEAT); // 关闭菜单(不触发GAME_RESUME事件,避免事件冲突) await this.closeMenuWithoutResume(); console.log('[MenuController] 菜单退出处理完成,已触发GAME_DEFEAT事件'); } else { // 游戏外不应该显示菜单按钮,如果意外触发则只关闭菜单 console.log('[MenuController] 游戏外意外触发退出按钮,仅关闭菜单'); await this.closeMenu(); } } /** * 重置镜头位置到原始位置 * 确保从游戏中退出时镜头位置正常 */ private resetCameraPosition() { // 如果还没有获取GameStartMove组件,尝试获取 if (!this.gameStartMoveComponent) { const cameraNode = find('Canvas/Main Camera'); if (cameraNode) { this.gameStartMoveComponent = cameraNode.getComponent(GameStartMove); } } // 如果成功获取到组件,重置镜头位置 if (this.gameStartMoveComponent) { console.log('[MenuController] 重置镜头位置到原始位置'); this.gameStartMoveComponent.resetCameraToOriginalPosition(0.3); } else { console.warn('[MenuController] 未找到GameStartMove组件,无法重置镜头位置'); } } /** * 打开菜单 */ public async openMenu(): Promise { if (this.isMenuOpen) return; this.isMenuOpen = true; // 检查是否在游戏中,如果是则通过事件系统触发游戏暂停 if (this.gameManager && this.gameManager.getCurrentAppState() === AppState.IN_GAME) { console.log('[MenuController] 游戏中打开菜单,通过事件系统触发游戏暂停'); const eventBus = EventBus.getInstance(); eventBus.emit(GameEvents.GAME_PAUSE); } // 使用动画显示菜单面板 if (this.popupAni) { await this.popupAni.showPanel(); } // 注意:不再有fallback逻辑设置active,菜单面板始终保持active=true console.log('菜单已打开'); } /** * 关闭菜单 */ public async closeMenu(): Promise { if (!this.isMenuOpen) return; this.isMenuOpen = false; // 使用动画隐藏菜单面板 if (this.popupAni) { await this.popupAni.hidePanel(); } // 注意:不再有fallback逻辑设置active,菜单面板始终保持active=true // 检查是否在游戏中,如果是则通过事件系统触发游戏恢复 if (this.gameManager && this.gameManager.getCurrentAppState() === AppState.IN_GAME) { console.log('[MenuController] 游戏中关闭菜单,通过事件系统触发游戏恢复'); const eventBus = EventBus.getInstance(); eventBus.emit(GameEvents.GAME_RESUME); } console.log('菜单已关闭'); } /** * 关闭菜单但不触发游戏恢复事件(用于游戏失败退出) */ private async closeMenuWithoutResume(): Promise { if (!this.isMenuOpen) return; this.isMenuOpen = false; // 使用动画隐藏菜单面板 if (this.popupAni) { await this.popupAni.hidePanel(); } // 注意:不再有fallback逻辑设置active,菜单面板始终保持active=true // 不触发GAME_RESUME事件,避免与GAME_DEFEAT事件冲突 console.log('菜单已关闭(未触发游戏恢复)'); } /** * 切换菜单状态 */ public async toggleMenu(): Promise { if (this.isMenuOpen) { await this.closeMenu(); } else { await this.openMenu(); } } /** * 获取菜单状态 */ public getMenuState(): boolean { return this.isMenuOpen; } /** * 立即关闭菜单(无动画) */ public closeMenuImmediate(): void { this.isMenuOpen = false; if (this.popupAni) { this.popupAni.hidePanelImmediate(); } // 注意:不再有fallback逻辑设置active,菜单面板始终保持active=true console.log('菜单已立即关闭'); } /** * 立即打开菜单(无动画) */ public openMenuImmediate(): void { this.isMenuOpen = true; if (this.popupAni) { this.popupAni.showPanelImmediate(); } // 注意:不再有fallback逻辑设置active,菜单面板始终保持active=true console.log('菜单已立即打开'); } /** * 应用状态切换事件处理 */ private onAppStateChanged(): void { console.log('[MenuController] 应用状态切换,更新菜单按钮显示状态'); this.updateMenuButtonVisibility(); } /** * 公共方法:更新菜单按钮显示状态 * 供外部组件调用,例如在界面切换时 */ public updateMenuButtonState(): void { this.updateMenuButtonVisibility(); } onDestroy() { // 解绑按钮事件 if (this.menuButton) { this.menuButton.node.off(Button.EventType.CLICK, this.onMenuButtonClick, this); } if (this.menuButton1) { this.menuButton1.node.off(Button.EventType.CLICK, this.onMenuButtonClick, this); } if (this.closeButton) { this.closeButton.node.off(Button.EventType.CLICK, this.onCloseButtonClick, this); } if (this.backButton) { this.backButton.node.off(Button.EventType.CLICK, this.onBackButtonClick, this); } if (this.continueButton) { this.continueButton.node.off(Button.EventType.CLICK, this.onContinueButtonClick, this); } // 解绑事件监听器 const eventBus = EventBus.getInstance(); eventBus.off(GameEvents.RETURN_TO_MAIN_MENU, this.updateMenuButtonVisibility, this); eventBus.off(GameEvents.UI_PANEL_SWITCHED, this.updateMenuButtonVisibility, this); eventBus.off(GameEvents.APP_STATE_CHANGED, this.onAppStateChanged, this); } }