NavBarController.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. import { _decorator, Color, Component, Node, Sprite, find, Vec3 } from 'cc';
  2. import EventBus, { GameEvents } from '../Core/EventBus';
  3. import { GameStartMove } from '../Animations/GameStartMove';
  4. import { Audio } from '../AudioManager/AudioManager';
  5. const { ccclass, property } = _decorator;
  6. @ccclass('NavBarController')
  7. export class NavBarController extends Component {
  8. @property({ type: [Node] }) panels: Node[] = []; // 依次给 Main、Shop、Upgrade、Skill
  9. @property({ type: [Node] }) buttons: Node[] = []; // 依次给 Battle、Shop、Upgrade、Skill
  10. @property({ type: [Node] }) buttonBorders: Node[] = []; // 按钮边框节点数组,需要手动配置
  11. private normalColor = new Color(255, 255, 255, 255);
  12. private lockedColor = new Color(128, 128, 128, 255); // 灰色(锁定状态)
  13. // 按钮锁定状态数组 - 对应 Battle、Shop、Upgrade、Skill 四个按钮
  14. private buttonLockStates: boolean[] = [false, true, false, false]; // 默认只锁定Shop按钮
  15. // 存储按钮原始位置
  16. private buttonOriginalPositions: Vec3[] = [];
  17. // 当前激活的按钮索引
  18. private currentActiveButtonIndex: number = -1;
  19. // GameStartMove组件引用,用于重置镜头位置
  20. private gameStartMoveComponent: GameStartMove = null;
  21. start () {
  22. // 保存按钮原始位置
  23. this.saveButtonOriginalPositions();
  24. // 默认打开 MainUI
  25. this.switchTo(0);
  26. // 初始化按钮状态,设置shop按钮为锁定状态
  27. this.updateButtonStates();
  28. // 设置事件监听
  29. this.setupEventListeners();
  30. }
  31. onDestroy() {
  32. // 移除事件监听
  33. this.removeEventListeners();
  34. }
  35. /**
  36. * 设置事件监听器
  37. */
  38. private setupEventListeners() {
  39. const eventBus = EventBus.getInstance();
  40. // 监听返回主菜单事件
  41. eventBus.on(GameEvents.RETURN_TO_MAIN_MENU, this.onReturnToMainMenu, this);
  42. }
  43. /**
  44. * 移除事件监听器
  45. */
  46. private removeEventListeners() {
  47. const eventBus = EventBus.getInstance();
  48. eventBus.off(GameEvents.RETURN_TO_MAIN_MENU, this.onReturnToMainMenu, this);
  49. }
  50. /**
  51. * 保存按钮原始位置
  52. */
  53. private saveButtonOriginalPositions() {
  54. this.buttonOriginalPositions = [];
  55. this.buttons.forEach(btn => {
  56. this.buttonOriginalPositions.push(btn.position.clone());
  57. });
  58. console.log('[NavBarController] 已保存按钮原始位置');
  59. }
  60. /**
  61. * 处理返回主菜单事件
  62. */
  63. private onReturnToMainMenu() {
  64. console.log('[NavBarController] 收到返回主菜单事件,切换到主界面');
  65. // 重置镜头位置到原始位置
  66. this.resetCameraPosition();
  67. // 切换到主界面(Battle按钮对应的Main面板,索引0)
  68. this.switchTo(0);
  69. }
  70. /**
  71. * 重置镜头位置到原始位置
  72. * 确保从游戏中返回主界面时镜头位置正常
  73. */
  74. private resetCameraPosition() {
  75. // 如果还没有获取GameStartMove组件,尝试获取
  76. if (!this.gameStartMoveComponent) {
  77. const cameraNode = find('Canvas/Main Camera');
  78. if (cameraNode) {
  79. this.gameStartMoveComponent = cameraNode.getComponent(GameStartMove);
  80. }
  81. }
  82. // 如果成功获取到组件,重置镜头位置
  83. if (this.gameStartMoveComponent) {
  84. console.log('[NavBarController] 重置镜头位置到原始位置');
  85. this.gameStartMoveComponent.resetCameraToOriginalPosition(0.3);
  86. } else {
  87. console.warn('[NavBarController] 未找到GameStartMove组件,无法重置镜头位置');
  88. }
  89. }
  90. onBattleClick () {
  91. // 播放UI点击音效
  92. Audio.playUISound('data/弹球音效/ui play');
  93. // 检查Battle按钮是否被锁定(索引0)
  94. if (this.buttonLockStates[0]) {
  95. console.log('[NavBarController] Battle按钮被锁定,无法点击');
  96. // 发送Toast事件显示锁定提示
  97. EventBus.getInstance().emit(GameEvents.SHOW_TOAST, {
  98. message: '暂未解锁该功能!',
  99. duration: 2.0
  100. });
  101. return;
  102. }
  103. this.switchTo(0);
  104. }
  105. onUpgradeClick () {
  106. // 播放UI点击音效
  107. Audio.playUISound('data/弹球音效/ui play');
  108. // 检查Upgrade按钮是否被锁定(索引2)
  109. if (this.buttonLockStates[2]) {
  110. console.log('[NavBarController] Upgrade按钮被锁定,无法点击');
  111. // 发送Toast事件显示锁定提示
  112. EventBus.getInstance().emit(GameEvents.SHOW_TOAST, {
  113. message: '暂未解锁该功能!',
  114. duration: 2.0
  115. });
  116. return;
  117. }
  118. this.switchTo(1);
  119. }
  120. onShopClick () {
  121. // 播放UI点击音效
  122. Audio.playUISound('data/弹球音效/ui play');
  123. // 检查shop按钮是否被锁定(索引1)
  124. if (this.buttonLockStates[1]) {
  125. console.log('[NavBarController] Shop按钮被锁定,无法点击');
  126. // 发送Toast事件显示锁定提示
  127. EventBus.getInstance().emit(GameEvents.SHOW_TOAST, {
  128. message: '暂未解锁该功能!',
  129. duration: 2.0
  130. });
  131. return;
  132. }
  133. this.switchTo(2);
  134. }
  135. onSkillClick () {
  136. // 播放UI点击音效
  137. Audio.playUISound('data/弹球音效/ui play');
  138. // 检查Skill按钮是否被锁定(索引3)
  139. if (this.buttonLockStates[3]) {
  140. console.log('[NavBarController] Skill按钮被锁定,无法点击');
  141. // 发送Toast事件显示锁定提示
  142. EventBus.getInstance().emit(GameEvents.SHOW_TOAST, {
  143. message: '暂未解锁该功能!',
  144. duration: 2.0
  145. });
  146. return;
  147. }
  148. this.switchTo(3);
  149. // 注意:滚动功能现在由SkillNodeGenerator组件通过装饰器直接处理
  150. }
  151. private switchTo (index: number) {
  152. // 显示对应面板
  153. this.panels.forEach((p, i) => p.active = i === index);
  154. // 按钮索引到面板索引的映射:根据实际的点击事件调用
  155. // 按钮索引: [0:Battle, 1:Shop, 2:Upgrade, 3:Skill]
  156. // 面板索引: [0:Main, 1:Shop, 2:Upgrade, 3:Skill]
  157. // 实际映射: Battle->Main(0), Shop->Upgrade(2), Upgrade->Shop(1), Skill->Skill(3)
  158. const buttonToPanelMap = [0, 2, 1, 3]; // Battle->Main(0), Shop->Upgrade(2), Upgrade->Shop(1), Skill->Skill(3)
  159. // 重置所有按钮到原始位置和状态
  160. this.buttons.forEach((btn, buttonIndex) => {
  161. const sp = btn.getComponent(Sprite);
  162. if (sp) {
  163. // 重置按钮位置到原始位置
  164. if (this.buttonOriginalPositions[buttonIndex]) {
  165. btn.position = this.buttonOriginalPositions[buttonIndex].clone();
  166. }
  167. // 设置按钮颜色(只处理锁定状态)
  168. if (this.buttonLockStates[buttonIndex]) {
  169. sp.color = this.lockedColor; // 锁定状态显示灰色
  170. } else {
  171. sp.color = this.normalColor; // 正常状态显示白色
  172. }
  173. }
  174. });
  175. // 隐藏所有边框
  176. this.buttonBorders.forEach(border => {
  177. if (border) {
  178. border.active = false;
  179. }
  180. });
  181. // 找到当前激活的按钮索引
  182. let activeButtonIndex = -1;
  183. for (let buttonIndex = 0; buttonIndex < buttonToPanelMap.length; buttonIndex++) {
  184. if (buttonToPanelMap[buttonIndex] === index) {
  185. activeButtonIndex = buttonIndex;
  186. break;
  187. }
  188. }
  189. // 如果找到激活按钮且未被锁定,则应用激活效果
  190. if (activeButtonIndex !== -1 && !this.buttonLockStates[activeButtonIndex]) {
  191. const activeBtn = this.buttons[activeButtonIndex];
  192. if (activeBtn && this.buttonOriginalPositions[activeButtonIndex]) {
  193. // 向上移动20px
  194. const newPos = this.buttonOriginalPositions[activeButtonIndex].clone();
  195. newPos.y += 20;
  196. activeBtn.position = newPos;
  197. // 显示对应的边框
  198. if (this.buttonBorders[activeButtonIndex]) {
  199. this.buttonBorders[activeButtonIndex].active = true;
  200. }
  201. this.currentActiveButtonIndex = activeButtonIndex;
  202. }
  203. } else {
  204. this.currentActiveButtonIndex = -1;
  205. }
  206. }
  207. /**
  208. * 更新按钮状态,主要用于设置锁定按钮的视觉效果
  209. */
  210. private updateButtonStates() {
  211. this.buttons.forEach((btn, buttonIndex) => {
  212. const sp = btn.getComponent(Sprite);
  213. if (sp) {
  214. if (this.buttonLockStates[buttonIndex]) {
  215. sp.color = this.lockedColor; // 设置锁定按钮为锁定颜色
  216. // 确保锁定的按钮在原始位置
  217. if (this.buttonOriginalPositions[buttonIndex]) {
  218. btn.position = this.buttonOriginalPositions[buttonIndex].clone();
  219. }
  220. // 隐藏锁定按钮的边框
  221. if (this.buttonBorders[buttonIndex]) {
  222. this.buttonBorders[buttonIndex].active = false;
  223. }
  224. } else {
  225. sp.color = this.normalColor; // 设置未锁定按钮为正常颜色
  226. }
  227. }
  228. });
  229. }
  230. /**
  231. * 解锁指定按钮
  232. * @param buttonIndex 按钮索引 (0:Battle, 1:Shop, 2:Upgrade, 3:Skill)
  233. */
  234. public unlockButton(buttonIndex: number) {
  235. if (buttonIndex >= 0 && buttonIndex < this.buttonLockStates.length) {
  236. this.buttonLockStates[buttonIndex] = false;
  237. this.updateButtonStates();
  238. const buttonNames = ['Battle', 'Shop', 'Upgrade', 'Skill'];
  239. console.log(`[NavBarController] ${buttonNames[buttonIndex]}按钮已解锁`);
  240. }
  241. }
  242. /**
  243. * 锁定指定按钮
  244. * @param buttonIndex 按钮索引 (0:Battle, 1:Shop, 2:Upgrade, 3:Skill)
  245. */
  246. public lockButton(buttonIndex: number) {
  247. if (buttonIndex >= 0 && buttonIndex < this.buttonLockStates.length) {
  248. this.buttonLockStates[buttonIndex] = true;
  249. this.updateButtonStates();
  250. const buttonNames = ['Battle', 'Shop', 'Upgrade', 'Skill'];
  251. console.log(`[NavBarController] ${buttonNames[buttonIndex]}按钮已锁定`);
  252. }
  253. }
  254. /**
  255. * 检查指定按钮是否被锁定
  256. * @param buttonIndex 按钮索引 (0:Battle, 1:Shop, 2:Upgrade, 3:Skill)
  257. */
  258. public isButtonLocked(buttonIndex: number): boolean {
  259. if (buttonIndex >= 0 && buttonIndex < this.buttonLockStates.length) {
  260. return this.buttonLockStates[buttonIndex];
  261. }
  262. return false;
  263. }
  264. /**
  265. * 批量设置按钮锁定状态
  266. * @param lockStates 锁定状态数组 [Battle, Shop, Upgrade, Skill]
  267. */
  268. public setButtonLockStates(lockStates: boolean[]) {
  269. if (lockStates.length === 4) {
  270. this.buttonLockStates = [...lockStates];
  271. this.updateButtonStates();
  272. console.log('[NavBarController] 按钮锁定状态已更新:', lockStates);
  273. }
  274. }
  275. /**
  276. * 获取当前所有按钮的锁定状态
  277. */
  278. public getButtonLockStates(): boolean[] {
  279. return [...this.buttonLockStates];
  280. }
  281. /**
  282. * 获取当前激活的按钮索引
  283. */
  284. public getCurrentActiveButtonIndex(): number {
  285. return this.currentActiveButtonIndex;
  286. }
  287. }