UpgradeController.ts 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. import { _decorator, Component, Node, Button, Label, Sprite, SpriteFrame, Texture2D, resources, ScrollView, Layout, Prefab, instantiate, find, UIOpacity, Color } from 'cc';
  2. import { SaveDataManager, WeaponData } from '../../LevelSystem/SaveDataManager';
  3. import { TopBarController } from '../TopBarController';
  4. import EventBus, { GameEvents } from '../../Core/EventBus';
  5. import { UpgradeAni } from './UpgradeAni';
  6. const { ccclass, property } = _decorator;
  7. /**
  8. * 武器配置接口(从weapons.json加载)
  9. */
  10. interface WeaponConfig {
  11. id: string;
  12. name: string;
  13. type: string;
  14. rarity: string;
  15. weight: number;
  16. stats: {
  17. damage: number;
  18. fireRate: number;
  19. range: number;
  20. bulletSpeed: number;
  21. };
  22. visualConfig: {
  23. weaponSprites: {
  24. "I": string;
  25. "H-I": string;
  26. "L": string;
  27. "S": string;
  28. "D-T": string;
  29. };
  30. };
  31. }
  32. /**
  33. * 武器升级系统控制器
  34. * 负责管理武器升级UI和逻辑
  35. */
  36. @ccclass('UpgradeController')
  37. export class UpgradeController extends Component {
  38. // UI节点引用
  39. @property(Node) upgradeUI: Node = null; // Canvas/UpgradeUI
  40. @property(ScrollView) weaponScrollView: ScrollView = null; // Canvas/UpgradeUI/ScrollView
  41. @property(Layout) weaponLayout: Layout = null; // Canvas/UpgradeUI/ScrollView/view/content/Layout
  42. @property(Node) upgradePanel: Node = null; // Canvas/UpgradeUI/UpgradePanel
  43. @property(Button) closePanelBtn: Button = null; // Canvas/UpgradeUI/UpgradePanel/CloseBtn
  44. // 升级面板UI组件
  45. @property(Sprite) panelWeaponSprite: Sprite = null; // Canvas/UpgradeUI/UpgradePanel/WeaponSprite
  46. @property(Label) panelLevelLabel: Label = null; // Canvas/UpgradeUI/UpgradePanel/LevelLabel
  47. @property(Label) panelCurrentDamage: Label = null; // Canvas/UpgradeUI/UpgradePanel/NumberBack/CurrentDamage
  48. @property(Label) panelCostLabel: Label = null; // Canvas/UpgradeUI/UpgradePanel/UpgradeBtn/CostLabel
  49. @property(Button) panelUpgradeBtn: Button = null; // Canvas/UpgradeUI/UpgradePanel/UpgradeBtn
  50. // 武器节点预制体
  51. @property(Prefab) weaponNodePrefab: Prefab = null;
  52. @property(Prefab) lockedWeaponPrefab: Prefab = null; // Lock.prefab
  53. @property(Prefab) unlockedWeaponPrefab: Prefab = null; // Unlock.prefab
  54. // 动画控制器
  55. @property(UpgradeAni) upgradeAni: UpgradeAni = null; // Canvas/UpgradeUI/UpgradePanel上的UpgradeAni组件
  56. // 数据管理
  57. private saveDataManager: SaveDataManager = null;
  58. private weaponsConfig: { weapons: WeaponConfig[] } = null;
  59. private currentSelectedWeapon: string = null;
  60. private levelConfigs: any[] = [];
  61. // 武器节点列表
  62. private weaponNodes: Node[] = [];
  63. onLoad() {
  64. this.saveDataManager = SaveDataManager.getInstance();
  65. this.bindEvents();
  66. }
  67. async start() {
  68. // 先加载武器配置
  69. await this.loadWeaponsConfig();
  70. // 加载关卡配置
  71. await this.loadLevelConfigs();
  72. // 初始化武器数据
  73. this.initializeWeapons();
  74. // 初始化时检查武器解锁状态
  75. this.checkInitialWeaponUnlocks();
  76. // 刷新UI
  77. this.refreshWeaponList();
  78. // 初始化升级面板状态
  79. if (this.upgradeAni) {
  80. this.upgradeAni.hidePanelImmediate();
  81. } else {
  82. this.upgradePanel.active = false;
  83. }
  84. console.log('[UpgradeController] 初始化完成');
  85. }
  86. /**
  87. * 绑定事件
  88. */
  89. private bindEvents() {
  90. // 关闭升级面板
  91. this.closePanelBtn?.node.on(Button.EventType.CLICK, this.closeUpgradePanel, this);
  92. // 升级按钮
  93. this.panelUpgradeBtn?.node.on(Button.EventType.CLICK, this.onUpgradeWeapon, this);
  94. // 监听关卡完成事件,自动解锁武器
  95. EventBus.getInstance().on(GameEvents.GAME_SUCCESS, this.onLevelComplete, this);
  96. }
  97. /**
  98. * 加载武器配置
  99. */
  100. private async loadWeaponsConfig() {
  101. try {
  102. const jsonAsset = await new Promise<any>((resolve, reject) => {
  103. resources.load('data/weapons', (err, asset) => {
  104. if (err) reject(err);
  105. else resolve(asset);
  106. });
  107. });
  108. this.weaponsConfig = jsonAsset.json;
  109. console.log('[UpgradeController] 武器配置加载成功:', this.weaponsConfig);
  110. } catch (error) {
  111. console.error('[UpgradeController] 加载武器配置失败:', error);
  112. }
  113. }
  114. /**
  115. * 加载关卡配置
  116. */
  117. private async loadLevelConfigs() {
  118. try {
  119. this.levelConfigs = [];
  120. // 加载Level1到Level5的配置
  121. for (let i = 1; i <= 5; i++) {
  122. try {
  123. const levelData = await new Promise<any>((resolve, reject) => {
  124. resources.load(`data/levels/Level${i}`, (err, asset) => {
  125. if (err) reject(err);
  126. else resolve(asset);
  127. });
  128. });
  129. this.levelConfigs.push({
  130. level: i,
  131. ...levelData
  132. });
  133. } catch (error) {
  134. console.warn(`加载Level${i}配置失败:`, error);
  135. }
  136. }
  137. console.log('关卡配置加载成功:', this.levelConfigs);
  138. } catch (error) {
  139. console.error('加载关卡配置失败:', error);
  140. this.levelConfigs = [];
  141. }
  142. }
  143. /**
  144. * 初始化武器数据(确保所有武器都在存档中)
  145. */
  146. private initializeWeapons() {
  147. if (!this.weaponsConfig) return;
  148. // 为每个武器创建初始数据(如果不存在)
  149. this.weaponsConfig.weapons.forEach(weaponConfig => {
  150. const existingWeapon = this.saveDataManager.getWeapon(weaponConfig.id);
  151. if (!existingWeapon) {
  152. this.saveDataManager.addWeapon(weaponConfig.id, weaponConfig.rarity);
  153. }
  154. });
  155. }
  156. /**
  157. * 初始化时检查武器解锁状态
  158. */
  159. private checkInitialWeaponUnlocks() {
  160. if (!this.saveDataManager || !this.weaponsConfig) return;
  161. const maxUnlockedLevel = this.saveDataManager.getMaxUnlockedLevel();
  162. console.log(`[UpgradeController] 初始化检查武器解锁状态,当前最大解锁关卡: ${maxUnlockedLevel}`);
  163. let hasUpdates = false;
  164. for (const weaponConfig of this.weaponsConfig.weapons) {
  165. const weaponId = weaponConfig.id;
  166. const weaponData = this.saveDataManager.getWeapon(weaponId);
  167. const requiredLevel = this.getWeaponUnlockLevelById(weaponId);
  168. // 检查武器是否应该根据关卡进度解锁
  169. const shouldBeUnlocked = maxUnlockedLevel >= requiredLevel;
  170. const isCurrentlyUnlocked = weaponData && weaponData.level > 0;
  171. // 如果武器应该解锁但还未解锁,则自动解锁
  172. if (shouldBeUnlocked && !isCurrentlyUnlocked && weaponData) {
  173. weaponData.level = 1;
  174. // 由于WeaponData类型中没有unlockTime属性,这里先注释掉
  175. // weaponData.unlockTime = weaponData.unlockTime || Date.now();
  176. console.log(`[UpgradeController] 初始化时自动解锁武器: ${weaponConfig.name} (${weaponId})`);
  177. hasUpdates = true;
  178. }
  179. }
  180. // 如果有更新,保存数据
  181. if (hasUpdates) {
  182. this.saveDataManager.savePlayerData();
  183. console.log(`[UpgradeController] 初始化武器解锁状态更新完成`);
  184. }
  185. }
  186. /**
  187. * 刷新武器列表UI
  188. */
  189. private refreshWeaponList() {
  190. if (!this.weaponsConfig || !this.weaponLayout) {
  191. console.warn('武器配置或武器布局未初始化');
  192. return;
  193. }
  194. // 清除现有节点
  195. this.clearWeaponNodes();
  196. // 为每个武器创建UI节点
  197. this.weaponsConfig.weapons.forEach((weaponConfig, index) => {
  198. this.createWeaponNode(weaponConfig, index);
  199. });
  200. }
  201. /**
  202. * 切换武器节点状态(从锁定到解锁或反之)
  203. */
  204. private switchWeaponNodeState(weaponId: string) {
  205. const weaponConfig = this.weaponsConfig.weapons.find(w => w.id === weaponId);
  206. if (!weaponConfig) {
  207. console.warn(`未找到武器配置: ${weaponId}`);
  208. return;
  209. }
  210. // 找到对应的武器节点
  211. const weaponNodeIndex = this.weaponNodes.findIndex(node => node.name === `WeaponNode_${weaponId}`);
  212. if (weaponNodeIndex === -1) {
  213. console.warn(`未找到武器节点: ${weaponId}`);
  214. return;
  215. }
  216. const oldNode = this.weaponNodes[weaponNodeIndex];
  217. const isUnlocked = this.saveDataManager.isWeaponUnlocked(weaponId);
  218. const weaponData = this.saveDataManager.getWeapon(weaponId);
  219. // 创建新节点
  220. let newNode: Node = null;
  221. if (isUnlocked) {
  222. if (this.unlockedWeaponPrefab) {
  223. newNode = instantiate(this.unlockedWeaponPrefab);
  224. this.setupUnlockedWeaponNode(newNode, weaponConfig, weaponData);
  225. }
  226. } else {
  227. if (this.lockedWeaponPrefab) {
  228. newNode = instantiate(this.lockedWeaponPrefab);
  229. this.setupLockedWeaponNode(newNode, weaponConfig);
  230. }
  231. }
  232. if (newNode) {
  233. newNode.name = `WeaponNode_${weaponId}`;
  234. // 获取旧节点的位置
  235. const siblingIndex = oldNode.getSiblingIndex();
  236. // 移除旧节点
  237. oldNode.removeFromParent();
  238. // 添加新节点到相同位置
  239. this.weaponLayout.node.insertChild(newNode, siblingIndex);
  240. // 更新节点数组
  241. this.weaponNodes[weaponNodeIndex] = newNode;
  242. console.log(`武器 ${weaponId} 状态切换完成: ${isUnlocked ? '解锁' : '锁定'}`);
  243. }
  244. }
  245. /**
  246. * 清除武器节点
  247. */
  248. private clearWeaponNodes() {
  249. this.weaponNodes.forEach(node => {
  250. if (node && node.isValid) {
  251. node.destroy();
  252. }
  253. });
  254. this.weaponNodes = [];
  255. }
  256. /**
  257. * 创建武器节点
  258. */
  259. private createWeaponNode(weaponConfig: WeaponConfig, index: number) {
  260. // 获取武器数据
  261. const weaponData = this.saveDataManager.getWeapon(weaponConfig.id);
  262. const isUnlocked = this.saveDataManager.isWeaponUnlocked(weaponConfig.id);
  263. console.log(`设置武器节点 ${index}: ${weaponConfig.name}, 等级: ${weaponData?.level || 0}, 已解锁: ${isUnlocked}`);
  264. // 根据解锁状态选择合适的预制体
  265. let weaponNode: Node = null;
  266. if (isUnlocked) {
  267. if (this.unlockedWeaponPrefab) {
  268. weaponNode = instantiate(this.unlockedWeaponPrefab);
  269. this.setupUnlockedWeaponNode(weaponNode, weaponConfig, weaponData);
  270. } else if (this.weaponNodePrefab) {
  271. weaponNode = instantiate(this.weaponNodePrefab);
  272. this.convertToUnlockedNode(weaponNode, weaponConfig, weaponData, index);
  273. }
  274. } else {
  275. if (this.lockedWeaponPrefab) {
  276. weaponNode = instantiate(this.lockedWeaponPrefab);
  277. this.setupLockedWeaponNode(weaponNode, weaponConfig);
  278. } else if (this.weaponNodePrefab) {
  279. weaponNode = instantiate(this.weaponNodePrefab);
  280. this.convertToLockedNode(weaponNode, weaponConfig, index);
  281. }
  282. }
  283. // 如果没有任何预制体,创建基本节点
  284. if (!weaponNode) {
  285. weaponNode = new Node(`WeaponNode_${index}`);
  286. weaponNode.addComponent(UIOpacity);
  287. if (isUnlocked) {
  288. this.convertToUnlockedNode(weaponNode, weaponConfig, weaponData, index);
  289. } else {
  290. this.convertToLockedNode(weaponNode, weaponConfig, index);
  291. }
  292. }
  293. // 设置节点名称
  294. weaponNode.name = `WeaponNode_${weaponConfig.id}`;
  295. // 添加到布局中
  296. this.weaponLayout.node.addChild(weaponNode);
  297. this.weaponNodes.push(weaponNode);
  298. }
  299. /**
  300. * 加载武器图标
  301. */
  302. private loadWeaponSprite(sprite: Sprite, spritePath: string) {
  303. // 参考WeaponBullet.ts的正确加载方式,在路径后添加'/spriteFrame'
  304. const framePath = `${spritePath}/spriteFrame`;
  305. resources.load(framePath, SpriteFrame, (err, spriteFrame) => {
  306. if (!err && spriteFrame && sprite && sprite.isValid) {
  307. sprite.spriteFrame = spriteFrame;
  308. console.log(`武器图标加载成功: ${spritePath}`);
  309. } else if (err) {
  310. console.warn(`加载武器图标失败: ${spritePath}`, err);
  311. }
  312. });
  313. }
  314. /**
  315. * 设置已解锁武器节点(适配Unlock.prefab)
  316. */
  317. private setupUnlockedWeaponNode(weaponNode: Node, weaponConfig: WeaponConfig, weaponData: any) {
  318. // 获取公共的Sprite节点,避免重复查找
  319. const spriteNode = weaponNode.getChildByName('Sprite');
  320. if (!spriteNode) {
  321. console.warn('未找到Sprite节点:', weaponConfig.id);
  322. return;
  323. }
  324. // 设置武器图标 - 查找专门的武器图标Sprite节点,避免影响背景
  325. const weaponSprite = spriteNode.getChildByName('WeaponSprite')?.getComponent(Sprite);
  326. if (weaponSprite && weaponConfig.visualConfig.weaponSprites) {
  327. const spritePath = weaponConfig.visualConfig.weaponSprites['I'] || weaponConfig.visualConfig.weaponSprites['H-I'] || weaponConfig.visualConfig.weaponSprites['L'] || weaponConfig.visualConfig.weaponSprites['S'] || weaponConfig.visualConfig.weaponSprites['D-T'];
  328. this.loadWeaponSprite(weaponSprite, spritePath);
  329. }
  330. // 设置武器名称 - Unlock.prefab中的Name节点下的Label
  331. const nameLabel = spriteNode.getChildByName('Name')?.getComponent(Label);
  332. if (nameLabel) {
  333. nameLabel.string = `${weaponConfig.name} Lv.${weaponData ? weaponData.level : 0}`;
  334. }
  335. // 设置升级按钮 - Unlock.prefab中的Button节点
  336. const upgradeButton = weaponNode.getChildByName('Upgrade')?.getComponent(Button);
  337. if (upgradeButton) {
  338. // 清除之前的事件监听
  339. upgradeButton.node.off(Button.EventType.CLICK);
  340. // 添加升级事件
  341. upgradeButton.node.on(Button.EventType.CLICK, () => {
  342. this.openUpgradePanel(weaponConfig.id);
  343. }, this);
  344. // 设置按钮文本和状态
  345. const buttonLabel = upgradeButton.node.getChildByName('Label')?.getComponent(Label);
  346. if (buttonLabel) {
  347. const cost = this.saveDataManager.getWeaponUpgradeCost(weaponConfig.id);
  348. const maxLevel = 10; // 假设最大等级为10
  349. if (weaponData && weaponData.level >= maxLevel) {
  350. buttonLabel.string = '已满级';
  351. upgradeButton.interactable = false;
  352. } else {
  353. buttonLabel.string = `升级 (${cost}金币)`;
  354. upgradeButton.interactable = true;
  355. }
  356. }
  357. }
  358. // Unlock.prefab已经有正常的视觉效果,确保节点激活
  359. weaponNode.active = true;
  360. }
  361. /**
  362. * 设置未解锁武器节点(适配Lock.prefab)
  363. */
  364. private setupLockedWeaponNode(weaponNode: Node, weaponConfig: WeaponConfig) {
  365. // 设置解锁信息文本 - Lock.prefab中的Label节点
  366. const unlockLabel = weaponNode.getChildByName('Label')?.getComponent(Label);
  367. if (unlockLabel) {
  368. const unlockLevel = this.getWeaponUnlockLevel(weaponConfig.name);
  369. unlockLabel.string = `通关第${unlockLevel}关解锁`;
  370. }
  371. // Lock.prefab已经有合适的视觉效果,不需要额外设置透明度
  372. weaponNode.active = true;
  373. // 禁用点击事件(如果有Button组件)
  374. const button = weaponNode.getComponent(Button);
  375. if (button) {
  376. button.interactable = false;
  377. }
  378. // 添加点击事件监听(显示解锁提示)
  379. weaponNode.on(Node.EventType.TOUCH_END, () => {
  380. const unlockLevel = this.getWeaponUnlockLevel(weaponConfig.name);
  381. console.log(`${weaponConfig.name} 需要通关第${unlockLevel}关才能解锁`);
  382. }, this);
  383. }
  384. /**
  385. * 转换为锁定节点
  386. */
  387. private convertToLockedNode(weaponNode: Node, weaponConfig: WeaponConfig, index: number) {
  388. // 隐藏正常武器节点的所有子节点
  389. const spriteNode = weaponNode.getChildByName('WeaponIcon') ||
  390. weaponNode.getChildByName('Icon') ||
  391. weaponNode.getChildByName('WeaponSprite') ||
  392. weaponNode.getChildByName('Sprite');
  393. if (spriteNode) {
  394. spriteNode.active = false;
  395. }
  396. const upgradeBtn = weaponNode.getChildByName('Upgrade');
  397. if (upgradeBtn) {
  398. upgradeBtn.active = false;
  399. }
  400. // 创建或显示锁定状态的Label
  401. let lockLabel = weaponNode.getChildByName('LockLabel');
  402. if (!lockLabel) {
  403. lockLabel = new Node('LockLabel');
  404. const labelComp = lockLabel.addComponent(Label);
  405. labelComp.fontSize = 24;
  406. labelComp.color = Color.WHITE;
  407. weaponNode.addChild(lockLabel);
  408. }
  409. const labelComp = lockLabel.getComponent(Label);
  410. if (labelComp) {
  411. const unlockLevel = this.getWeaponUnlockLevel(weaponConfig.name);
  412. labelComp.string = `通关第${unlockLevel}关解锁`;
  413. }
  414. lockLabel.active = true;
  415. // 设置节点为锁定状态
  416. let uiOpacity = weaponNode.getComponent(UIOpacity);
  417. if (!uiOpacity) {
  418. uiOpacity = weaponNode.addComponent(UIOpacity);
  419. }
  420. uiOpacity.opacity = 180;
  421. weaponNode.active = true;
  422. // 禁用点击事件
  423. const button = weaponNode.getComponent(Button);
  424. if (button) {
  425. button.interactable = false;
  426. }
  427. }
  428. /**
  429. * 转换为解锁节点
  430. */
  431. private convertToUnlockedNode(weaponNode: Node, weaponConfig: WeaponConfig, weaponData: any, index: number) {
  432. // 隐藏锁定状态的Label
  433. const lockLabel = weaponNode.getChildByName('LockLabel');
  434. if (lockLabel) {
  435. lockLabel.active = false;
  436. }
  437. // 显示正常武器节点的所有子节点
  438. const spriteNode = weaponNode.getChildByName('WeaponIcon') ||
  439. weaponNode.getChildByName('Icon') ||
  440. weaponNode.getChildByName('WeaponSprite') ||
  441. weaponNode.getChildByName('Sprite');
  442. if (spriteNode) {
  443. spriteNode.active = true;
  444. }
  445. const upgradeBtn = weaponNode.getChildByName('Upgrade');
  446. if (upgradeBtn) {
  447. upgradeBtn.active = true;
  448. }
  449. // 设置为解锁状态
  450. this.setupUnlockedWeaponNode(weaponNode, weaponConfig, weaponData);
  451. }
  452. /**
  453. * 打开升级面板
  454. */
  455. private async openUpgradePanel(weaponId: string) {
  456. const weaponConfig = this.weaponsConfig.weapons.find(config => config.id === weaponId);
  457. if (!weaponConfig) {
  458. console.error(`未找到武器配置: ${weaponId}`);
  459. return;
  460. }
  461. const weaponData = this.saveDataManager.getWeapon(weaponId);
  462. if (!weaponData) {
  463. console.error(`未找到武器数据: ${weaponId}`);
  464. return;
  465. }
  466. this.currentSelectedWeapon = weaponId;
  467. console.log(`打开升级面板: ${weaponConfig.name}, 当前等级: ${weaponData.level}`);
  468. // 刷新面板内容
  469. this.refreshUpgradePanel();
  470. // 使用动画显示升级面板
  471. if (this.upgradeAni) {
  472. await this.upgradeAni.showPanel();
  473. } else {
  474. // 如果没有动画组件,直接显示
  475. this.upgradePanel.active = true;
  476. }
  477. }
  478. /**
  479. * 关闭升级面板
  480. */
  481. private async closeUpgradePanel() {
  482. // 使用动画隐藏升级面板
  483. if (this.upgradeAni) {
  484. await this.upgradeAni.hidePanel();
  485. } else {
  486. // 如果没有动画组件,直接隐藏
  487. this.upgradePanel.active = false;
  488. }
  489. this.currentSelectedWeapon = null;
  490. }
  491. /**
  492. * 刷新升级面板
  493. */
  494. private refreshUpgradePanel() {
  495. if (!this.currentSelectedWeapon || !this.weaponsConfig) return;
  496. const weaponConfig = this.weaponsConfig.weapons.find(w => w.id === this.currentSelectedWeapon);
  497. const weaponData = this.saveDataManager.getWeapon(this.currentSelectedWeapon);
  498. if (!weaponConfig || !weaponData) {
  499. console.error(`刷新升级面板失败: 武器配置或数据不存在 ${this.currentSelectedWeapon}`);
  500. return;
  501. }
  502. console.log(`刷新升级面板: ${weaponConfig.name}, 等级: ${weaponData.level}`);
  503. // 设置武器图标 - Canvas/UpgradeUI/UpgradePanel/WeaponSprite
  504. if (this.panelWeaponSprite && weaponConfig.visualConfig.weaponSprites) {
  505. const spritePath = weaponConfig.visualConfig.weaponSprites['I'] || weaponConfig.visualConfig.weaponSprites['H-I'] || weaponConfig.visualConfig.weaponSprites['L'] || weaponConfig.visualConfig.weaponSprites['S'] || weaponConfig.visualConfig.weaponSprites['D-T'];
  506. this.loadWeaponSprite(this.panelWeaponSprite, spritePath);
  507. }
  508. // 设置武器名称和等级 - Canvas/UpgradeUI/UpgradePanel/LevelLabel
  509. if (this.panelLevelLabel) {
  510. this.panelLevelLabel.string = `${weaponConfig.name} 等级 ${weaponData.level}`;
  511. }
  512. // 计算当前伤害(基础伤害 + 等级加成)- Canvas/UpgradeUI/UpgradePanel/NumberBack/CurrentDamage
  513. const baseDamage = weaponConfig.stats.damage;
  514. const currentDamage = this.calculateWeaponDamage(baseDamage, weaponData.level);
  515. if (this.panelCurrentDamage) {
  516. this.panelCurrentDamage.string = currentDamage.toString();
  517. }
  518. // 设置升级费用 - Canvas/UpgradeUI/UpgradePanel/UpgradeBtn/CostLabel
  519. const upgradeCost = this.saveDataManager.getWeaponUpgradeCost(this.currentSelectedWeapon);
  520. if (this.panelCostLabel) {
  521. this.panelCostLabel.string = upgradeCost.toString();
  522. }
  523. // 设置升级按钮状态 - Canvas/UpgradeUI/UpgradePanel/UpgradeBtn
  524. if (this.panelUpgradeBtn) {
  525. const canUpgrade = this.saveDataManager.canUpgradeWeapon(this.currentSelectedWeapon);
  526. this.panelUpgradeBtn.interactable = canUpgrade;
  527. // 检查金币是否足够
  528. const playerData = this.saveDataManager.getPlayerData();
  529. const cost = this.saveDataManager.getWeaponUpgradeCost(this.currentSelectedWeapon);
  530. if (playerData.coins < cost) {
  531. console.log(`金币不足进行升级: 需要 ${cost}, 当前 ${playerData.coins}`);
  532. }
  533. }
  534. }
  535. /**
  536. * 计算武器伤害
  537. */
  538. private calculateWeaponDamage(baseDamage: number, level: number): number {
  539. if (level === 0) return 0; // 未解锁武器伤害为0
  540. // 每级增加10%基础伤害
  541. const damageMultiplier = 1 + (level - 1) * 0.1;
  542. return Math.floor(baseDamage * damageMultiplier);
  543. }
  544. /**
  545. * 根据武器名称查找解锁关卡
  546. */
  547. private getWeaponUnlockLevel(weaponName: string): number {
  548. // 武器名称到解锁关卡的映射
  549. const weaponUnlockMap: { [key: string]: number } = {
  550. "毛豆射手": 1,
  551. "尖胡萝卜": 2,
  552. "锯齿草": 3,
  553. "西瓜炸弹": 4,
  554. "回旋镖盆栽": 5,
  555. "炙热辣椒": 6,
  556. "仙人散弹": 7,
  557. "秋葵导弹": 8,
  558. "狼牙棒": 9
  559. };
  560. return weaponUnlockMap[weaponName] || 1;
  561. }
  562. /**
  563. * 根据武器ID查找解锁关卡
  564. */
  565. private getWeaponUnlockLevelById(weaponId: string): number {
  566. // 武器ID到解锁关卡的映射
  567. const weaponUnlockMap: { [key: string]: number } = {
  568. "pea_shooter": 1,
  569. "sharp_carrot": 2,
  570. "saw_grass": 3,
  571. "watermelon_bomb": 4,
  572. "boomerang_plant": 5,
  573. "hot_pepper": 6,
  574. "cactus_shotgun": 7,
  575. "okra_missile": 8,
  576. "mace_club": 9
  577. };
  578. return weaponUnlockMap[weaponId] || 1;
  579. }
  580. /**
  581. * 升级武器
  582. */
  583. private onUpgradeWeapon() {
  584. if (!this.currentSelectedWeapon) return;
  585. const success = this.saveDataManager.upgradeWeapon(this.currentSelectedWeapon);
  586. if (success) {
  587. console.log(`武器 ${this.currentSelectedWeapon} 升级成功`);
  588. // 刷新升级面板
  589. this.refreshUpgradePanel();
  590. // 使用新的状态切换方法更新武器节点
  591. this.switchWeaponNodeState(this.currentSelectedWeapon);
  592. // 更新顶部金币显示
  593. TopBarController.updateTopBarUI();
  594. // 保存数据
  595. this.saveDataManager.savePlayerData();
  596. } else {
  597. console.log(`武器 ${this.currentSelectedWeapon} 升级失败`);
  598. }
  599. }
  600. /**
  601. * 解锁武器
  602. */
  603. public unlockWeapon(weaponId: string): boolean {
  604. const success = this.saveDataManager.unlockWeapon(weaponId);
  605. if (success) {
  606. console.log(`武器 ${weaponId} 解锁成功`);
  607. // 使用新的状态切换方法更新武器节点
  608. this.switchWeaponNodeState(weaponId);
  609. // 更新顶部金币显示
  610. TopBarController.updateTopBarUI();
  611. // 保存数据
  612. this.saveDataManager.savePlayerData();
  613. }
  614. return success;
  615. }
  616. /**
  617. * 获取武器当前伤害
  618. */
  619. public getWeaponDamage(weaponId: string): number {
  620. if (!this.weaponsConfig) return 0;
  621. const weaponConfig = this.weaponsConfig.weapons.find(w => w.id === weaponId);
  622. const weaponData = this.saveDataManager.getWeapon(weaponId);
  623. if (!weaponConfig || !weaponData) return 0;
  624. return this.calculateWeaponDamage(weaponConfig.stats.damage, weaponData.level);
  625. }
  626. /**
  627. * 刷新UI
  628. */
  629. public refreshUI() {
  630. this.refreshWeaponList();
  631. }
  632. /**
  633. * 处理关卡完成事件,自动解锁相应武器
  634. */
  635. private onLevelComplete() {
  636. if (!this.saveDataManager || !this.weaponsConfig) return;
  637. // 获取当前关卡数据
  638. const currentLevel = this.saveDataManager.getCurrentLevel();
  639. const maxUnlockedLevel = this.saveDataManager.getMaxUnlockedLevel();
  640. const playerData = this.saveDataManager.getPlayerData();
  641. console.log(`[UpgradeController] 关卡完成事件触发`);
  642. console.log(`[UpgradeController] 当前关卡: ${currentLevel}, 最大解锁关卡: ${maxUnlockedLevel}`);
  643. console.log(`[UpgradeController] 玩家数据:`, {
  644. coins: playerData?.coins || 0,
  645. currentLevel: playerData?.currentLevel || 1,
  646. maxUnlockedLevel: playerData?.maxUnlockedLevel || 1
  647. });
  648. // 遍历所有武器,检查是否有新解锁的武器
  649. let hasNewUnlocks = false;
  650. const newlyUnlockedWeapons: string[] = [];
  651. for (const weaponConfig of this.weaponsConfig.weapons) {
  652. const weaponId = weaponConfig.id;
  653. const weaponData = this.saveDataManager.getWeapon(weaponId);
  654. const requiredLevel = this.getWeaponUnlockLevelById(weaponId);
  655. // 检查武器是否应该根据关卡进度解锁
  656. const shouldBeUnlocked = maxUnlockedLevel >= requiredLevel;
  657. const isCurrentlyUnlocked = weaponData && weaponData.level > 0;
  658. console.log(`[UpgradeController] 武器检查: ${weaponConfig.name} (${weaponId})`);
  659. console.log(` - 需要关卡: ${requiredLevel}, 当前最大解锁: ${maxUnlockedLevel}`);
  660. console.log(` - 应该解锁: ${shouldBeUnlocked}, 当前已解锁: ${isCurrentlyUnlocked}`);
  661. console.log(` - 武器数据:`, weaponData);
  662. // 如果武器应该解锁但还未解锁,则自动解锁
  663. if (shouldBeUnlocked && !isCurrentlyUnlocked) {
  664. // 确保武器数据存在
  665. if (!weaponData) {
  666. this.saveDataManager.addWeapon(weaponId, weaponConfig.rarity);
  667. }
  668. // 自动解锁武器(设置为level 1,免费解锁)
  669. const updatedWeaponData = this.saveDataManager.getWeapon(weaponId);
  670. if (updatedWeaponData) {
  671. updatedWeaponData.level = 1;
  672. // 由于WeaponData类型中没有unlockTime属性,暂时注释掉这行
  673. // updatedWeaponData.unlockTime = Date.now();
  674. console.log(`[UpgradeController] 自动解锁武器: ${weaponConfig.name} (${weaponId})`);
  675. newlyUnlockedWeapons.push(weaponConfig.name);
  676. hasNewUnlocks = true;
  677. }
  678. }
  679. }
  680. // 如果有新解锁的武器,刷新UI并保存数据
  681. if (hasNewUnlocks) {
  682. this.refreshWeaponList();
  683. this.saveDataManager.savePlayerData();
  684. console.log(`[UpgradeController] 关卡完成后解锁了 ${newlyUnlockedWeapons.length} 个武器:`, newlyUnlockedWeapons);
  685. // 可以在这里添加解锁提示UI
  686. this.showWeaponUnlockNotification(newlyUnlockedWeapons);
  687. } else {
  688. console.log(`[UpgradeController] 关卡完成后没有新武器解锁`);
  689. }
  690. }
  691. /**
  692. * 显示武器解锁通知
  693. */
  694. private showWeaponUnlockNotification(weaponNames: string[]) {
  695. if (weaponNames.length === 0) return;
  696. // 这里可以实现解锁通知UI
  697. // 目前先用console输出
  698. console.log(`🎉 恭喜解锁新武器: ${weaponNames.join(', ')}!`);
  699. // TODO: 实现实际的UI通知
  700. // 可以显示一个弹窗或者顶部通知条
  701. }
  702. /**
  703. * 获取当前关卡数据(用于调试和UI显示)
  704. */
  705. public getCurrentLevelData() {
  706. if (!this.saveDataManager) return null;
  707. return {
  708. currentLevel: this.saveDataManager.getCurrentLevel(),
  709. maxUnlockedLevel: this.saveDataManager.getMaxUnlockedLevel(),
  710. coins: this.saveDataManager.getCoins(),
  711. diamonds: this.saveDataManager.getDiamonds(),
  712. gems: this.saveDataManager.getGems(),
  713. wallLevel: this.saveDataManager.getWallLevel()
  714. };
  715. }
  716. /**
  717. * 手动检查并解锁武器(用于调试或特殊情况)
  718. */
  719. public checkAndUnlockWeapons() {
  720. console.log('[UpgradeController] 手动检查武器解锁状态');
  721. this.onLevelComplete();
  722. }
  723. /**
  724. * 获取所有武器的解锁状态信息(用于调试和UI显示)
  725. */
  726. public getWeaponUnlockStatus() {
  727. if (!this.saveDataManager || !this.weaponsConfig) {
  728. return { error: '数据管理器或武器配置未初始化' };
  729. }
  730. const maxUnlockedLevel = this.saveDataManager.getMaxUnlockedLevel();
  731. const weaponStatus = [];
  732. for (const weaponConfig of this.weaponsConfig.weapons) {
  733. const weaponId = weaponConfig.id;
  734. const weaponData = this.saveDataManager.getWeapon(weaponId);
  735. const requiredLevel = this.getWeaponUnlockLevelById(weaponId);
  736. const shouldBeUnlocked = maxUnlockedLevel >= requiredLevel;
  737. const isCurrentlyUnlocked = weaponData && weaponData.level > 0;
  738. weaponStatus.push({
  739. id: weaponId,
  740. name: weaponConfig.name,
  741. requiredLevel: requiredLevel,
  742. shouldBeUnlocked: shouldBeUnlocked,
  743. isCurrentlyUnlocked: isCurrentlyUnlocked,
  744. currentLevel: weaponData?.level || 0,
  745. // 由于WeaponData类型中没有unlockTime属性,暂时移除该字段
  746. unlocked: weaponData?.level > 0,
  747. needsUpdate: shouldBeUnlocked && !isCurrentlyUnlocked
  748. });
  749. }
  750. return {
  751. maxUnlockedLevel: maxUnlockedLevel,
  752. weapons: weaponStatus,
  753. summary: {
  754. total: weaponStatus.length,
  755. unlocked: weaponStatus.filter(w => w.isCurrentlyUnlocked).length,
  756. shouldBeUnlocked: weaponStatus.filter(w => w.shouldBeUnlocked).length,
  757. needsUpdate: weaponStatus.filter(w => w.needsUpdate).length
  758. }
  759. };
  760. }
  761. /**
  762. * 强制同步所有武器解锁状态(用于修复数据不一致问题)
  763. */
  764. public forceSyncWeaponUnlocks() {
  765. if (!this.saveDataManager || !this.weaponsConfig) {
  766. console.error('[UpgradeController] 无法强制同步:数据管理器或武器配置未初始化');
  767. return false;
  768. }
  769. const maxUnlockedLevel = this.saveDataManager.getMaxUnlockedLevel();
  770. let syncCount = 0;
  771. console.log(`[UpgradeController] 开始强制同步武器解锁状态,基于最大解锁关卡: ${maxUnlockedLevel}`);
  772. for (const weaponConfig of this.weaponsConfig.weapons) {
  773. const weaponId = weaponConfig.id;
  774. const weaponData = this.saveDataManager.getWeapon(weaponId);
  775. const requiredLevel = this.getWeaponUnlockLevelById(weaponId);
  776. const shouldBeUnlocked = maxUnlockedLevel >= requiredLevel;
  777. const isCurrentlyUnlocked = weaponData && weaponData.level > 0;
  778. if (shouldBeUnlocked && !isCurrentlyUnlocked && weaponData) {
  779. weaponData.level = 1;
  780. // 由于WeaponData类型中没有unlockTime属性,暂时注释掉这行代码
  781. // weaponData.unlockTime = weaponData.unlockTime || Date.now();
  782. syncCount++;
  783. console.log(`[UpgradeController] 强制解锁武器: ${weaponConfig.name} (${weaponId})`);
  784. }
  785. }
  786. if (syncCount > 0) {
  787. this.saveDataManager.savePlayerData();
  788. this.refreshWeaponList();
  789. console.log(`[UpgradeController] 强制同步完成,解锁了 ${syncCount} 个武器`);
  790. } else {
  791. console.log(`[UpgradeController] 强制同步完成,没有需要更新的武器`);
  792. }
  793. return syncCount > 0;
  794. }
  795. /**
  796. * 诊断武器解锁问题(用于调试)
  797. */
  798. public diagnoseWeaponUnlockIssue() {
  799. console.log('=== 武器解锁问题诊断 ===');
  800. if (!this.saveDataManager) {
  801. console.error('SaveDataManager未初始化');
  802. return;
  803. }
  804. if (!this.weaponsConfig) {
  805. console.error('武器配置未加载');
  806. return;
  807. }
  808. const currentLevel = this.saveDataManager.getCurrentLevel();
  809. const maxUnlockedLevel = this.saveDataManager.getMaxUnlockedLevel();
  810. const playerData = this.saveDataManager.getPlayerData();
  811. console.log(`当前关卡: ${currentLevel}`);
  812. console.log(`最大解锁关卡: ${maxUnlockedLevel}`);
  813. console.log(`金币: ${playerData?.coins || 0}`);
  814. console.log('\n=== 关卡完成状态 ===');
  815. for (let i = 1; i <= 5; i++) {
  816. const progress = this.saveDataManager.getLevelProgress(i);
  817. const isCompleted = this.saveDataManager.isLevelCompleted(i);
  818. console.log(`关卡${i}: 完成=${isCompleted}, 尝试次数=${progress?.attempts || 0}`);
  819. }
  820. console.log('\n=== 武器解锁状态 ===');
  821. const weaponUnlockMap = {
  822. 'pea_shooter': 1,
  823. 'sharp_carrot': 2,
  824. 'saw_grass': 3,
  825. 'watermelon_bomb': 4,
  826. 'boomerang_plant': 5,
  827. 'hot_pepper': 6,
  828. 'cactus_shotgun': 7,
  829. 'okra_missile': 8,
  830. 'mace_club': 9
  831. };
  832. for (const weaponConfig of this.weaponsConfig.weapons) {
  833. const weaponId = weaponConfig.id;
  834. const weaponData = this.saveDataManager.getWeapon(weaponId);
  835. const requiredLevel = weaponUnlockMap[weaponId] || 1;
  836. const shouldBeUnlocked = maxUnlockedLevel >= requiredLevel;
  837. const isCurrentlyUnlocked = weaponData && weaponData.level > 0;
  838. console.log(`${weaponConfig.name} (${weaponId}):`);
  839. console.log(` 需要关卡: ${requiredLevel}`);
  840. console.log(` 应该解锁: ${shouldBeUnlocked}`);
  841. console.log(` 当前状态: ${isCurrentlyUnlocked ? '已解锁' : '未解锁'}`);
  842. console.log(` 武器等级: ${weaponData?.level || 0}`);
  843. if (shouldBeUnlocked && !isCurrentlyUnlocked) {
  844. console.log(` ❌ 问题:应该解锁但未解锁`);
  845. } else if (shouldBeUnlocked && isCurrentlyUnlocked) {
  846. console.log(` ✅ 正常:已正确解锁`);
  847. } else {
  848. console.log(` ⏳ 等待:尚未达到解锁条件`);
  849. }
  850. }
  851. console.log('\n=== 修复建议 ===');
  852. console.log('如果发现武器解锁状态不正确,请运行以下命令:');
  853. console.log('1. 在控制台运行: window.upgradeController.forceSyncWeaponUnlocks()');
  854. console.log('2. 或者刷新页面重新初始化');
  855. // 将实例暴露到全局,方便调试
  856. (window as any).upgradeController = this;
  857. }
  858. /**
  859. * 组件销毁时清理事件监听
  860. */
  861. onDestroy() {
  862. EventBus.getInstance().off(GameEvents.GAME_SUCCESS, this.onLevelComplete, this);
  863. }
  864. }