NavBarController.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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. if (index === 0) {
  156. console.log('[NavBarController] 切换到主界面,播放背景音乐');
  157. Audio.playMusic('data/弹球音效/ui bgm', true);
  158. }
  159. // 按钮索引到面板索引的映射:根据实际的点击事件调用
  160. // 按钮索引: [0:Battle, 1:Shop, 2:Upgrade, 3:Skill]
  161. // 面板索引: [0:Main, 1:Shop, 2:Upgrade, 3:Skill]
  162. // 实际映射: Battle->Main(0), Shop->Upgrade(2), Upgrade->Shop(1), Skill->Skill(3)
  163. const buttonToPanelMap = [0, 2, 1, 3]; // Battle->Main(0), Shop->Upgrade(2), Upgrade->Shop(1), Skill->Skill(3)
  164. // 重置所有按钮到原始位置和状态
  165. this.buttons.forEach((btn, buttonIndex) => {
  166. const sp = btn.getComponent(Sprite);
  167. if (sp) {
  168. // 重置按钮位置到原始位置
  169. if (this.buttonOriginalPositions[buttonIndex]) {
  170. btn.position = this.buttonOriginalPositions[buttonIndex].clone();
  171. }
  172. // 设置按钮颜色(只处理锁定状态)
  173. if (this.buttonLockStates[buttonIndex]) {
  174. sp.color = this.lockedColor; // 锁定状态显示灰色
  175. } else {
  176. sp.color = this.normalColor; // 正常状态显示白色
  177. }
  178. }
  179. });
  180. // 隐藏所有边框
  181. this.buttonBorders.forEach(border => {
  182. if (border) {
  183. border.active = false;
  184. }
  185. });
  186. // 找到当前激活的按钮索引
  187. let activeButtonIndex = -1;
  188. for (let buttonIndex = 0; buttonIndex < buttonToPanelMap.length; buttonIndex++) {
  189. if (buttonToPanelMap[buttonIndex] === index) {
  190. activeButtonIndex = buttonIndex;
  191. break;
  192. }
  193. }
  194. // 如果找到激活按钮且未被锁定,则应用激活效果
  195. if (activeButtonIndex !== -1 && !this.buttonLockStates[activeButtonIndex]) {
  196. const activeBtn = this.buttons[activeButtonIndex];
  197. if (activeBtn && this.buttonOriginalPositions[activeButtonIndex]) {
  198. // 向上移动20px
  199. const newPos = this.buttonOriginalPositions[activeButtonIndex].clone();
  200. newPos.y += 20;
  201. activeBtn.position = newPos;
  202. // 显示对应的边框
  203. if (this.buttonBorders[activeButtonIndex]) {
  204. this.buttonBorders[activeButtonIndex].active = true;
  205. }
  206. this.currentActiveButtonIndex = activeButtonIndex;
  207. }
  208. } else {
  209. this.currentActiveButtonIndex = -1;
  210. }
  211. // 通知MenuController更新菜单按钮状态
  212. const eventBus = EventBus.getInstance();
  213. eventBus.emit(GameEvents.UI_PANEL_SWITCHED, { panelIndex: index });
  214. }
  215. /**
  216. * 更新按钮状态,主要用于设置锁定按钮的视觉效果
  217. */
  218. private updateButtonStates() {
  219. this.buttons.forEach((btn, buttonIndex) => {
  220. const sp = btn.getComponent(Sprite);
  221. if (sp) {
  222. if (this.buttonLockStates[buttonIndex]) {
  223. sp.color = this.lockedColor; // 设置锁定按钮为锁定颜色
  224. // 确保锁定的按钮在原始位置
  225. if (this.buttonOriginalPositions[buttonIndex]) {
  226. btn.position = this.buttonOriginalPositions[buttonIndex].clone();
  227. }
  228. // 隐藏锁定按钮的边框
  229. if (this.buttonBorders[buttonIndex]) {
  230. this.buttonBorders[buttonIndex].active = false;
  231. }
  232. } else {
  233. sp.color = this.normalColor; // 设置未锁定按钮为正常颜色
  234. }
  235. }
  236. });
  237. }
  238. /**
  239. * 解锁指定按钮
  240. * @param buttonIndex 按钮索引 (0:Battle, 1:Shop, 2:Upgrade, 3:Skill)
  241. */
  242. public unlockButton(buttonIndex: number) {
  243. if (buttonIndex >= 0 && buttonIndex < this.buttonLockStates.length) {
  244. this.buttonLockStates[buttonIndex] = false;
  245. this.updateButtonStates();
  246. const buttonNames = ['Battle', 'Shop', 'Upgrade', 'Skill'];
  247. console.log(`[NavBarController] ${buttonNames[buttonIndex]}按钮已解锁`);
  248. }
  249. }
  250. /**
  251. * 锁定指定按钮
  252. * @param buttonIndex 按钮索引 (0:Battle, 1:Shop, 2:Upgrade, 3:Skill)
  253. */
  254. public lockButton(buttonIndex: number) {
  255. if (buttonIndex >= 0 && buttonIndex < this.buttonLockStates.length) {
  256. this.buttonLockStates[buttonIndex] = true;
  257. this.updateButtonStates();
  258. const buttonNames = ['Battle', 'Shop', 'Upgrade', 'Skill'];
  259. console.log(`[NavBarController] ${buttonNames[buttonIndex]}按钮已锁定`);
  260. }
  261. }
  262. /**
  263. * 检查指定按钮是否被锁定
  264. * @param buttonIndex 按钮索引 (0:Battle, 1:Shop, 2:Upgrade, 3:Skill)
  265. */
  266. public isButtonLocked(buttonIndex: number): boolean {
  267. if (buttonIndex >= 0 && buttonIndex < this.buttonLockStates.length) {
  268. return this.buttonLockStates[buttonIndex];
  269. }
  270. return false;
  271. }
  272. /**
  273. * 批量设置按钮锁定状态
  274. * @param lockStates 锁定状态数组 [Battle, Shop, Upgrade, Skill]
  275. */
  276. public setButtonLockStates(lockStates: boolean[]) {
  277. if (lockStates.length === 4) {
  278. this.buttonLockStates = [...lockStates];
  279. this.updateButtonStates();
  280. console.log('[NavBarController] 按钮锁定状态已更新:', lockStates);
  281. }
  282. }
  283. /**
  284. * 获取当前所有按钮的锁定状态
  285. */
  286. public getButtonLockStates(): boolean[] {
  287. return [...this.buttonLockStates];
  288. }
  289. /**
  290. * 获取当前激活的按钮索引
  291. */
  292. public getCurrentActiveButtonIndex(): number {
  293. return this.currentActiveButtonIndex;
  294. }
  295. }