| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024 |
- import { _decorator, Component, Node, Label, Button, tween, Tween, Vec3, UIOpacity, find } from 'cc';
- import { SaveDataManager } from '../LevelSystem/SaveDataManager';
- import { InGameManager, GameState } from '../LevelSystem/IN_game';
- import EventBus, { GameEvents } from '../Core/EventBus';
- import { Audio } from '../AudioManager/AudioManager';
- const { ccclass, property } = _decorator;
- /**
- * 游戏结算界面管理器
- * 负责处理游戏结束后的奖励显示和双倍奖励功能
- */
- @ccclass('GameEnd')
- export class GameEnd extends Component {
-
- // === UI节点引用 ===
- @property({
- type: Button,
- tooltip: '双倍奖励按钮 (Canvas/GameEnd/double)'
- })
- public doubleButton: Button = null;
-
- @property({
- type: Label,
- tooltip: '钞票数量显示 '
- })
- public moneyLabel: Label = null;
-
- @property({
- type: Label,
- tooltip: '钻石数量显示 '
- })
- public diamondLabel: Label = null;
-
- @property({
- type: Button,
- tooltip: '继续按钮 (Canvas/GameEnd/Continue)'
- })
- public continueButton: Button = null;
-
- @property({
- type: InGameManager,
- tooltip: '游戏管理器组件'
- })
- public inGameManager: InGameManager = null;
-
- @property({
- type: Label,
- tooltip: 'EndLabel文本显示 (Canvas/GameEnd/Sprite/EndLabel)'
- })
- public endLabel: Label = null;
-
- // === 动画相关属性 ===
- @property({ tooltip: '动画持续时间(秒)' })
- public animationDuration: number = 0.3;
-
- // 淡入淡出和缩放动画都直接作用于当前节点(Canvas/GameEnd)
- // 不需要额外的目标节点属性
-
- private _originalScale: Vec3 = new Vec3();
-
- // === 私有属性 ===
- private saveDataManager: SaveDataManager = null;
- public currentRewards: {money: number, diamonds: number} = {money: -1, diamonds: -1};
- private hasDoubledReward: boolean = false;
- private isGameSuccess: boolean = false;
- private hasProcessedGameEnd: boolean = false; // 添加处理状态标志
- onLoad() {
- console.log('[GameEnd] onLoad方法被调用');
- this.setupEventListeners();
- }
-
- start() {
- console.log('[GameEnd] start方法被调用');
-
- // 保存原始缩放值
- if (this.node) {
- this._originalScale.set(this.node.scale);
- }
-
- // 设置事件监听器
- this.setupEventListeners();
-
- // 初始化为隐藏状态(但保持节点激活以便接收事件)
- this.initializeHiddenStateKeepActive();
- console.log('[GameEnd] start方法完成,面板已初始化为隐藏状态');
- }
-
- onEnable() {
- console.log('[GameEnd] onEnable方法被调用,节点已激活');
-
- // 初始化管理器
- this.initializeManagers();
-
- // UI节点已通过装饰器挂载,无需自动查找
-
- // 绑定按钮事件
- this.bindButtonEvents();
-
- // 初始化UI状态
- this.initializeUI();
-
- // 检查当前游戏状态并处理奖励(解决时序问题)
- this.checkAndHandleGameState();
- }
-
- /**
- * 初始化管理器
- */
- private initializeManagers() {
- this.saveDataManager = SaveDataManager.getInstance();
- // InGameManager已通过装饰器挂载,无需查找
-
- // 如果UI组件未在编辑器中绑定,尝试自动查找
- this.autoFindUIComponents();
- }
-
- /**
- * 自动查找UI组件(如果编辑器中未绑定)
- */
- private autoFindUIComponents() {
- // 自动查找moneyLabel
- if (!this.moneyLabel) {
- // 尝试多个可能的路径
- const moneyLabelPaths = [
- 'ResourceNode/MoneyResourceNode/MoneyLabel',
- 'Sprite/ResourceNode/MoneyResourceNode/MoneyLabel',
- 'ResourceNode/MoneyLabel',
- 'MoneyResourceNode/MoneyLabel'
- ];
-
- for (const path of moneyLabelPaths) {
- const moneyLabelNode = this.node.getChildByPath(path);
- if (moneyLabelNode) {
- this.moneyLabel = moneyLabelNode.getComponent(Label);
- if (this.moneyLabel) {
- console.log(`[GameEnd] 自动找到moneyLabel,路径: ${path}`);
- break;
- }
- }
- }
-
- // 如果还是没找到,尝试递归查找
- if (!this.moneyLabel) {
- this.moneyLabel = this.findLabelByName(this.node, 'MoneyLabel');
- if (this.moneyLabel) {
- console.log('[GameEnd] 通过递归查找找到moneyLabel');
- }
- }
- }
-
- // 自动查找diamondLabel
- if (!this.diamondLabel) {
- // 尝试多个可能的路径
- const diamondLabelPaths = [
- 'ResourceNode/DiamondResourceNode/DiamondLabel',
- 'Sprite/ResourceNode/DiamondResourceNode/DiamondLabel',
- 'ResourceNode/DiamondLabel',
- 'DiamondResourceNode/DiamondLabel'
- ];
-
- for (const path of diamondLabelPaths) {
- const diamondLabelNode = this.node.getChildByPath(path);
- if (diamondLabelNode) {
- this.diamondLabel = diamondLabelNode.getComponent(Label);
- if (this.diamondLabel) {
- console.log(`[GameEnd] 自动找到diamondLabel,路径: ${path}`);
- break;
- }
- }
- }
-
- // 如果还是没找到,尝试递归查找
- if (!this.diamondLabel) {
- this.diamondLabel = this.findLabelByName(this.node, 'DiamondLabel');
- if (this.diamondLabel) {
- console.log('[GameEnd] 通过递归查找找到diamondLabel');
- }
- }
- }
-
- console.log('[GameEnd] UI组件自动查找完成 - moneyLabel:', !!this.moneyLabel, 'diamondLabel:', !!this.diamondLabel);
-
- // 如果仍然没有找到组件,打印节点结构用于调试
- if (!this.moneyLabel || !this.diamondLabel) {
- console.warn('[GameEnd] 部分UI组件未找到,打印节点结构用于调试:');
- this.printNodeStructure(this.node, 0, 3); // 最多打印3层
- }
- }
-
- /**
- * 递归查找指定名称的Label组件
- */
- private findLabelByName(node: Node, targetName: string): Label | null {
- // 检查当前节点
- if (node.name === targetName) {
- const label = node.getComponent(Label);
- if (label) return label;
- }
-
- // 递归检查子节点
- for (const child of node.children) {
- const result = this.findLabelByName(child, targetName);
- if (result) return result;
- }
-
- return null;
- }
-
- /**
- * 打印节点结构用于调试
- */
- private printNodeStructure(node: Node, depth: number, maxDepth: number) {
- if (depth > maxDepth) return;
-
- const indent = ' '.repeat(depth);
- const components = node.getComponents(Component).map(c => c.constructor.name).join(', ');
- console.log(`${indent}${node.name} [${components || 'No Components'}]`);
-
- for (const child of node.children) {
- this.printNodeStructure(child, depth + 1, maxDepth);
- }
- }
- /**
- * 绑定按钮事件
- */
- private bindButtonEvents() {
- if (this.doubleButton) {
- this.doubleButton.node.on(Button.EventType.CLICK, this.onDoubleButtonClick, this);
- }
-
- if (this.continueButton) {
- this.continueButton.node.on(Button.EventType.CLICK, this.onContinueButtonClick, this);
- }
- }
-
- /**
- * 设置事件监听器
- */
- private setupEventListeners() {
- console.log('[GameEnd] 开始设置事件监听器');
- const eventBus = EventBus.getInstance();
-
- // 监听游戏成功事件
- eventBus.on(GameEvents.GAME_SUCCESS, this.onGameSuccess, this);
- console.log('[GameEnd] 已注册GAME_SUCCESS事件监听器');
-
- // 监听游戏失败事件
- eventBus.on(GameEvents.GAME_DEFEAT, this.onGameDefeat, this);
- console.log('[GameEnd] 已注册GAME_DEFEAT事件监听器');
-
- // 监听游戏开始事件
- eventBus.on(GameEvents.GAME_START, this.onGameStart, this);
- console.log('[GameEnd] 已注册GAME_START事件监听器');
-
- // 监听UI重置事件
- eventBus.on(GameEvents.RESET_UI_STATES, this.onResetUI, this);
- console.log('[GameEnd] 事件监听器设置完成');
- }
-
- /**
- * 初始化UI状态
- */
- private initializeUI() {
- // 重置状态
- this.hasDoubledReward = false;
- this.currentRewards = {money: 0, diamonds: 0};
-
- console.log('[GameEnd] UI状态初始化完成');
- }
-
- /**
- * 检查当前游戏状态并处理奖励(解决时序问题)
- */
- private checkAndHandleGameState() {
- console.log('[GameEnd] 检查当前游戏状态');
-
- if (!this.inGameManager) {
- console.log('[GameEnd] InGameManager未初始化,无法检查游戏状态');
- return;
- }
-
- const currentState = this.inGameManager.getCurrentState();
- console.log('[GameEnd] 当前游戏状态:', currentState);
-
- // 如果游戏已经结束,主动处理奖励
- if (currentState === GameState.SUCCESS) {
- console.log('[GameEnd] 检测到游戏成功状态,主动处理奖励');
- this.isGameSuccess = true;
- this.calculateAndShowRewards();
- } else if (currentState === GameState.DEFEAT) {
- console.log('[GameEnd] 检测到游戏失败状态,主动处理奖励');
- this.isGameSuccess = false;
- this.calculateAndShowRewards();
- }
- }
-
- /**
- * 处理游戏成功事件
- * 统一处理游戏成功逻辑:状态切换 + UI显示 + 奖励计算
- */
- private onGameSuccess() {
- console.log('[GameEnd] 接收到GAME_SUCCESS事件');
- console.log('[GameEnd] 游戏成功事件处理,开始统一处理流程');
-
- // 1. 清理敌人(阶段一:UI弹出阶段的职责)
- this.clearAllEnemies();
-
- // 2. 设置游戏状态为成功(如果还未设置)
- if (this.inGameManager && this.inGameManager.getCurrentState() !== GameState.SUCCESS) {
- this.inGameManager.setCurrentState(GameState.SUCCESS);
- console.log('[GameEnd] 已将游戏状态切换为SUCCESS');
- }
-
- // 3. 播放游戏成功音效
- Audio.playUISound('data/弹球音效/win');
- console.log('[GameEnd] 已播放游戏成功音效');
-
- // 4. 设置EndLabel文本
- this.setEndLabelText('SUCCESS');
-
- // 5. 设置成功标志
- this.isGameSuccess = true;
-
- // 6. 计算和显示奖励(包含面板动画显示)
- this.calculateAndShowRewards();
- }
-
- /**
- * 处理游戏失败事件
- * 统一处理游戏失败逻辑:状态切换 + UI显示 + 奖励计算
- */
- private onGameDefeat() {
- console.log('[GameEnd] 接收到GAME_DEFEAT事件');
- console.log('[GameEnd] 游戏失败事件处理,开始统一处理流程');
-
- // 1. 清理敌人(阶段一:UI弹出阶段的职责)
- this.clearAllEnemies();
-
- // 2. 设置游戏状态为失败(如果还未设置)
- if (this.inGameManager && this.inGameManager.getCurrentState() !== GameState.DEFEAT) {
- this.inGameManager.setCurrentState(GameState.DEFEAT);
- console.log('[GameEnd] 已将游戏状态切换为DEFEAT');
- }
-
- // 3. 播放游戏失败音效
- Audio.playUISound('data/弹球音效/lose');
- console.log('[GameEnd] 已播放游戏失败音效');
-
- // 4. 设置EndLabel文本
- this.setEndLabelText('DEFEAT');
-
- // 5. 设置失败标志
- this.isGameSuccess = false;
-
- // 6. 计算和显示奖励(包含面板动画显示)
- this.calculateAndShowRewards();
- }
-
- /**
- * 游戏开始处理
- */
- private onGameStart() {
- console.log('[GameEnd] 收到游戏开始事件,重置奖励显示');
- // 重置奖励显示,为新游戏做准备
- this.currentRewards = {money: 0, diamonds: 0};
- this.hasProcessedGameEnd = false;
- this.hasDoubledReward = false;
- this.isGameSuccess = false;
- }
-
- /**
- * 计算并显示奖励
- */
- private async calculateAndShowRewards() {
- console.log('[GameEnd] 开始计算并显示奖励');
-
- // 防止重复计算奖励(使用专用标志判断)
- if (this.hasProcessedGameEnd) {
- console.log('[GameEnd] 游戏结束已处理过,跳过重复计算,直接显示面板');
- this.updateRewardDisplay();
- // 确保面板显示
- this.showEndPanelWithAnimation();
- return;
- }
-
- // 标记为已处理,防止重复执行
- this.hasProcessedGameEnd = true;
-
- if (!this.saveDataManager) {
- console.error('[GameEnd] SaveDataManager未初始化');
- return;
- }
-
- const currentLevel = this.saveDataManager.getCurrentLevel();
- console.log(`[GameEnd] 当前关卡: ${currentLevel}, 游戏成功: ${this.isGameSuccess}`);
-
- try {
- if (this.isGameSuccess) {
- // 游戏成功,给予完整奖励
- console.log('[GameEnd] 准备给予成功奖励');
- await this.saveDataManager.giveCompletionRewards(currentLevel);
- console.log('[GameEnd] 已给予成功奖励');
- } else {
- // 游戏失败,给予按比例奖励
- const totalWaves = this.inGameManager?.levelWaves?.length || 1;
- const completedWaves = this.inGameManager ? Math.max(0, this.inGameManager.getCurrentWave() - 1) : 0;
-
- console.log(`[GameEnd] 准备给予失败奖励,完成波数: ${completedWaves}/${totalWaves}`);
- await this.saveDataManager.giveFailureRewards(currentLevel, completedWaves, totalWaves);
- console.log(`[GameEnd] 已给予失败奖励,完成波数: ${completedWaves}/${totalWaves}`);
- }
-
- // 获取奖励数据并显示
- this.currentRewards = this.saveDataManager.getLastRewards();
- console.log('[GameEnd] 获取到的奖励数据:', this.currentRewards);
- console.log('[GameEnd] 奖励计算完成');
- this.updateRewardDisplay();
-
- // 显示结算面板(通过动画)
- this.showEndPanelWithAnimation();
-
- } catch (error) {
- console.error('[GameEnd] 计算奖励时出错:', error);
- }
- }
-
- /**
- * 更新奖励显示
- */
- private updateRewardDisplay() {
- console.log(`[GameEnd] 开始更新奖励显示 - 钞票: ${this.currentRewards.money}, 钻石: ${this.currentRewards.diamonds}`);
-
- // 检查moneyLabel绑定状态
- if (this.moneyLabel) {
- this.moneyLabel.string = this.currentRewards.money.toString();
- console.log(`[GameEnd] 钞票标签已更新: ${this.currentRewards.money}`);
- } else {
- console.error('[GameEnd] moneyLabel未绑定!请在编辑器中将Canvas/GameEnd/ResourceNode/MoneyResourceNode/MoneyLabel拖拽到GameEnd组件的moneyLabel属性');
- }
-
- // 检查diamondLabel绑定状态
- if (this.diamondLabel) {
- this.diamondLabel.string = this.currentRewards.diamonds.toString();
- console.log(`[GameEnd] 钻石标签已更新: ${this.currentRewards.diamonds}`);
- } else {
- console.error('[GameEnd] diamondLabel未绑定!请在编辑器中将Canvas/GameEnd/ResourceNode/DiamondResourceNode/DiamondLabel拖拽到GameEnd组件的diamondLabel属性');
- }
-
- console.log(`[GameEnd] 奖励显示更新完成`);
- }
-
- /**
- * 显示结算面板(通过动画)
- */
- private showEndPanelWithAnimation() {
- console.log('[GameEnd] 开始显示结算面板动画');
-
- // 确保节点处于激活状态
- if (this.node && !this.node.active) {
- this.node.active = true;
- console.log('[GameEnd] 激活GameEnd节点');
- }
- // 重置双倍奖励状态
- this.hasDoubledReward = false;
- if (this.doubleButton) {
- this.doubleButton.interactable = true;
- }
-
- // 确保有UIOpacity组件
- if (this.node) {
- let uiOpacity = this.node.getComponent(UIOpacity);
- if (!uiOpacity) {
- uiOpacity = this.node.addComponent(UIOpacity);
- console.log('[GameEnd] 在showEndPanelWithAnimation中添加UIOpacity组件');
- }
- }
-
- // 播放显示动画(如果有的话)
- if (this.animationDuration > 0) {
- console.log(`[GameEnd] 动画持续时间: ${this.animationDuration}秒,开始播放GameEnd面板弹出动画`);
- this.playShowAnimation();
- } else {
- // 如果没有动画,直接显示
- if (this.node) {
- this.node.setScale(1, 1, 1);
- const uiOpacity = this.node.getComponent(UIOpacity);
- if (uiOpacity) {
- uiOpacity.opacity = 255;
- }
- }
- console.log('[GameEnd] 无动画配置,直接显示面板');
- }
-
- console.log('[GameEnd] GameEnd面板显示流程完成');
- }
-
- /**
- * 播放显示动画
- */
- private playShowAnimation() {
- if (!this.node) {
- console.error('[GameEnd] playShowAnimation: 节点不存在');
- return;
- }
-
- console.log('[GameEnd] 开始播放GameEnd面板弹出动画');
-
- // 停止所有正在进行的动画
- this.stopAllAnimations();
-
- // 设置节点位置到屏幕中心
- this.centerNodeOnScreen();
-
- // 确保有UIOpacity组件
- let uiOpacity = this.node.getComponent(UIOpacity);
- if (!uiOpacity) {
- uiOpacity = this.node.addComponent(UIOpacity);
- console.log('[GameEnd] 添加UIOpacity组件');
- }
-
- // 设置初始状态
- this.node.setScale(0, 0, 1);
- uiOpacity.opacity = 0;
-
- console.log('[GameEnd] 设置动画初始状态 - 缩放: 0, 透明度: 0');
-
- // 播放缩放和淡入动画
- tween(this.node)
- .to(this.animationDuration, {
- scale: new Vec3(1, 1, 1)
- }, {
- easing: 'backOut'
- })
- .call(() => {
- console.log('[GameEnd] GameEnd面板缩放动画完成');
- })
- .start();
-
- tween(uiOpacity)
- .to(this.animationDuration, {
- opacity: 255
- })
- .call(() => {
- console.log('[GameEnd] GameEnd面板淡入动画完成');
- })
- .start();
-
- console.log('[GameEnd] GameEnd面板弹出动画开始执行');
- }
-
- /**
- * 将节点居中到屏幕中央
- */
- private centerNodeOnScreen() {
- if (!this.node) return;
-
- // 获取Canvas节点
- const canvas = find('Canvas');
- if (!canvas) {
- console.warn('[GameEnd] 未找到Canvas节点');
- return;
- }
-
- // 设置位置为(0, 0),这在Canvas坐标系中是屏幕中心
- this.node.setPosition(0, 0, 0);
- console.log('[GameEnd] 已将面板居中到屏幕中央');
- }
-
- /**
- * 双倍按钮点击事件
- */
- private onDoubleButtonClick() {
- // 播放UI点击音效
- Audio.playUISound('data/弹球音效/ui play');
- if (this.hasDoubledReward) {
- console.log('[GameEnd] 已经获得过双倍奖励');
- return;
- }
-
- console.log('[GameEnd] 点击双倍奖励按钮');
-
- // 这里可以添加观看广告的逻辑
- // 暂时直接给予双倍奖励
- this.giveDoubleReward();
- }
-
- /**
- * 给予双倍奖励
- */
- private giveDoubleReward() {
- if (!this.saveDataManager || this.hasDoubledReward) {
- return;
- }
-
- // 计算双倍奖励
- const doubleMoney = this.currentRewards.money;
- const doubleDiamonds = this.currentRewards.diamonds;
-
- // 添加额外奖励到玩家账户
- if (doubleMoney > 0) {
- this.saveDataManager.addMoney(doubleMoney, 'double_reward');
- }
-
- if (doubleDiamonds > 0) {
- this.saveDataManager.addDiamonds(doubleDiamonds, 'double_reward');
- }
-
- // 更新当前奖励显示(显示双倍后的数值)
- this.currentRewards.money += doubleMoney;
- this.currentRewards.diamonds += doubleDiamonds;
- this.updateRewardDisplay();
-
-
- // 标记已获得双倍奖励
- this.hasDoubledReward = true;
-
- // 禁用双倍按钮
- if (this.doubleButton) {
- this.doubleButton.interactable = false;
- }
-
- console.log(`[GameEnd] 双倍奖励已给予 - 额外钞票: ${doubleMoney}, 额外钻石: ${doubleDiamonds}`);
-
- // 触发货币变化事件
- EventBus.getInstance().emit(GameEvents.CURRENCY_CHANGED);
-
- // 派发事件给MoneyAni播放奖励动画
- const rewards = this.saveDataManager.getLastRewards();
- console.log('[GameEnd] 派发奖励动画事件,奖励数据:', rewards);
- EventBus.getInstance().emit('PLAY_REWARD_ANIMATION', {
- money: rewards.money,
- diamonds: rewards.diamonds
- });
-
- // 触发返回主菜单事件
- EventBus.getInstance().emit('CONTINUE_CLICK');
-
- // 隐藏结算面板(通过动画)
- this.hideEndPanelWithAnimation();
- }
-
- /**
- * 继续按钮点击事件
- */
- private onContinueButtonClick() {
- // 播放UI点击音效
- Audio.playUISound('data/弹球音效/ui play');
- console.log('[GameEnd] 点击继续按钮');
-
- // 派发事件给MoneyAni播放奖励动画
- const rewards = this.saveDataManager.getLastRewards();
- console.log('[GameEnd] 派发奖励动画事件,奖励数据:', rewards);
- EventBus.getInstance().emit('PLAY_REWARD_ANIMATION', {
- money: rewards.money,
- diamonds: rewards.diamonds
- });
-
- // 触发返回主菜单事件
- EventBus.getInstance().emit('CONTINUE_CLICK');
-
- // 隐藏结算面板(通过动画)
- this.hideEndPanelWithAnimation();
- }
-
- /**
- * 隐藏结算面板(通过动画)
- */
- private async hideEndPanelWithAnimation() {
- // 播放隐藏动画
- await this.fadeOutWithScale();
-
- console.log('[GameEnd] 结算面板已通过动画隐藏');
- }
-
- /**
- * 重置UI状态
- */
- private onResetUI() {
- console.log('[GameEnd] 重置UI状态');
-
- // 停止所有动画
- this.stopAllAnimations();
-
- // 直接重置到隐藏状态,不使用动画
- this.initializeHiddenState();
-
- // 重置所有状态,为下一局游戏做准备
- this.hasDoubledReward = false;
- // 注意:不重置currentRewards,保持奖励显示直到下次游戏开始
- // this.currentRewards = {money: -1, diamonds: -1}; // 移除这行,避免重置奖励显示
- this.isGameSuccess = false;
- this.hasProcessedGameEnd = false; // 重置处理状态标志
-
- // 重置按钮状态
- if (this.doubleButton) {
- this.doubleButton.interactable = true;
- }
-
- console.log('[GameEnd] UI状态重置完成');
- }
-
- /**
- * 设置EndLabel文本
- * @param text 要显示的文本内容
- */
- private setEndLabelText(text: string) {
- if (this.endLabel) {
- this.endLabel.string = text;
- console.log(`[GameEnd] 已设置EndLabel文本为: ${text}`);
- } else {
- // 如果endLabel未绑定,尝试通过路径查找
- const endLabelNode = find('Canvas/GameEnd/Sprite/EndLabel');
- if (endLabelNode) {
- const labelComponent = endLabelNode.getComponent(Label);
- if (labelComponent) {
- labelComponent.string = text;
- console.log(`[GameEnd] 通过路径查找设置EndLabel文本为: ${text}`);
- } else {
- console.warn('[GameEnd] 找到EndLabel节点但无Label组件');
- }
- } else {
- console.warn('[GameEnd] 未找到EndLabel节点,请检查路径: Canvas/GameEnd/Sprite/EndLabel');
- }
- }
- }
-
- /**
- * 获取当前奖励信息(用于外部查询)
- */
- public getCurrentRewards(): {money: number, diamonds: number} {
- return {...this.currentRewards};
- }
-
- /**
- * 检查是否已获得双倍奖励
- */
- public hasGotDoubleReward(): boolean {
- return this.hasDoubledReward;
- }
-
- // === 动画方法 ===
-
- /**
- * 初始化为隐藏状态
- */
- private initializeHiddenState() {
- // 设置初始透明度为0
- if (this.node) {
- let uiOpacity = this.node.getComponent(UIOpacity);
- if (!uiOpacity) {
- uiOpacity = this.node.addComponent(UIOpacity);
- console.log('[GameEnd] 添加UIOpacity组件到节点');
- }
- uiOpacity.opacity = 0;
- }
-
- // 设置初始缩放为0(完全隐藏,恢复到历史版本实现)
- if (this.node) {
- this.node.setScale(0, 0, 1);
- }
-
- console.log('[GameEnd] 初始化为隐藏状态 - 缩放: 0, 透明度: 0');
- }
-
- /**
- * 初始化为隐藏状态但保持节点激活(用于游戏开始时)
- */
- private initializeHiddenStateKeepActive() {
- // 设置初始透明度为0
- if (this.node) {
- let uiOpacity = this.node.getComponent(UIOpacity);
- if (!uiOpacity) {
- uiOpacity = this.node.addComponent(UIOpacity);
- console.log('[GameEnd] 添加UIOpacity组件到节点');
- }
- uiOpacity.opacity = 0;
- }
-
- // 设置初始缩放为0(完全隐藏,恢复到历史版本实现)
- if (this.node) {
- this.node.setScale(0, 0, 1);
- }
-
- console.log('[GameEnd] 初始化为隐藏状态(保持激活) - 缩放: 0, 透明度: 0');
- }
-
- /**
- * 淡入动画
- */
- public fadeIn(target?: Node, duration?: number): Promise<void> {
- const animTarget = target || this.node;
- const animDuration = duration !== undefined ? duration : this.animationDuration;
-
- if (!animTarget) {
- console.warn('[GameEnd] fadeIn: 未指定目标节点');
- return Promise.resolve();
- }
-
- return new Promise<void>((resolve) => {
- let uiOpacity = animTarget.getComponent(UIOpacity);
- if (!uiOpacity) {
- uiOpacity = animTarget.addComponent(UIOpacity);
- }
-
- Tween.stopAllByTarget(uiOpacity);
- uiOpacity.opacity = 0;
-
- tween(uiOpacity)
- .to(animDuration, { opacity: 255 }, { easing: 'quadOut' })
- .call(() => {
- resolve();
- })
- .start();
- });
- }
-
- /**
- * 淡出动画
- */
- public fadeOut(target?: Node, duration?: number): Promise<void> {
- const animTarget = target || this.node;
- const animDuration = duration !== undefined ? duration : this.animationDuration;
-
- if (!animTarget) {
- console.warn('[GameEnd] fadeOut: 未指定目标节点');
- return Promise.resolve();
- }
-
- return new Promise<void>((resolve) => {
- let uiOpacity = animTarget.getComponent(UIOpacity);
- if (!uiOpacity) {
- uiOpacity = animTarget.addComponent(UIOpacity);
- }
-
- Tween.stopAllByTarget(uiOpacity);
-
- tween(uiOpacity)
- .to(animDuration, { opacity: 0 }, { easing: 'quadIn' })
- .call(() => {
- resolve();
- })
- .start();
- });
- }
-
- /**
- * 缩放弹出动画
- */
- public scalePopIn(target?: Node, duration?: number): Promise<void> {
- const animTarget = target || this.node;
- const animDuration = duration !== undefined ? duration : this.animationDuration;
-
- if (!animTarget) {
- console.warn('[GameEnd] scalePopIn: 未指定目标节点');
- return Promise.resolve();
- }
-
- return new Promise<void>((resolve) => {
- Tween.stopAllByTarget(animTarget);
- animTarget.setScale(0, 0, 1);
-
- tween(animTarget)
- .to(animDuration, { scale: this._originalScale }, { easing: 'backOut' })
- .call(() => {
- resolve();
- })
- .start();
- });
- }
-
- /**
- * 缩放收缩动画
- */
- public scalePopOut(target?: Node, duration?: number): Promise<void> {
- const animTarget = target || this.node;
- const animDuration = duration !== undefined ? duration : this.animationDuration;
-
- if (!animTarget) {
- console.warn('[GameEnd] scalePopOut: 未指定目标节点');
- return Promise.resolve();
- }
-
- return new Promise<void>((resolve) => {
- Tween.stopAllByTarget(animTarget);
-
- tween(animTarget)
- .to(animDuration, { scale: new Vec3(0, 0, 1) }, { easing: 'backIn' })
- .call(() => {
- resolve();
- })
- .start();
- });
- }
-
- /**
- * 组合动画:淡入 + 缩放弹出
- */
- public async fadeInWithScale(fadeTarget?: Node, scaleTarget?: Node, duration?: number): Promise<void> {
- const promises: Promise<void>[] = [];
-
- if (fadeTarget || this.node) {
- promises.push(this.fadeIn(fadeTarget, duration));
- }
-
- if (scaleTarget || this.node) {
- promises.push(this.scalePopIn(scaleTarget, duration));
- }
-
- await Promise.all(promises);
- }
-
- /**
- * 组合动画:淡出 + 缩放收缩
- */
- public async fadeOutWithScale(fadeTarget?: Node, scaleTarget?: Node, duration?: number): Promise<void> {
- const promises: Promise<void>[] = [];
-
- if (fadeTarget || this.node) {
- promises.push(this.fadeOut(fadeTarget, duration));
- }
-
- if (scaleTarget || this.node) {
- promises.push(this.scalePopOut(scaleTarget, duration));
- }
-
- await Promise.all(promises);
- }
-
- /**
- * 停止所有动画
- */
- public stopAllAnimations() {
- if (this.node) {
- // 停止所有Tween动画
- Tween.stopAllByTarget(this.node);
-
- // 停止UIOpacity组件的动画
- const uiOpacity = this.node.getComponent(UIOpacity);
- if (uiOpacity) {
- Tween.stopAllByTarget(uiOpacity);
- }
-
- console.log('[GameEnd] 已停止所有动画');
- } else {
- console.warn('[GameEnd] stopAllAnimations: 节点不存在');
- }
- }
-
- /**
- * 清理所有敌人
- * 在游戏结束时调用,符合阶段一UI弹出阶段的职责
- */
- /**
- * 通过事件系统清理所有敌人
- * 使用CLEAR_ALL_ENEMIES事件,避免直接引用EnemyController
- */
- private clearAllEnemies() {
- console.log('[GameEnd] 游戏结束,派发CLEAR_ALL_ENEMIES事件清理所有敌人');
-
- try {
- // 通过事件总线派发清理敌人事件
- EventBus.getInstance().emit(GameEvents.CLEAR_ALL_ENEMIES);
- console.log('[GameEnd] 已派发CLEAR_ALL_ENEMIES事件,统一清理敌人');
- } catch (error) {
- console.error('[GameEnd] 派发清理敌人事件时发生错误:', error);
- }
- }
-
- /**
- * 重置所有目标节点到初始状态
- */
- public resetToInitialState() {
- this.stopAllAnimations();
-
- if (this.node) {
- let uiOpacity = this.node.getComponent(UIOpacity);
- if (uiOpacity) {
- uiOpacity.opacity = 255;
- }
- this.node.setScale(this._originalScale);
- }
- }
- onDisable() {
- console.log('[GameEnd] onDisable方法被调用,节点已禁用');
-
- // 停止所有动画
- this.stopAllAnimations();
-
- // 清理事件监听
- const eventBus = EventBus.getInstance();
- eventBus.off(GameEvents.GAME_SUCCESS, this.onGameSuccess, this);
- eventBus.off(GameEvents.GAME_DEFEAT, this.onGameDefeat, this);
- eventBus.off(GameEvents.GAME_START, this.onGameStart, this);
- eventBus.off(GameEvents.RESET_UI_STATES, this.onResetUI, this);
- console.log('[GameEnd] 事件监听器已清理');
- }
-
- protected onDestroy() {
- // 停止所有动画
- this.stopAllAnimations();
-
- // 清理事件监听
- const eventBus = EventBus.getInstance();
- eventBus.off(GameEvents.GAME_SUCCESS, this.onGameSuccess, this);
- eventBus.off(GameEvents.GAME_DEFEAT, this.onGameDefeat, this);
- eventBus.off(GameEvents.GAME_START, this.onGameStart, this);
- eventBus.off(GameEvents.RESET_UI_STATES, this.onResetUI, this);
-
- // 清理按钮事件
- if (this.doubleButton) {
- this.doubleButton.node.off(Button.EventType.CLICK, this.onDoubleButtonClick, this);
- }
-
- if (this.continueButton) {
- this.continueButton.node.off(Button.EventType.CLICK, this.onContinueButtonClick, this);
- }
- }
- }
|