UpgradeAni.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import { _decorator, Component, Node, Tween, tween, Vec3, Material, Sprite, resources } from 'cc';
  2. import { Audio } from '../../AudioManager/AudioManager';
  3. const { ccclass, property } = _decorator;
  4. /**
  5. * 植物升级动画控制器
  6. * 负责管理植物升级相关的动画效果
  7. */
  8. @ccclass('UpgradeAni')
  9. export class UpgradeAni extends Component {
  10. @property(Node)
  11. weaponSpriteNode: Node = null;
  12. @property(Node)
  13. upgradeBtnNode: Node = null; // Canvas/UpgradePanel/UpgradeBtn/UP节点
  14. private blinkTween: Tween<Node> = null; // 闪烁动画的引用
  15. /**
  16. * 植物升级成功动画
  17. * 播放植物图标的放大缩小动画,并在升级期间应用扫描效果材质,同时播放升级音效
  18. * @param weaponIconNode 植物图标节点
  19. */
  20. public playWeaponUpgradeAnimation(weaponIconNode: Node): Promise<void> {
  21. return new Promise((resolve) => {
  22. if (!weaponIconNode) {
  23. resolve();
  24. return;
  25. }
  26. // 停止之前的动画,防止快速点击时动画冲突
  27. Tween.stopAllByTarget(weaponIconNode);
  28. // 重置到原始缩放状态,确保动画从正确的状态开始
  29. weaponIconNode.setScale(Vec3.ONE);
  30. // 保存原始缩放值
  31. const originalScale = Vec3.ONE.clone();
  32. let weaponSprite: Sprite = null;
  33. let originalMaterial: Material = null;
  34. console.log('[UpgradeAni] 开始武器升级动画,weaponSpriteNode:', this.weaponSpriteNode);
  35. // 播放植物升级音效
  36. Audio.playUISound('data/弹球音效/equipment level up finish');
  37. // 使用装饰器引用的WeaponSprite节点,获取其Sprite组件并保存原始材质
  38. if (this.weaponSpriteNode) {
  39. console.log('[UpgradeAni] 找到weaponSpriteNode,开始获取Sprite组件');
  40. weaponSprite = this.weaponSpriteNode.getComponent(Sprite);
  41. if (weaponSprite) {
  42. console.log('[UpgradeAni] 找到Sprite组件,开始加载材质');
  43. // 保存原始材质,优先保存customMaterial,如果没有则保存当前material
  44. originalMaterial = weaponSprite.customMaterial || weaponSprite.material;
  45. console.log('[UpgradeAni] 原始材质:', originalMaterial);
  46. // 加载并应用扫描效果材质
  47. resources.load('shaders/scan-effect', Material, (err, scanMaterial) => {
  48. console.log('[UpgradeAni] 材质加载回调,err:', err, 'scanMaterial:', scanMaterial);
  49. if (!err && scanMaterial && weaponSprite) {
  50. weaponSprite.material = scanMaterial;
  51. console.log('[UpgradeAni] 应用扫描效果材质成功');
  52. } else {
  53. console.warn('[UpgradeAni] 加载扫描效果材质失败:', err);
  54. }
  55. });
  56. } else {
  57. console.warn('[UpgradeAni] weaponSpriteNode上没有找到Sprite组件');
  58. }
  59. } else {
  60. console.warn('[UpgradeAni] weaponSpriteNode为null,请在编辑器中设置');
  61. }
  62. // 创建缩放动画:放大到1.5倍再立即缩小回原始大小
  63. const scaleAnimation = tween(weaponIconNode)
  64. .to(0.25, { scale: new Vec3(originalScale.x * 1.5, originalScale.y * 1.5, originalScale.z) }, {
  65. easing: 'sineOut'
  66. })
  67. .to(0.25, { scale: originalScale }, {
  68. easing: 'sineIn'
  69. })
  70. .call(() => {
  71. // 动画结束后恢复原始材质
  72. if (weaponSprite && originalMaterial) {
  73. // 如果原始材质是customMaterial,则恢复customMaterial
  74. if (weaponSprite.customMaterial === originalMaterial) {
  75. weaponSprite.material = weaponSprite.customMaterial;
  76. } else {
  77. weaponSprite.material = originalMaterial;
  78. }
  79. console.log('[UpgradeAni] 恢复原始材质成功');
  80. } else if (weaponSprite) {
  81. // 如果没有保存的原始材质,尝试恢复到customMaterial
  82. if (weaponSprite.customMaterial) {
  83. weaponSprite.material = weaponSprite.customMaterial;
  84. console.log('[UpgradeAni] 恢复到customMaterial');
  85. } else {
  86. weaponSprite.material = null;
  87. console.log('[UpgradeAni] 恢复到默认材质');
  88. }
  89. }
  90. resolve();
  91. });
  92. // 播放缩放动画
  93. scaleAnimation.start();
  94. });
  95. }
  96. /**
  97. * 显示升级面板动画
  98. */
  99. public showPanel(): Promise<void> {
  100. return new Promise((resolve) => {
  101. const panel = this.node;
  102. if (!panel) {
  103. resolve();
  104. return;
  105. }
  106. // 确保面板激活
  107. panel.active = true;
  108. // 停止之前的动画
  109. Tween.stopAllByTarget(panel);
  110. // 设置初始状态:缩放为0
  111. panel.setScale(Vec3.ZERO);
  112. // 播放弹出动画
  113. tween(panel)
  114. .to(0.3, { scale: Vec3.ONE }, {
  115. easing: 'backOut'
  116. })
  117. .call(() => {
  118. resolve();
  119. })
  120. .start();
  121. });
  122. }
  123. /**
  124. * 隐藏升级面板动画
  125. */
  126. public hidePanel(): Promise<void> {
  127. return new Promise((resolve) => {
  128. const panel = this.node;
  129. if (!panel) {
  130. resolve();
  131. return;
  132. }
  133. // 停止之前的动画
  134. Tween.stopAllByTarget(panel);
  135. // 播放缩小动画
  136. tween(panel)
  137. .to(0.2, { scale: Vec3.ZERO }, {
  138. easing: 'backIn'
  139. })
  140. .call(() => {
  141. // 动画结束后隐藏面板
  142. panel.active = false;
  143. resolve();
  144. })
  145. .start();
  146. });
  147. }
  148. /**
  149. * 立即隐藏面板(无动画)
  150. */
  151. public hidePanelImmediate(): void {
  152. const panel = this.node;
  153. if (panel) {
  154. // 停止所有动画
  155. Tween.stopAllByTarget(panel);
  156. // 立即隐藏
  157. panel.active = false;
  158. panel.setScale(Vec3.ONE);
  159. }
  160. }
  161. /**
  162. * 开始升级按钮闪烁动画
  163. * 当钞票足够升级时调用此方法
  164. */
  165. public startUpgradeBtnBlink(): void {
  166. if (!this.upgradeBtnNode) {
  167. console.warn('[UpgradeAni] upgradeBtnNode为null,请在编辑器中设置Canvas/UpgradePanel/UpgradeBtn/UP节点');
  168. return;
  169. }
  170. // 停止之前的闪烁动画
  171. this.stopUpgradeBtnBlink();
  172. // 重置到原始缩放状态
  173. this.upgradeBtnNode.setScale(Vec3.ONE);
  174. // 创建循环闪烁动画:放大到1.5倍再缩小回原始大小,无限循环
  175. this.blinkTween = tween(this.upgradeBtnNode)
  176. .to(0.5, { scale: new Vec3(1.5, 1.5, 1) }, {
  177. easing: 'sineInOut'
  178. })
  179. .to(0.5, { scale: Vec3.ONE }, {
  180. easing: 'sineInOut'
  181. })
  182. .union() // 将上面的动画组合成一个整体
  183. .repeatForever(); // 无限循环
  184. this.blinkTween.start();
  185. console.log('[UpgradeAni] 开始升级按钮闪烁动画');
  186. }
  187. /**
  188. * 停止升级按钮闪烁动画
  189. * 当钞票不够升级时调用此方法
  190. */
  191. public stopUpgradeBtnBlink(): void {
  192. if (this.blinkTween) {
  193. this.blinkTween.stop();
  194. this.blinkTween = null;
  195. }
  196. if (this.upgradeBtnNode) {
  197. // 停止节点上的所有动画
  198. Tween.stopAllByTarget(this.upgradeBtnNode);
  199. // 恢复到原始缩放状态
  200. this.upgradeBtnNode.setScale(Vec3.ONE);
  201. }
  202. console.log('[UpgradeAni] 停止升级按钮闪烁动画');
  203. }
  204. /**
  205. * 检查升级按钮是否正在闪烁
  206. * @returns 是否正在闪烁
  207. */
  208. public isUpgradeBtnBlinking(): boolean {
  209. return this.blinkTween !== null;
  210. }
  211. }