GainUI.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { _decorator, Component, Node, Label, Sprite, Button } from 'cc';
  2. import EventBus, { GameEvents } from '../Core/EventBus';
  3. import { JsonConfigLoader } from '../Core/JsonConfigLoader';
  4. import { BundleLoader } from '../Core/BundleLoader';
  5. import { PopUPAni } from '../Animations/PopUPAni';
  6. const { ccclass, property } = _decorator;
  7. @ccclass('GainUI')
  8. export class GainUI extends Component {
  9. @property(Node) panel: Node = null; // 弹窗根节点
  10. @property(Label) titleLabel: Label = null; // 标题,如“新武器”
  11. @property(Sprite) iconSprite: Sprite = null; // 武器图标
  12. @property(Label) nameLabel: Label = null; // 武器名称
  13. @property(Node) bt1: Node = null; // Canvas/GainUI/bt1
  14. @property(Node) weaponNode: Node = null; // Canvas/GainUI/Weapon
  15. @property(Button) confirmBtn: Button = null; // 确认按钮
  16. private weaponsConfig: any = null;
  17. private bundleLoader: BundleLoader = null;
  18. // 等待展示的武器名称队列(来自 UpgradeController 派发的 NEW_WEAPONS_UNLOCKED)
  19. private pendingWeapons: string[] = [];
  20. // 是否已经完成奖励动画(由 MoneyAni 派发 REWARD_ANIMATION_COMPLETED)
  21. private rewardAnimationCompleted = false;
  22. // 当前是否正在显示弹窗
  23. private showing = false;
  24. // 当前正在展示的武器名称(用于避免重复渲染队列首项)
  25. private currentWeaponName: string | null = null;
  26. // 辅助:获取或添加 PopUPAni 组件
  27. private getOrAddPopAni(node: Node): PopUPAni | null {
  28. if (!node) return null;
  29. let comp = node.getComponent(PopUPAni);
  30. if (!comp) {
  31. comp = node.addComponent(PopUPAni);
  32. }
  33. return comp;
  34. }
  35. async onLoad() {
  36. this.bundleLoader = BundleLoader.getInstance();
  37. // 默认隐藏弹窗
  38. if (this.panel) this.panel.active = false;
  39. console.log('[GainUI] 已隐藏弹窗(默认状态)');
  40. // 改为仅监听GameManager派发的显示事件
  41. EventBus.getInstance().on(GameEvents.SHOW_GAIN_UI, this.onShowGainUI, this);
  42. // 监听新武器解锁事件,接收武器名称队列
  43. EventBus.getInstance().on(GameEvents.NEW_WEAPONS_UNLOCKED, this.onNewWeaponsUnlocked, this);
  44. // 绑定确认按钮
  45. this.confirmBtn?.node.on(Button.EventType.CLICK, this.onConfirm, this);
  46. }
  47. async start() {
  48. console.log('[GainUI] 已初始化,等待新武器解锁事件...');
  49. // 预加载武器配置,便于查找图标与名称
  50. try {
  51. this.weaponsConfig = await JsonConfigLoader.getInstance().loadConfig('weapons');
  52. } catch (err) {
  53. console.warn('[GainUI] 加载武器配置失败:', err);
  54. }
  55. }
  56. onDestroy() {
  57. EventBus.getInstance().off(GameEvents.SHOW_GAIN_UI, this.onShowGainUI, this);
  58. EventBus.getInstance().off(GameEvents.NEW_WEAPONS_UNLOCKED, this.onNewWeaponsUnlocked, this);
  59. this.confirmBtn?.node.off(Button.EventType.CLICK, this.onConfirm, this);
  60. }
  61. // 确认按钮逻辑:继续展示队列中的下一个或关闭弹窗
  62. private async onConfirm() {
  63. if (this.pendingWeapons.length > 0) {
  64. const nextName = this.pendingWeapons.shift();
  65. await this.renderWeapon(nextName);
  66. } else {
  67. if (this.panel) this.panel.active = false;
  68. this.showing = false;
  69. this.currentWeaponName = null;
  70. EventBus.getInstance().emit(GameEvents.GAIN_UI_CONFIRMED);
  71. }
  72. }
  73. // 接收解锁事件并更新待展示队列
  74. private async onNewWeaponsUnlocked(weaponNames: string[]) {
  75. if (!weaponNames || weaponNames.length === 0) return;
  76. this.pendingWeapons.push(...weaponNames);
  77. console.log('[GainUI] 收到新武器解锁:', weaponNames);
  78. // 如果弹窗已显示且当前未渲染任何武器,则渲染第一个
  79. if (this.showing && !this.currentWeaponName && this.pendingWeapons.length > 0) {
  80. const first = this.pendingWeapons.shift();
  81. await this.renderWeapon(first);
  82. }
  83. }
  84. // 根据武器名称渲染弹窗内容(标题、图标、名称)
  85. private async renderWeapon(weaponName: string) {
  86. this.currentWeaponName = weaponName || null;
  87. if (this.titleLabel) this.titleLabel.string = '新武器';
  88. if (this.nameLabel) this.nameLabel.string = weaponName || '';
  89. // 查找武器配置,加载图标
  90. const config = this.findWeaponConfigByName(weaponName);
  91. if (config && config.visualConfig && config.visualConfig.weaponSprites) {
  92. let spritePath: string;
  93. const sprites = config.visualConfig.weaponSprites;
  94. if (typeof sprites === 'string') {
  95. spritePath = sprites;
  96. } else {
  97. spritePath = sprites['I'] || sprites['H-I'] || sprites['L'] || sprites['S'] || sprites['D-T'];
  98. }
  99. if (spritePath && this.iconSprite) {
  100. await this.loadWeaponSprite(this.iconSprite, spritePath);
  101. }
  102. }
  103. }
  104. private findWeaponConfigByName(name: string) {
  105. if (!this.weaponsConfig || !this.weaponsConfig.weapons) return null;
  106. return this.weaponsConfig.weapons.find((w: any) => w.name === name);
  107. }
  108. private async loadWeaponSprite(sprite: Sprite, spritePath: string) {
  109. const bundlePath = spritePath.replace(/^images\//, '');
  110. try {
  111. const spriteFrame = await this.bundleLoader.loadSpriteFrame(bundlePath + '/spriteFrame');
  112. if (spriteFrame && sprite && sprite.isValid) {
  113. sprite.spriteFrame = spriteFrame;
  114. }
  115. } catch (err) {
  116. console.warn(`[GainUI] 加载武器图标失败: ${spritePath}`, err);
  117. }
  118. }
  119. // 新增:接收GameManager派发的显示事件,直接显示弹窗
  120. private onShowGainUI = async () => {
  121. if (this.panel) {
  122. this.panel.active = true;
  123. const parent = this.panel.parent;
  124. if (parent) {
  125. this.panel.setSiblingIndex(parent.children.length - 1);
  126. }
  127. }
  128. this.showing = true;
  129. // 新增:显示时让 bt1 与 Weapon 节点弹出显示
  130. try {
  131. const promises: Promise<void>[] = [];
  132. const bt1Ani = this.getOrAddPopAni(this.bt1);
  133. const weaponAni = this.getOrAddPopAni(this.weaponNode);
  134. if (bt1Ani) promises.push(bt1Ani.showPanel());
  135. if (weaponAni) promises.push(weaponAni.showPanel());
  136. if (promises.length > 0) {
  137. await Promise.all(promises);
  138. }
  139. } catch (e) {
  140. console.warn('[GainUI] 弹出动画执行失败:', e);
  141. }
  142. // 如果已有待展示武器,立即渲染第一个(并弹出队列)
  143. if (this.pendingWeapons.length > 0) {
  144. const first = this.pendingWeapons.shift();
  145. await this.renderWeapon(first);
  146. }
  147. }
  148. }