SkillSelectionController.ts 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import { _decorator, Component, Node, find, CCFloat, resources, JsonAsset } from 'cc';
  2. import { GameManager } from '../../LevelSystem/GameManager';
  3. import { InGameManager } from '../../LevelSystem/IN_game';
  4. import { SkillButtonController } from './SkillButtonController';
  5. import { SkillManager, SkillData } from './SkillManager';
  6. import { Wall } from '../Wall';
  7. import { EnemyController } from '../EnemyController';
  8. const { ccclass, property } = _decorator;
  9. // 移除本地SkillData声明,直接用SkillManager中的SkillData
  10. interface SkillConfig {
  11. skills: SkillData[];
  12. }
  13. /**
  14. * SkillSelectionController
  15. * 放在 Canvas/SelectSkillUI 节点上。
  16. * 负责监听技能按钮点击,随机选择技能显示,并按顺序播放缩小动画,最后关闭整个 SelectSkillUI。
  17. */
  18. @ccclass('SkillSelectionController')
  19. export class SkillSelectionController extends Component {
  20. @property({ type: [SkillButtonController], tooltip: '技能按钮控制器列表,留空则自动从 SkillsContainer 获取' })
  21. public skillButtons: SkillButtonController[] = [];
  22. @property({ type: CCFloat, tooltip: '收缩动画时长' })
  23. public shrinkDuration: number = 0.3;
  24. // 防止重复点击标记
  25. private _clicked = false;
  26. // 技能配置数据
  27. private _skillConfig: SkillConfig | null = null;
  28. // 当前显示的技能数据
  29. private _currentSkills: SkillData[] = [];
  30. start() {
  31. this.loadSkillConfig();
  32. }
  33. /**
  34. * 加载技能配置
  35. */
  36. private loadSkillConfig() {
  37. resources.load('data/skill', JsonAsset, (err, jsonAsset: JsonAsset) => {
  38. if (err) {
  39. console.error('加载技能配置失败:', err);
  40. return;
  41. }
  42. this._skillConfig = jsonAsset.json as SkillConfig;
  43. // 初始化技能管理器
  44. const skillManager = SkillManager.getInstance();
  45. if (skillManager) {
  46. skillManager.initSkills(this._skillConfig.skills);
  47. }
  48. this.setupSkillButtons();
  49. this.randomizeSkills();
  50. });
  51. }
  52. private setupSkillButtons() {
  53. if (this.skillButtons.length === 0) {
  54. const container = this.node.getChildByName('SkillsContainer');
  55. if (container) {
  56. this.skillButtons = container.children
  57. .map(child => child.getComponent(SkillButtonController))
  58. .filter(controller => controller !== null) as SkillButtonController[];
  59. }
  60. }
  61. this.skillButtons.forEach(skillButton => {
  62. skillButton.setClickCallback((selectedButton) => this.onSkillSelected(selectedButton));
  63. });
  64. }
  65. /**
  66. * 随机选择3个技能显示
  67. */
  68. private randomizeSkills() {
  69. if (!this._skillConfig || this._skillConfig.skills.length < 3) {
  70. console.error('技能配置不足,无法随机选择');
  71. return;
  72. }
  73. // 从6个技能中随机选择3个
  74. const allSkills = [...this._skillConfig.skills];
  75. this._currentSkills = [];
  76. for (let i = 0; i < 3 && allSkills.length > 0; i++) {
  77. const randomIndex = Math.floor(Math.random() * allSkills.length);
  78. this._currentSkills.push(allSkills.splice(randomIndex, 1)[0]);
  79. }
  80. // 更新UI显示
  81. this.updateSkillUI();
  82. }
  83. /**
  84. * 更新技能UI显示
  85. */
  86. private updateSkillUI() {
  87. this.skillButtons.forEach((skillButton, index) => {
  88. if (index < this._currentSkills.length) {
  89. const skillData = this._currentSkills[index];
  90. skillButton.setSkillData(skillData);
  91. // 确保显示当前等级的描述
  92. const skillManager = SkillManager.getInstance();
  93. if (skillManager) {
  94. const currentLevel = skillManager.getSkillLevel(skillData.id);
  95. console.log(`[SkillSelectionController] 技能 ${skillData.name} 当前等级: ${currentLevel}`);
  96. }
  97. } else {
  98. skillButton.setSkillData(null);
  99. }
  100. });
  101. }
  102. /**
  103. * 玩家选择某技能按钮
  104. */
  105. private onSkillSelected(selectedButton: SkillButtonController) {
  106. if (this._clicked) return;
  107. this._clicked = true;
  108. // 获取选中的技能
  109. const selectedSkill = selectedButton.getSkillData();
  110. if (selectedSkill) {
  111. // 通过技能管理器升级技能
  112. const skillManager = SkillManager.getInstance();
  113. if (skillManager) {
  114. skillManager.upgradeSkill(selectedSkill.id);
  115. // 立即更新UI显示新的星级
  116. this.skillButtons.forEach(btn => btn.refreshSkillLevel());
  117. // 如果是治疗技能,立即应用治疗效果
  118. if (selectedSkill.id === 'heal') {
  119. this.applyHealEffect(selectedSkill.id);
  120. }
  121. }
  122. }
  123. const otherButtons = this.skillButtons.filter(btn => btn !== selectedButton);
  124. let finishedOthers = 0;
  125. // 所有其他按钮完成动画后,再收缩选中按钮
  126. const onOtherFinished = () => {
  127. finishedOthers++;
  128. if (finishedOthers >= otherButtons.length) {
  129. // 收缩选中按钮
  130. selectedButton.playShrinkAnimation(this.shrinkDuration, undefined, () => {
  131. const igm = this.getInGameManager();
  132. if (igm) {
  133. igm.resetEnergyValue();
  134. // 检查是否需要播放diban动画
  135. // 通过InGameManager处理后续逻辑
  136. igm.onSkillSelectionComplete();
  137. }
  138. // 关闭后立刻重置UI
  139. this.resetUI();
  140. });
  141. }
  142. };
  143. // 播放其他按钮动画
  144. const targetPos = selectedButton.node.position.clone();
  145. otherButtons.forEach(btn => {
  146. btn.playShrinkAnimation(this.shrinkDuration, targetPos, onOtherFinished);
  147. });
  148. }
  149. /**
  150. * 重置 UI 状态,供下次开启时使用
  151. */
  152. public resetUI() {
  153. this._clicked = false;
  154. // 重新启用所有按钮交互
  155. this.skillButtons.forEach(btn => {
  156. btn.resetAnimationState();
  157. btn.setInteractable(true);
  158. });
  159. // 重新随机选择技能
  160. this.randomizeSkills();
  161. }
  162. /**
  163. * 应用治疗技能效果
  164. */
  165. private applyHealEffect(skillId: string) {
  166. const skillManager = SkillManager.getInstance();
  167. if (!skillManager) return;
  168. const skillLevel = skillManager.getSkillLevel(skillId);
  169. if (skillLevel <= 0) return;
  170. // 查找墙体组件
  171. const wall = this.findWallComponent();
  172. if (!wall) {
  173. console.warn('[SkillSelectionController] 未找到墙体组件,无法应用治疗效果');
  174. return;
  175. }
  176. // 计算治疗量:使用SkillManager的计算方法
  177. const maxHealth = wall.getMaxHealth();
  178. const healAmount = SkillManager.calculateInstantHeal(maxHealth, skillLevel);
  179. // 应用治疗效果
  180. wall.heal(healAmount);
  181. // 由于治疗技能会增加最大血量,需要更新血量显示
  182. wall.updateHealthDisplay();
  183. console.log(`[SkillSelectionController] 应用治疗效果: +${healAmount} 血量,技能等级: ${skillLevel}`);
  184. }
  185. /**
  186. * 查找墙体组件
  187. */
  188. private findWallComponent(): Wall | null {
  189. // 尝试从EnemyController获取墙体组件
  190. const enemyController = EnemyController.getInstance();
  191. if (enemyController) {
  192. // 通过topFenceNode或bottomFenceNode查找Wall组件
  193. if (enemyController.topFenceNode) {
  194. const wall = enemyController.topFenceNode.getComponent(Wall);
  195. if (wall) return wall;
  196. }
  197. if (enemyController.bottomFenceNode) {
  198. const wall = enemyController.bottomFenceNode.getComponent(Wall);
  199. if (wall) return wall;
  200. }
  201. }
  202. // 备用方案:直接在场景中查找
  203. const wallNode = find('Canvas/GameLevelUI/GameArea/TopFence') ||
  204. find('Canvas/GameLevelUI/GameArea/BottomFence') ||
  205. find('Canvas/GameLevelUI/Wall') ||
  206. find('Canvas/Wall');
  207. if (wallNode) {
  208. return wallNode.getComponent(Wall);
  209. }
  210. return null;
  211. }
  212. private getGameManager(): GameManager | null {
  213. const gmNode = find('Canvas/GameLevelUI/GameManager');
  214. return gmNode?.getComponent(GameManager) || null;
  215. }
  216. private getInGameManager(): InGameManager | null {
  217. const gm = this.getGameManager();
  218. return gm ? gm.getInGameManager() : null;
  219. }
  220. }