SkillButtonController.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. import { _decorator, Component, Node, Button, Sprite, Label, resources, SpriteFrame } from 'cc';
  2. import { SkillData, SkillManager } from './SkillManager';
  3. import { SkillButtonAnimator } from './SkillButtonAnimator';
  4. import { Audio } from '../../AudioManager/AudioManager';
  5. import { BundleLoader } from '../../Core/BundleLoader';
  6. const { ccclass, property } = _decorator;
  7. /**
  8. * SkillButtonController
  9. * 单个技能按钮的控制器,负责显示技能信息和处理点击事件
  10. * 配合预制体使用,提高代码复用性和维护性
  11. */
  12. @ccclass('SkillButtonController')
  13. export class SkillButtonController extends Component {
  14. @property({ type: Node, tooltip: '技能图标节点' })
  15. public skillSpriteNode: Node = null!;
  16. @property({ type: Node, tooltip: '技能名称节点' })
  17. public skillNameNode: Node = null!;
  18. @property({ type: Node, tooltip: '技能介绍节点' })
  19. public skillIntroduceNode: Node = null!;
  20. // 当前技能数据
  21. private _skillData: SkillData | null = null;
  22. // 按钮组件
  23. private _button: Button | null = null;
  24. // 动画组件
  25. private _animator: SkillButtonAnimator | null = null;
  26. // 点击回调
  27. private _onClickCallback: ((skillButton: SkillButtonController) => void) | null = null;
  28. protected onLoad() {
  29. this._button = this.getComponent(Button);
  30. this._animator = this.getComponent(SkillButtonAnimator);
  31. // 如果没有手动设置节点引用,尝试自动查找
  32. if (!this.skillSpriteNode) {
  33. this.skillSpriteNode = this.node.getChildByName('SkillSprite');
  34. }
  35. if (!this.skillNameNode) {
  36. this.skillNameNode = this.node.getChildByName('SkillName');
  37. }
  38. if (!this.skillIntroduceNode && this.skillNameNode) {
  39. this.skillIntroduceNode = this.skillNameNode.getChildByName('SkillIntroduce');
  40. }
  41. }
  42. protected start() {
  43. if (this._button) {
  44. this._button.node.on(Button.EventType.CLICK, this.onButtonClick, this);
  45. }
  46. }
  47. protected onDestroy() {
  48. if (this._button) {
  49. this._button.node.off(Button.EventType.CLICK, this.onButtonClick, this);
  50. }
  51. }
  52. /**
  53. * 设置技能数据并更新UI显示
  54. */
  55. public setSkillData(skillData: SkillData) {
  56. this._skillData = skillData;
  57. this.updateUI();
  58. }
  59. /**
  60. * 获取当前技能数据
  61. */
  62. public getSkillData(): SkillData | null {
  63. return this._skillData;
  64. }
  65. /**
  66. * 设置点击回调
  67. */
  68. public setClickCallback(callback: (skillButton: SkillButtonController) => void) {
  69. this._onClickCallback = callback;
  70. }
  71. /**
  72. * 更新UI显示
  73. */
  74. private updateUI() {
  75. if (!this._skillData) {
  76. this.node.active = false;
  77. return;
  78. }
  79. this.node.active = true;
  80. // 更新技能图标
  81. this.updateSkillIcon();
  82. // 更新技能名称
  83. this.updateSkillName();
  84. // 更新技能介绍
  85. this.updateSkillDescription();
  86. // 更新星级显示
  87. this.updateSkillLevel();
  88. }
  89. /**
  90. * 更新技能图标
  91. */
  92. private async updateSkillIcon() {
  93. if (!this.skillSpriteNode || !this._skillData) return;
  94. const sprite = this.skillSpriteNode.getComponent(Sprite);
  95. if (sprite) {
  96. // 转换路径格式,去除"images/"前缀
  97. const bundlePath = this._skillData.iconPath.replace(/^images\//, '');
  98. try {
  99. // 使用BundleLoader从images Bundle加载SpriteFrame,需要添加/spriteFrame后缀
  100. const bundleLoader = BundleLoader.getInstance();
  101. const spriteFrame = await bundleLoader.loadSpriteFrame(bundlePath + '/spriteFrame');
  102. if (spriteFrame && sprite && sprite.isValid) {
  103. sprite.spriteFrame = spriteFrame;
  104. console.log(`技能图标加载成功: ${this._skillData.iconPath}`);
  105. }
  106. } catch (err) {
  107. console.warn(`加载技能图标失败: ${this._skillData.iconPath}`, err);
  108. }
  109. }
  110. }
  111. /**
  112. * 更新技能名称
  113. */
  114. private updateSkillName() {
  115. if (!this.skillNameNode || !this._skillData) return;
  116. const label = this.skillNameNode.getComponent(Label);
  117. if (label) {
  118. label.string = this._skillData.name;
  119. }
  120. }
  121. /**
  122. * 更新技能介绍
  123. */
  124. private updateSkillDescription() {
  125. if (!this.skillIntroduceNode || !this._skillData) return;
  126. const label = this.skillIntroduceNode.getComponent(Label);
  127. if (label) {
  128. const skillManager = SkillManager.getInstance();
  129. if (skillManager) {
  130. // 检查技能是否满级
  131. if (skillManager.isSkillMaxLevel(this._skillData.id)) {
  132. label.string = "技能等级已满";
  133. } else {
  134. // 获取当前技能等级的描述
  135. const currentLevel = skillManager.getSkillLevel(this._skillData.id);
  136. const description = skillManager.getSkillDescription(this._skillData.id, currentLevel);
  137. label.string = description;
  138. }
  139. } else {
  140. label.string = this._skillData.description;
  141. }
  142. }
  143. }
  144. /**
  145. * 更新技能等级显示
  146. */
  147. private updateSkillLevel() {
  148. if (!this._animator || !this._skillData) return;
  149. const skillManager = SkillManager.getInstance();
  150. const actualLevel = skillManager ? skillManager.getSkillLevel(this._skillData.id) : 0;
  151. this._animator.setSkillLevel(actualLevel);
  152. console.log(`设置技能 ${this._skillData.name} 星级: ${actualLevel}`);
  153. }
  154. /**
  155. * 刷新技能等级显示(用于技能升级后的UI更新)
  156. */
  157. public refreshSkillLevel() {
  158. this.updateSkillLevel();
  159. this.updateSkillDescription(); // 同时更新描述
  160. }
  161. /**
  162. * 按钮点击事件
  163. */
  164. private onButtonClick() {
  165. Audio.playUISound('data/弹球音效/level up 2');
  166. if (this._onClickCallback) {
  167. this._onClickCallback(this);
  168. }
  169. }
  170. /**
  171. * 播放收缩动画
  172. */
  173. public playShrinkAnimation(duration: number, targetPos?: any, onComplete?: () => void) {
  174. if (this._animator) {
  175. this._animator.playShrink(duration, targetPos, onComplete);
  176. } else if (onComplete) {
  177. onComplete();
  178. }
  179. }
  180. /**
  181. * 重置动画状态
  182. */
  183. public resetAnimationState() {
  184. if (this._animator) {
  185. this._animator.resetState();
  186. }
  187. }
  188. /**
  189. * 设置按钮交互状态
  190. */
  191. public setInteractable(interactable: boolean) {
  192. if (this._button) {
  193. this._button.interactable = interactable;
  194. }
  195. }
  196. }