NavBarController.ts 12 KB

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