SkillSelectionController.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { _decorator, Component, Node, Button, Vec3, find} from 'cc';
  2. import SkillButtonAnimator from './SkillButtonAnimator';
  3. import { GameManager } from '../../LevelSystem/GameManager';
  4. const { ccclass, property } = _decorator;
  5. /**
  6. * SkillSelectionController
  7. * 放在 Canvas/SelectSkillUI 节点上。
  8. * 负责监听技能按钮点击,并按顺序播放缩小动画,最后关闭整个 SelectSkillUI。
  9. */
  10. @ccclass('SkillSelectionController')
  11. export class SkillSelectionController extends Component {
  12. @property({ type: [Node], tooltip: '技能按钮节点列表,留空则自动从 SkillsContainer 获取' })
  13. public skillButtons: Node[] = [];
  14. @property({ tooltip: '缩小动画时长(秒)' })
  15. public shrinkDuration: number = 0.25;
  16. private _clicked = false;
  17. start() {
  18. // 自动收集按钮
  19. if (this.skillButtons.length === 0) {
  20. const container = this.node.getChildByName('SkillsContainer');
  21. if (container) {
  22. this.skillButtons = container.children;
  23. }
  24. }
  25. // 绑定点击事件
  26. this.skillButtons.forEach(btn => {
  27. const buttonComp = btn.getComponent(Button);
  28. if (buttonComp) {
  29. buttonComp.node.on(Button.EventType.CLICK, () => this.onSkillSelected(btn));
  30. } else {
  31. // 兜底:直接监听触摸
  32. btn.on(Node.EventType.TOUCH_END, () => this.onSkillSelected(btn));
  33. }
  34. });
  35. }
  36. /**
  37. * 玩家选择某技能按钮
  38. */
  39. private onSkillSelected(selectedBtn: Node) {
  40. if (this._clicked) return; // 只允许一次
  41. this._clicked = true;
  42. // 禁用所有按钮交互
  43. this.skillButtons.forEach(btn => {
  44. const b = btn.getComponent(Button);
  45. if (b) b.interactable = false;
  46. });
  47. const otherBtns = this.skillButtons.filter(btn => btn !== selectedBtn);
  48. let finishedOthers = 0;
  49. // 所有其他按钮完成动画后,再收缩选中按钮
  50. const onOtherFinished = () => {
  51. finishedOthers++;
  52. if (finishedOthers >= otherBtns.length) {
  53. // 收缩选中按钮
  54. const selAnim = selectedBtn.getComponent(SkillButtonAnimator);
  55. selAnim?.playShrink(this.shrinkDuration, undefined, () => {
  56. // 关闭整个 UI
  57. this.node.active = false;
  58. // 恢复游戏并重置能量
  59. const gm = this.getGameManager();
  60. if (gm) {
  61. gm.resetEnergy();
  62. gm.resumeGame();
  63. }
  64. // 关闭后立刻重置UI
  65. this.resetUI();
  66. });
  67. }
  68. };
  69. // 播放其他按钮动画
  70. const targetPos = selectedBtn.position.clone();
  71. otherBtns.forEach(btn => {
  72. const anim = btn.getComponent(SkillButtonAnimator);
  73. anim?.playShrink(this.shrinkDuration, targetPos, onOtherFinished);
  74. });
  75. }
  76. private resetUI() {
  77. this._clicked = false;
  78. this.skillButtons.forEach(btn => {
  79. // 恢复交互
  80. const b = btn.getComponent(Button);
  81. if (b) b.interactable = true;
  82. // 恢复缩放
  83. btn.setScale(Vec3.ONE);
  84. // 恢复位置(如果有初始位置记录,建议用初始位置)
  85. // btn.setPosition(初始位置);
  86. // 恢复透明度等
  87. // btn.opacity = 255;
  88. // 还原动画状态
  89. const anim = btn.getComponent(SkillButtonAnimator);
  90. anim?.resetState?.();
  91. });
  92. }
  93. private _gameManager: GameManager = null;
  94. private getGameManager(): GameManager {
  95. if (this._gameManager && this._gameManager.isValid) return this._gameManager;
  96. // 尝试在 Canvas 下递归查找
  97. const canvas = find('Canvas');
  98. if (canvas) {
  99. this._gameManager = canvas.getComponentInChildren(GameManager);
  100. if (this._gameManager) return this._gameManager;
  101. }
  102. }
  103. }
  104. export default SkillSelectionController;