|
|
@@ -1,7 +1,8 @@
|
|
|
-import { _decorator, Component, Node, Label, Button } from 'cc';
|
|
|
+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;
|
|
|
|
|
|
/**
|
|
|
@@ -42,16 +43,44 @@ export class GameEnd extends Component {
|
|
|
})
|
|
|
public inGameManager: InGameManager = null;
|
|
|
|
|
|
- // 动画相关属性已移除,现在由MoneyAni组件负责处理奖励动画
|
|
|
+ @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};
|
|
|
private hasDoubledReward: boolean = false;
|
|
|
private isGameSuccess: boolean = false;
|
|
|
+
|
|
|
+ onLoad() {
|
|
|
+ console.log('[GameEnd] onLoad方法被调用');
|
|
|
+ this.setupEventListeners();
|
|
|
+ }
|
|
|
|
|
|
start() {
|
|
|
console.log('[GameEnd] start方法被调用');
|
|
|
+
|
|
|
+ // 保存原始缩放值
|
|
|
+ if (this.node) {
|
|
|
+ this._originalScale.set(this.node.scale);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化为隐藏状态(通过动画实现)
|
|
|
+ this.initializeHiddenState();
|
|
|
+
|
|
|
+ // 监听游戏事件
|
|
|
// start方法只在节点首次激活时调用一次
|
|
|
// 如果节点初始状态为false,start不会被调用
|
|
|
}
|
|
|
@@ -67,9 +96,6 @@ export class GameEnd extends Component {
|
|
|
// 绑定按钮事件
|
|
|
this.bindButtonEvents();
|
|
|
|
|
|
- // 监听游戏事件
|
|
|
- this.setupEventListeners();
|
|
|
-
|
|
|
// 初始化UI状态
|
|
|
this.initializeUI();
|
|
|
|
|
|
@@ -83,6 +109,116 @@ export class GameEnd extends Component {
|
|
|
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);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -122,14 +258,11 @@ export class GameEnd extends Component {
|
|
|
* 初始化UI状态
|
|
|
*/
|
|
|
private initializeUI() {
|
|
|
- // 不强制隐藏面板,让UIStateManager控制面板显示状态
|
|
|
- // this.node.active = false;
|
|
|
-
|
|
|
// 重置状态
|
|
|
this.hasDoubledReward = false;
|
|
|
this.currentRewards = {money: 0, diamonds: 0};
|
|
|
|
|
|
- console.log('[GameEnd] UI状态初始化完成,面板状态由UIStateManager控制');
|
|
|
+ console.log('[GameEnd] UI状态初始化完成');
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -160,20 +293,57 @@ export class GameEnd extends Component {
|
|
|
|
|
|
/**
|
|
|
* 处理游戏成功事件
|
|
|
+ * 统一处理游戏成功逻辑:状态切换 + UI显示 + 奖励计算
|
|
|
*/
|
|
|
private onGameSuccess() {
|
|
|
console.log('[GameEnd] 接收到GAME_SUCCESS事件');
|
|
|
- console.log('[GameEnd] 游戏成功,准备显示奖励');
|
|
|
+ console.log('[GameEnd] 游戏成功,开始统一处理流程');
|
|
|
+
|
|
|
+ // 1. 设置游戏状态为成功(如果还未设置)
|
|
|
+ if (this.inGameManager && this.inGameManager.getCurrentState() !== GameState.SUCCESS) {
|
|
|
+ this.inGameManager.setCurrentState(GameState.SUCCESS);
|
|
|
+ console.log('[GameEnd] 已将游戏状态切换为SUCCESS');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 设置EndLabel文本
|
|
|
+ this.setEndLabelText('SUCCESS');
|
|
|
+
|
|
|
+ // 3. 显示UI面板
|
|
|
+ this.showEndPanelWithAnimation();
|
|
|
+
|
|
|
+ // 4. 计算和显示奖励
|
|
|
this.isGameSuccess = true;
|
|
|
this.calculateAndShowRewards();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 处理游戏失败事件
|
|
|
+ * 统一处理游戏失败逻辑:状态切换 + UI显示 + 奖励计算
|
|
|
*/
|
|
|
private onGameDefeat() {
|
|
|
console.log('[GameEnd] 接收到GAME_DEFEAT事件');
|
|
|
- console.log('[GameEnd] 游戏失败,准备显示奖励');
|
|
|
+ console.log('[GameEnd] 游戏失败,开始统一处理流程');
|
|
|
+ console.log('[GameEnd] 当前节点激活状态:', this.node.active);
|
|
|
+ console.log('[GameEnd] moneyLabel绑定状态:', !!this.moneyLabel);
|
|
|
+ console.log('[GameEnd] diamondLabel绑定状态:', !!this.diamondLabel);
|
|
|
+
|
|
|
+ // 1. 设置游戏状态为失败(如果还未设置)
|
|
|
+ if (this.inGameManager && this.inGameManager.getCurrentState() !== GameState.DEFEAT) {
|
|
|
+ this.inGameManager.setCurrentState(GameState.DEFEAT);
|
|
|
+ console.log('[GameEnd] 已将游戏状态切换为DEFEAT');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 播放游戏失败音效
|
|
|
+ Audio.playUISound('data/弹球音效/lose');
|
|
|
+ console.log('[GameEnd] 已播放游戏失败音效');
|
|
|
+
|
|
|
+ // 3. 设置EndLabel文本
|
|
|
+ this.setEndLabelText('DEFEAT');
|
|
|
+
|
|
|
+ // 4. 显示UI面板
|
|
|
+ this.showEndPanelWithAnimation();
|
|
|
+
|
|
|
+ // 5. 计算和显示奖励
|
|
|
this.isGameSuccess = false;
|
|
|
this.calculateAndShowRewards();
|
|
|
}
|
|
|
@@ -213,8 +383,8 @@ export class GameEnd extends Component {
|
|
|
console.log('[GameEnd] 获取到的奖励数据:', this.currentRewards);
|
|
|
this.updateRewardDisplay();
|
|
|
|
|
|
- // 显示结算面板
|
|
|
- this.showEndPanel();
|
|
|
+ // 显示结算面板(通过动画)
|
|
|
+ this.showEndPanelWithAnimation();
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('[GameEnd] 计算奖励时出错:', error);
|
|
|
@@ -225,38 +395,106 @@ export class GameEnd extends Component {
|
|
|
* 更新奖励显示
|
|
|
*/
|
|
|
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] 更新奖励显示 - 钞票: ${this.currentRewards.money}, 钻石: ${this.currentRewards.diamonds}`);
|
|
|
+ console.log(`[GameEnd] 奖励显示更新完成`);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 显示结算面板
|
|
|
+ * 显示结算面板(通过动画)
|
|
|
*/
|
|
|
- private showEndPanel() {
|
|
|
- this.node.active = true;
|
|
|
-
|
|
|
+ private showEndPanelWithAnimation() {
|
|
|
+
|
|
|
// 重置双倍奖励状态
|
|
|
this.hasDoubledReward = false;
|
|
|
if (this.doubleButton) {
|
|
|
this.doubleButton.interactable = true;
|
|
|
}
|
|
|
|
|
|
- console.log('[GameEnd] 结算面板已显示');
|
|
|
+ // 播放显示动画(如果有的话)
|
|
|
+ if (this.animationDuration > 0) {
|
|
|
+ this.playShowAnimation();
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
+ console.log('[GameEnd] 结算面板已通过动画显示');
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 播放显示动画
|
|
|
+ */
|
|
|
+ private playShowAnimation() {
|
|
|
+ if (!this.node) return;
|
|
|
+
|
|
|
+ // 设置节点位置到屏幕中心
|
|
|
+ this.centerNodeOnScreen();
|
|
|
+
|
|
|
+ // 设置初始状态
|
|
|
+ this.node.setScale(0.5, 0.5, 1);
|
|
|
+ const uiOpacity = this.node.getComponent(UIOpacity);
|
|
|
+ if (uiOpacity) {
|
|
|
+ uiOpacity.opacity = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 播放缩放和淡入动画
|
|
|
+ tween(this.node)
|
|
|
+ .to(this.animationDuration, {
|
|
|
+ scale: new Vec3(1, 1, 1)
|
|
|
+ }, {
|
|
|
+ easing: 'backOut'
|
|
|
+ })
|
|
|
+ .start();
|
|
|
+
|
|
|
+ if (uiOpacity) {
|
|
|
+ tween(uiOpacity)
|
|
|
+ .to(this.animationDuration, {
|
|
|
+ opacity: 255
|
|
|
+ })
|
|
|
+ .start();
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('[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;
|
|
|
@@ -315,6 +553,8 @@ export class GameEnd extends Component {
|
|
|
* 继续按钮点击事件
|
|
|
*/
|
|
|
private onContinueButtonClick() {
|
|
|
+ // 播放UI点击音效
|
|
|
+ Audio.playUISound('data/弹球音效/ui play');
|
|
|
console.log('[GameEnd] 点击继续按钮');
|
|
|
|
|
|
// 派发事件给MoneyAni播放奖励动画
|
|
|
@@ -328,16 +568,18 @@ export class GameEnd extends Component {
|
|
|
// 触发返回主菜单事件
|
|
|
EventBus.getInstance().emit('CONTINUE_CLICK');
|
|
|
|
|
|
- // 隐藏结算面板
|
|
|
- this.hideEndPanel();
|
|
|
+ // 隐藏结算面板(通过动画)
|
|
|
+ this.hideEndPanelWithAnimation();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 隐藏结算面板
|
|
|
+ * 隐藏结算面板(通过动画)
|
|
|
*/
|
|
|
- private hideEndPanel() {
|
|
|
- this.node.active = false;
|
|
|
- console.log('[GameEnd] 结算面板已隐藏');
|
|
|
+ private async hideEndPanelWithAnimation() {
|
|
|
+ // 播放隐藏动画
|
|
|
+ await this.fadeOutWithScale();
|
|
|
+
|
|
|
+ console.log('[GameEnd] 结算面板已通过动画隐藏');
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -345,11 +587,36 @@ export class GameEnd extends Component {
|
|
|
*/
|
|
|
private onResetUI() {
|
|
|
console.log('[GameEnd] 重置UI状态');
|
|
|
- this.hideEndPanel();
|
|
|
+ this.hideEndPanelWithAnimation();
|
|
|
this.hasDoubledReward = false;
|
|
|
this.currentRewards = {money: 0, diamonds: 0};
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 设置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');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 获取当前奖励信息(用于外部查询)
|
|
|
*/
|
|
|
@@ -364,27 +631,205 @@ export class GameEnd extends Component {
|
|
|
return this.hasDoubledReward;
|
|
|
}
|
|
|
|
|
|
+ // === 动画方法 ===
|
|
|
|
|
|
+ /**
|
|
|
+ * 初始化为隐藏状态
|
|
|
+ */
|
|
|
+ private initializeHiddenState() {
|
|
|
+ // 设置初始透明度为0
|
|
|
+ if (this.node) {
|
|
|
+ let uiOpacity = this.node.getComponent(UIOpacity);
|
|
|
+ if (!uiOpacity) {
|
|
|
+ uiOpacity = this.node.addComponent(UIOpacity);
|
|
|
+ }
|
|
|
+ uiOpacity.opacity = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置初始缩放为0
|
|
|
+ if (this.node) {
|
|
|
+ this.node.setScale(0, 0, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('[GameEnd] 初始化为隐藏状态');
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ /**
|
|
|
+ * 淡入动画
|
|
|
+ */
|
|
|
+ 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) {
|
|
|
+ const uiOpacity = this.node.getComponent(UIOpacity);
|
|
|
+ if (uiOpacity) {
|
|
|
+ Tween.stopAllByTarget(uiOpacity);
|
|
|
+ }
|
|
|
+ Tween.stopAllByTarget(this.node);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ /**
|
|
|
+ * 重置所有目标节点到初始状态
|
|
|
+ */
|
|
|
+ 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);
|
|
|
@@ -394,6 +839,9 @@ export class GameEnd extends Component {
|
|
|
}
|
|
|
|
|
|
protected onDestroy() {
|
|
|
+ // 停止所有动画
|
|
|
+ this.stopAllAnimations();
|
|
|
+
|
|
|
// 清理事件监听
|
|
|
const eventBus = EventBus.getInstance();
|
|
|
eventBus.off(GameEvents.GAME_SUCCESS, this.onGameSuccess, this);
|