GameManager.ts 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  1. import { _decorator, Component, Node, Prefab, instantiate, Vec3, find, director, Canvas, UITransform, Button, Label, EPhysics2DDrawFlags, sys } from 'cc';
  2. import { LevelManager } from './LevelManager';
  3. import { LevelConfigManager } from './LevelConfigManager';
  4. import { SaveDataManager } from './SaveDataManager';
  5. import { ShopManager } from '../ShopSystem/ShopManager';
  6. import { ConfigManager } from '../Core/ConfigManager';
  7. import { EnemyController } from '../CombatSystem/EnemyController';
  8. import EventBus, { GameEvents } from '../Core/EventBus';
  9. import { PhysicsManager } from '../Core/PhysicsManager';
  10. const { ccclass, property } = _decorator;
  11. /**
  12. * 游戏状态枚举
  13. */
  14. enum GameState {
  15. PLAYING = 'playing',
  16. SUCCESS = 'success',
  17. DEFEAT = 'defeat',
  18. PAUSED = 'paused'
  19. }
  20. /**
  21. * 增强版游戏管理器
  22. * 整合了游戏启动、状态管理、UI控制等功能
  23. */
  24. @ccclass('GameManager')
  25. export class GameManager extends Component {
  26. // === 原GameManager属性 ===
  27. @property({
  28. type: Node,
  29. tooltip: '拖拽BallController节点到这里'
  30. })
  31. public ballController: Node = null;
  32. @property({
  33. type: Node,
  34. tooltip: '拖拽BlockSelectionUI节点到这里'
  35. })
  36. public blockSelectionUI: Node = null;
  37. @property({
  38. type: Node,
  39. tooltip: '拖拽GameArea节点到这里'
  40. })
  41. public gameArea: Node = null;
  42. @property({
  43. type: Node,
  44. tooltip: '拖拽EnemyController节点到这里'
  45. })
  46. public enemyManager: Node = null;
  47. // === 游戏状态管理属性 ===
  48. @property({
  49. type: Node,
  50. tooltip: '血量显示节点 (HeartLabeld)'
  51. })
  52. public heartLabelNode: Node = null;
  53. @property({
  54. type: Node,
  55. tooltip: '游戏成功UI节点 (GameSuccess)'
  56. })
  57. public gameSuccessUI: Node = null;
  58. @property({
  59. type: Node,
  60. tooltip: '游戏失败UI节点 (GameDefeat)'
  61. })
  62. public gameDefeatUI: Node = null;
  63. @property({
  64. type: Node,
  65. tooltip: '波次显示节点 (WaveNumber)'
  66. })
  67. public waveNumberNode: Node = null;
  68. @property({
  69. type: Node,
  70. tooltip: '敌人数量显示节点 (EnemyNumber)'
  71. })
  72. public enemyNumberNode: Node = null;
  73. // === 游戏配置属性 ===
  74. @property({
  75. tooltip: '墙体初始血量'
  76. })
  77. public wallHealth: number = 1200;
  78. @property({
  79. tooltip: '初始血量'
  80. })
  81. public initialHealth: number = 100;
  82. @property({
  83. tooltip: '状态检查间隔(秒)'
  84. })
  85. public checkInterval: number = 1.0;
  86. // === 私有属性 ===
  87. private gameStarted: boolean = false;
  88. private currentHealth: number = 100;
  89. private currentState: GameState = GameState.PLAYING;
  90. private checkTimer: number = 0;
  91. private heartLabel: Label = null;
  92. private waveNumberLabel: Label = null;
  93. private enemyNumberLabel: Label = null;
  94. private enemyController: EnemyController = null;
  95. private levelManager: LevelManager = null;
  96. private levelConfigManager: LevelConfigManager = null;
  97. private saveDataManager: SaveDataManager = null;
  98. private shopManager: ShopManager = null;
  99. private configManager: ConfigManager = null;
  100. private enemySpawningStarted: boolean = false;
  101. private totalEnemiesSpawned: number = 0;
  102. private currentWave: number = 1;
  103. private currentWaveEnemyCount: number = 0;
  104. private currentWaveTotalEnemies: number = 0; // 当前波次总敌人数
  105. private levelWaves: any[] = []; // 关卡波次配置
  106. private levelTotalEnemies: number = 0; // 本关卡总敌人数
  107. private enemiesKilled: number = 0; // 已击杀敌人数量
  108. // 游戏计时器
  109. private gameStartTime: number = 0;
  110. private gameEndTime: number = 0;
  111. // 游戏区域的边界
  112. private gameBounds = {
  113. left: 0,
  114. right: 0,
  115. top: 0,
  116. bottom: 0
  117. };
  118. start() {
  119. // 初始化物理系统
  120. this.initPhysicsSystem();
  121. // 初始化管理器
  122. this.initializeManagers();
  123. // 计算游戏区域边界
  124. this.calculateGameBounds();
  125. // 初始化游戏状态
  126. this.initializeGameState();
  127. // 查找UI节点
  128. this.findUINodes();
  129. // 查找敌人控制器
  130. this.findEnemyController();
  131. // 初始化墙体血量显示
  132. this.initWallHealthDisplay();
  133. // 设置敌人控制器
  134. this.setupEnemyController();
  135. // 设置UI按钮
  136. this.setupUIButtons();
  137. // 加载当前关卡配置
  138. this.loadCurrentLevelConfig();
  139. }
  140. update(deltaTime: number) {
  141. if (this.currentState !== GameState.PLAYING) {
  142. return;
  143. }
  144. // 更新检查计时器
  145. this.checkTimer += deltaTime;
  146. if (this.checkTimer >= this.checkInterval) {
  147. this.checkTimer = 0;
  148. this.checkGameState();
  149. }
  150. // 检查自动保存
  151. if (this.saveDataManager) {
  152. this.saveDataManager.checkAutoSave();
  153. }
  154. }
  155. // === 物理系统初始化 ===
  156. private initPhysicsSystem() {
  157. // 确保 PhysicsManager 单例存在
  158. let pm = PhysicsManager.getInstance();
  159. if (!pm) {
  160. const physicsNode = new Node('PhysicsManager');
  161. director.getScene()?.addChild(physicsNode);
  162. pm = physicsNode.addComponent(PhysicsManager);
  163. }
  164. }
  165. // === 管理器初始化 ===
  166. private initializeManagers() {
  167. this.levelManager = LevelManager.getInstance();
  168. this.shopManager = ShopManager.getInstance();
  169. this.configManager = ConfigManager.getInstance();
  170. this.levelConfigManager = LevelConfigManager.getInstance();
  171. this.enemyController = EnemyController.getInstance() || null;
  172. // 初始化存档管理器
  173. this.saveDataManager = SaveDataManager.getInstance();
  174. this.saveDataManager.initialize();
  175. }
  176. // === 游戏状态初始化 ===
  177. private initializeGameState() {
  178. this.currentHealth = this.initialHealth;
  179. this.currentState = GameState.PLAYING;
  180. this.checkTimer = 0;
  181. this.enemySpawningStarted = false;
  182. this.totalEnemiesSpawned = 0;
  183. this.currentWave = 1;
  184. this.currentWaveEnemyCount = 0;
  185. this.currentWaveTotalEnemies = 0; // 当前波次总敌人数
  186. // 初始化UI显示
  187. this.updateWaveDisplay();
  188. this.updateEnemyCountDisplay();
  189. }
  190. // === 计算游戏区域边界 ===
  191. private calculateGameBounds() {
  192. const canvas = find('Canvas');
  193. if (!canvas) {
  194. return;
  195. }
  196. const canvasUI = canvas.getComponent(UITransform);
  197. if (!canvasUI) {
  198. return;
  199. }
  200. const screenWidth = canvasUI.width;
  201. const screenHeight = canvasUI.height;
  202. const worldPos = canvas.worldPosition;
  203. this.gameBounds.left = worldPos.x - screenWidth / 2;
  204. this.gameBounds.right = worldPos.x + screenWidth / 2;
  205. this.gameBounds.bottom = worldPos.y - screenHeight / 2;
  206. this.gameBounds.top = worldPos.y + screenHeight / 2;
  207. }
  208. // === 查找UI节点 ===
  209. private findUINodes() {
  210. // 查找血量显示节点
  211. if (!this.heartLabelNode) {
  212. this.heartLabelNode = find('Canvas/GameLevelUI/HeartNode/HeartLabeld');
  213. }
  214. if (this.heartLabelNode) {
  215. this.heartLabel = this.heartLabelNode.getComponent(Label);
  216. }
  217. // 查找波次显示节点
  218. if (!this.waveNumberNode) {
  219. this.waveNumberNode = find('Canvas/GameLevelUI/WaveInfo/WaveNumber');
  220. }
  221. if (this.waveNumberNode) {
  222. this.waveNumberLabel = this.waveNumberNode.getComponent(Label);
  223. }
  224. // 查找敌人数量显示节点
  225. if (!this.enemyNumberNode) {
  226. this.enemyNumberNode = find('Canvas/GameLevelUI/EnemyNode/EnemyNumber');
  227. }
  228. if (this.enemyNumberNode) {
  229. this.enemyNumberLabel = this.enemyNumberNode.getComponent(Label);
  230. }
  231. // 查找游戏成功UI
  232. if (!this.gameSuccessUI) {
  233. this.gameSuccessUI = find('Canvas/GameSuccess');
  234. }
  235. if (this.gameSuccessUI) {
  236. this.gameSuccessUI.active = false;
  237. }
  238. // 查找游戏失败UI
  239. if (!this.gameDefeatUI) {
  240. this.gameDefeatUI = find('Canvas/GameDefeat');
  241. }
  242. if (this.gameDefeatUI) {
  243. this.gameDefeatUI.active = false;
  244. }
  245. }
  246. // === 查找敌人控制器 ===
  247. private findEnemyController() {
  248. if (this.enemyManager) {
  249. this.enemyController = this.enemyManager.getComponent(EnemyController);
  250. }
  251. if (!this.enemyController) {
  252. const enemyNode = find('Canvas/GameLevelUI/EnemyController');
  253. if (enemyNode) {
  254. this.enemyController = enemyNode.getComponent(EnemyController);
  255. }
  256. }
  257. }
  258. // === 初始化墙体血量显示 ===
  259. private initWallHealthDisplay() {
  260. if (this.heartLabelNode && this.heartLabel) {
  261. this.heartLabel.string = this.wallHealth.toString();
  262. }
  263. // 通知敌人控制器墙体血量节点
  264. if (this.enemyController && this.heartLabelNode) {
  265. this.updateEnemyControllerWallHealth(this.heartLabelNode);
  266. }
  267. }
  268. // === 更新EnemyController的墙体血量 ===
  269. private updateEnemyControllerWallHealth(wallHealthNode: Node) {
  270. if (this.enemyController) {
  271. // 同步血量值
  272. this.enemyController.wallHealth = this.wallHealth;
  273. // 设置血量显示节点
  274. const heartLabelNode = find('Canvas/GameLevelUI/HeartNode/HeartLabeld');
  275. if (heartLabelNode) {
  276. this.enemyController.wallHealthNode = heartLabelNode;
  277. }
  278. // 让EnemyController更新显示
  279. this.enemyController.updateWallHealthDisplay();
  280. }
  281. }
  282. // === 设置敌人控制器 ===
  283. private setupEnemyController() {
  284. if (!this.enemyManager) {
  285. const gameLevelUI = find('Canvas/GameLevelUI');
  286. if (!gameLevelUI) {
  287. console.error('找不到GameLevelUI节点,无法创建EnemyController');
  288. return;
  289. }
  290. this.enemyManager = new Node('EnemyController');
  291. gameLevelUI.addChild(this.enemyManager);
  292. }
  293. if (!this.enemyController) {
  294. this.enemyController = this.enemyManager.addComponent(EnemyController);
  295. this.enemyController.wallHealth = this.wallHealth;
  296. }
  297. }
  298. // === 游戏状态检查 ===
  299. private checkGameState() {
  300. // 更新血量
  301. this.updateHealthFromUI();
  302. if (this.currentHealth <= 0) {
  303. this.triggerGameDefeat();
  304. return;
  305. }
  306. // 更新当前敌人数量(用于波次UI显示等,不影响胜利逻辑)
  307. if (this.enemyController) {
  308. const currentEnemyCount = this.enemyController.getCurrentEnemyCount ?
  309. this.enemyController.getCurrentEnemyCount() : 0;
  310. this.updateCurrentWaveEnemyCount(currentEnemyCount);
  311. }
  312. // 检查是否全部击败
  313. if (this.checkAllEnemiesDefeated()) {
  314. this.triggerGameSuccess();
  315. return;
  316. }
  317. }
  318. // === 从UI更新血量 ===
  319. private updateHealthFromUI() {
  320. if (this.heartLabel) {
  321. const healthText = this.heartLabel.string;
  322. const healthMatch = healthText.match(/\d+/);
  323. if (healthMatch) {
  324. const newHealth = parseInt(healthMatch[0]);
  325. if (newHealth !== this.currentHealth) {
  326. this.currentHealth = newHealth;
  327. }
  328. }
  329. }
  330. }
  331. // === 检查所有敌人是否被击败 ===
  332. private checkAllEnemiesDefeated(): boolean {
  333. if (!this.enemyController) {
  334. return false;
  335. }
  336. // 检查敌人是否已开始生成(避免开局就胜利)
  337. if (!this.enemySpawningStarted) {
  338. if (this.enemyController.isGameStarted && this.enemyController.isGameStarted()) {
  339. this.enemySpawningStarted = true;
  340. } else {
  341. return false;
  342. }
  343. }
  344. // 获取当前敌人数量
  345. const currentEnemyCount = this.enemyController.getCurrentEnemyCount ?
  346. this.enemyController.getCurrentEnemyCount() : 0;
  347. // 如果关卡总敌人数已知,以击杀数为准判定胜利
  348. if (this.levelTotalEnemies > 0) {
  349. // 当击杀数达到或超过总敌数且场上没有存活敌人时胜利
  350. return this.enemiesKilled >= this.levelTotalEnemies && currentEnemyCount === 0;
  351. }
  352. // 否则退化到旧逻辑:依赖于是否曾经生成过敌人
  353. // 更新已生成敌人总数(记录曾经达到的最大值)
  354. if (currentEnemyCount > this.totalEnemiesSpawned) {
  355. this.totalEnemiesSpawned = currentEnemyCount;
  356. }
  357. const shouldCheckVictory = this.enemySpawningStarted &&
  358. currentEnemyCount === 0 &&
  359. this.totalEnemiesSpawned > 0;
  360. return shouldCheckVictory;
  361. }
  362. // === 触发游戏失败 ===
  363. private triggerGameDefeat() {
  364. if (this.currentState === GameState.DEFEAT) {
  365. return;
  366. }
  367. this.currentState = GameState.DEFEAT;
  368. this.pauseGame();
  369. if (this.gameDefeatUI) {
  370. this.gameDefeatUI.active = true;
  371. }
  372. this.onGameDefeat();
  373. // 派发游戏失败事件
  374. EventBus.getInstance().emit(GameEvents.GAME_DEFEAT);
  375. }
  376. // === 触发游戏成功 ===
  377. private triggerGameSuccess() {
  378. if (this.currentState === GameState.SUCCESS) {
  379. return;
  380. }
  381. this.currentState = GameState.SUCCESS;
  382. this.pauseGame();
  383. if (this.gameSuccessUI) {
  384. this.gameSuccessUI.active = true;
  385. }
  386. this.onGameSuccess();
  387. // 派发游戏成功事件
  388. EventBus.getInstance().emit(GameEvents.GAME_SUCCESS);
  389. }
  390. // === 暂停游戏 ===
  391. private pauseGame() {
  392. this.gameStarted = false;
  393. if (this.enemyController && this.enemyController.pauseSpawning) {
  394. this.enemyController.pauseSpawning();
  395. }
  396. }
  397. // === 恢复游戏 ===
  398. private resumeGame() {
  399. this.currentState = GameState.PLAYING;
  400. this.gameStarted = true;
  401. if (this.enemyController && this.enemyController.resumeSpawning) {
  402. this.enemyController.resumeSpawning();
  403. }
  404. if (this.gameSuccessUI) {
  405. this.gameSuccessUI.active = false;
  406. }
  407. if (this.gameDefeatUI) {
  408. this.gameDefeatUI.active = false;
  409. }
  410. }
  411. // === 游戏失败回调 ===
  412. private onGameDefeat() {
  413. console.log('处理游戏失败逻辑');
  414. this.gameEndTime = Date.now();
  415. // 记录游戏失败到存档
  416. if (this.saveDataManager) {
  417. const currentLevel = this.saveDataManager.getCurrentLevel();
  418. this.saveDataManager.failLevel(currentLevel);
  419. // 更新统计数据
  420. this.saveDataManager.updateStatistic('totalTimePlayed', this.getGameDuration());
  421. }
  422. }
  423. // === 游戏成功回调 ===
  424. private onGameSuccess() {
  425. console.log('处理游戏成功逻辑');
  426. this.gameEndTime = Date.now();
  427. this.giveReward();
  428. this.onLevelComplete();
  429. }
  430. // === 给予奖励 ===
  431. private giveReward() {
  432. if (!this.saveDataManager) return;
  433. const currentLevel = this.saveDataManager.getCurrentLevel();
  434. const baseReward = currentLevel * 50;
  435. const healthBonus = Math.floor(this.currentHealth * 0.1);
  436. const timeBonus = this.calculateTimeBonus();
  437. const totalCoins = baseReward + healthBonus + timeBonus;
  438. // 给予金币奖励
  439. this.saveDataManager.addCoins(totalCoins, `level_${currentLevel}_complete`);
  440. // 如果是首次完成,给予额外奖励
  441. if (!this.saveDataManager.isLevelCompleted(currentLevel)) {
  442. const firstClearBonus = currentLevel * 25;
  443. this.saveDataManager.addCoins(firstClearBonus, `level_${currentLevel}_first_clear`);
  444. }
  445. console.log(`🎉 关卡奖励:金币 +${totalCoins},健康奖励 +${healthBonus},时间奖励 +${timeBonus}`);
  446. }
  447. // === 处理关卡完成 ===
  448. private onLevelComplete(score: number = 0, stars: number = 1) {
  449. if (!this.saveDataManager) return;
  450. const currentLevel = this.saveDataManager.getCurrentLevel();
  451. const gameTime = this.getGameDuration();
  452. // 计算得分(基于剩余血量、用时等)
  453. const calculatedScore = this.calculateScore();
  454. const finalScore = Math.max(score, calculatedScore);
  455. // 计算星级(基于表现)
  456. const calculatedStars = this.calculateStars();
  457. const finalStars = Math.max(stars, calculatedStars);
  458. // 记录关卡完成到存档
  459. this.saveDataManager.completeLevel(currentLevel, finalScore, gameTime, finalStars);
  460. // 更新统计数据
  461. this.saveDataManager.updateStatistic('totalTimePlayed', gameTime);
  462. this.saveDataManager.updateStatistic('totalEnemiesDefeated', this.totalEnemiesSpawned);
  463. console.log(`🏆 关卡 ${currentLevel} 完成!得分: ${finalScore}, 星级: ${finalStars}, 用时: ${gameTime}秒`);
  464. // 兼容原有的LevelManager
  465. if (this.levelManager) {
  466. this.levelManager.completeLevel(currentLevel, finalScore, finalStars);
  467. }
  468. }
  469. // === 计算游戏时长 ===
  470. private getGameDuration(): number {
  471. if (this.gameStartTime === 0) return 0;
  472. const endTime = this.gameEndTime || Date.now();
  473. return Math.floor((endTime - this.gameStartTime) / 1000);
  474. }
  475. // === 计算时间奖励 ===
  476. private calculateTimeBonus(): number {
  477. const gameTime = this.getGameDuration();
  478. if (gameTime === 0) return 0;
  479. // 时间越短奖励越多,最多额外50%奖励
  480. const maxTime = 300; // 5分钟
  481. const timeRatio = Math.max(0, (maxTime - gameTime) / maxTime);
  482. const baseReward = this.saveDataManager.getCurrentLevel() * 50;
  483. return Math.floor(baseReward * timeRatio * 0.5);
  484. }
  485. // === 计算得分 ===
  486. private calculateScore(): number {
  487. const currentLevel = this.saveDataManager?.getCurrentLevel() || 1;
  488. const baseScore = currentLevel * 1000;
  489. const healthScore = this.currentHealth * 10;
  490. const enemyScore = this.totalEnemiesSpawned * 50;
  491. const timeScore = this.calculateTimeBonus();
  492. return baseScore + healthScore + enemyScore + timeScore;
  493. }
  494. // === 计算星级 ===
  495. private calculateStars(): number {
  496. const healthRatio = this.currentHealth / this.initialHealth;
  497. const gameTime = this.getGameDuration();
  498. // 基于血量剩余和用时计算星级
  499. if (healthRatio >= 0.8 && gameTime <= 120) {
  500. return 3; // 3星:血量80%以上,2分钟内完成
  501. } else if (healthRatio >= 0.5 && gameTime <= 300) {
  502. return 2; // 2星:血量50%以上,5分钟内完成
  503. } else if (healthRatio > 0) {
  504. return 1; // 1星:只要完成就有1星
  505. }
  506. return 1;
  507. }
  508. // === 设置UI按钮 ===
  509. private setupUIButtons() {
  510. this.setupSuccessUIButtons();
  511. this.setupDefeatUIButtons();
  512. }
  513. // === 设置成功界面按钮 ===
  514. private setupSuccessUIButtons() {
  515. if (this.gameSuccessUI) {
  516. const nextLevelBtn = this.gameSuccessUI.getChildByName('NextLevelBtn');
  517. const restartBtn = this.gameSuccessUI.getChildByName('RestartBtn');
  518. const mainMenuBtn = this.gameSuccessUI.getChildByName('MainMenuBtn');
  519. const shopBtn = this.gameSuccessUI.getChildByName('ShopBtn');
  520. if (nextLevelBtn) {
  521. const button = nextLevelBtn.getComponent(Button);
  522. if (button) {
  523. button.node.on(Button.EventType.CLICK, this.onNextLevelClick, this);
  524. }
  525. }
  526. if (restartBtn) {
  527. const button = restartBtn.getComponent(Button);
  528. if (button) {
  529. button.node.on(Button.EventType.CLICK, this.onRestartClick, this);
  530. }
  531. }
  532. if (mainMenuBtn) {
  533. const button = mainMenuBtn.getComponent(Button);
  534. if (button) {
  535. button.node.on(Button.EventType.CLICK, this.onMainMenuClick, this);
  536. }
  537. }
  538. if (shopBtn) {
  539. const button = shopBtn.getComponent(Button);
  540. if (button) {
  541. button.node.on(Button.EventType.CLICK, this.onShopClick, this);
  542. }
  543. }
  544. }
  545. }
  546. // === 设置失败界面按钮 ===
  547. private setupDefeatUIButtons() {
  548. if (this.gameDefeatUI) {
  549. const restartBtn = this.gameDefeatUI.getChildByName('RestartBtn');
  550. const mainMenuBtn = this.gameDefeatUI.getChildByName('MainMenuBtn');
  551. const shopBtn = this.gameDefeatUI.getChildByName('ShopBtn');
  552. const reviveBtn = this.gameDefeatUI.getChildByName('ReviveBtn');
  553. if (restartBtn) {
  554. const button = restartBtn.getComponent(Button);
  555. if (button) {
  556. button.node.on(Button.EventType.CLICK, this.onRestartClick, this);
  557. }
  558. }
  559. if (mainMenuBtn) {
  560. const button = mainMenuBtn.getComponent(Button);
  561. if (button) {
  562. button.node.on(Button.EventType.CLICK, this.onMainMenuClick, this);
  563. }
  564. }
  565. if (shopBtn) {
  566. const button = shopBtn.getComponent(Button);
  567. if (button) {
  568. button.node.on(Button.EventType.CLICK, this.onShopClick, this);
  569. }
  570. }
  571. if (reviveBtn) {
  572. const button = reviveBtn.getComponent(Button);
  573. if (button) {
  574. button.node.on(Button.EventType.CLICK, this.onReviveClick, this);
  575. }
  576. }
  577. }
  578. }
  579. // === 按钮点击事件处理 ===
  580. private async onNextLevelClick() {
  581. if (!this.saveDataManager) {
  582. console.warn('SaveDataManager 未初始化');
  583. return;
  584. }
  585. const currentLevel = this.saveDataManager.getCurrentLevel();
  586. const nextLevel = currentLevel + 1;
  587. if (!this.saveDataManager.isLevelUnlocked(nextLevel)) {
  588. console.log('下一关卡尚未解锁');
  589. return;
  590. }
  591. // 设置当前关卡为下一关
  592. this.saveDataManager.getPlayerData().currentLevel = nextLevel;
  593. this.saveDataManager.savePlayerData();
  594. // 隐藏结算面板
  595. if (this.gameSuccessUI) this.gameSuccessUI.active = false;
  596. if (this.gameDefeatUI) this.gameDefeatUI.active = false;
  597. // 停止并清理敌人
  598. if (this.enemyController) {
  599. this.enemyController.stopGame();
  600. this.enemyController.clearAllEnemies();
  601. }
  602. // 重置方块、子弹等(通过 BlockManager)
  603. const blockManager = find('Canvas/GameLevelUI')?.getComponent('BlockManager');
  604. if (blockManager) {
  605. if (blockManager['clearBlocks']) blockManager['clearBlocks']();
  606. if (blockManager['onGameReset']) blockManager['onGameReset']();
  607. }
  608. // 重置内部状态
  609. this.restartGame();
  610. // 加载并应用新关卡配置
  611. await this.loadCurrentLevelConfig();
  612. // 直接开始游戏(如果需要再次确认,可移除此行)
  613. this.startGame();
  614. }
  615. private onRestartClick() {
  616. this.restartCurrentLevel();
  617. }
  618. private onMainMenuClick() {
  619. // 保存数据
  620. if (this.saveDataManager) {
  621. this.saveDataManager.savePlayerData(true);
  622. }
  623. // 隐藏结算面板
  624. if (this.gameSuccessUI) this.gameSuccessUI.active = false;
  625. if (this.gameDefeatUI) this.gameDefeatUI.active = false;
  626. // 停止并清理游戏内容
  627. if (this.enemyController) {
  628. this.enemyController.stopGame();
  629. this.enemyController.clearAllEnemies();
  630. }
  631. this.restartGame();
  632. // UI 切换:隐藏关卡界面,显示主界面
  633. const mainUI = find('Canvas/MainUI');
  634. const gameLevelUI = find('Canvas/GameLevelUI');
  635. if (mainUI) mainUI.active = true;
  636. if (gameLevelUI) gameLevelUI.active = false;
  637. console.log('返回主界面');
  638. }
  639. private onShopClick() {
  640. console.log('打开商店');
  641. }
  642. private onReviveClick() {
  643. // 消费钻石复活
  644. if (this.saveDataManager) {
  645. const reviveCost = 10; // 复活需要10钻石
  646. if (this.saveDataManager.spendDiamonds(reviveCost)) {
  647. this.revivePlayer();
  648. console.log(`💎 消费 ${reviveCost} 钻石复活`);
  649. } else {
  650. console.log('钻石不足,无法复活');
  651. }
  652. }
  653. }
  654. // === 复活玩家 ===
  655. private revivePlayer() {
  656. this.setHealth(50);
  657. this.restartGame();
  658. }
  659. // === 重新开始当前关卡 ===
  660. private restartCurrentLevel() {
  661. this.restartGame();
  662. }
  663. // === 原GameManager方法 ===
  664. public onConfirmButtonClicked() {
  665. if (this.blockSelectionUI) {
  666. this.blockSelectionUI.active = false;
  667. const gridContainer = find('Canvas/GameLevelUI/GameArea/GridContainer');
  668. if (gridContainer) {
  669. gridContainer.active = true;
  670. }
  671. this.preservePlacedBlocks();
  672. }
  673. this.startGame();
  674. }
  675. private preservePlacedBlocks() {
  676. const blockController = find('Canvas/GameLevelUI/BlockController');
  677. if (blockController) {
  678. const blockManager = blockController.getComponent('BlockManager') as any;
  679. if (blockManager) {
  680. blockManager.onGameStart();
  681. }
  682. }
  683. }
  684. public startGame() {
  685. this.gameStarted = true;
  686. this.gameStartTime = Date.now();
  687. this.gameEndTime = 0;
  688. this.currentState = GameState.PLAYING;
  689. // 通知BlockManager游戏开始
  690. const blockManager = find('Canvas/GameLevelUI')?.getComponent('BlockManager');
  691. if (blockManager && blockManager['onGameStart']) {
  692. blockManager['onGameStart']();
  693. }
  694. this.spawnBall();
  695. console.log('🎮 游戏开始!');
  696. if (this.enemyController) {
  697. this.enemyController.startGame();
  698. }
  699. }
  700. private spawnBall() {
  701. console.log('🎯 === GameManager: 启动小球 ===');
  702. if (!this.ballController) {
  703. console.error('❌ BallController 节点未设置');
  704. return;
  705. }
  706. // 获取BallController组件
  707. const ballControllerComp = this.ballController.getComponent('BallController') as any;
  708. if (ballControllerComp) {
  709. console.log('✅ 找到BallController组件,启动小球...');
  710. // 调用startBall方法而不是initialize,确保小球在确定按钮点击后才开始运动
  711. ballControllerComp.startBall();
  712. console.log('🚀 小球启动完成');
  713. } else {
  714. console.error('❌ 找不到BallController组件');
  715. }
  716. console.log('🎯 === GameManager: 小球启动流程完成 ===');
  717. }
  718. public gameOver() {
  719. this.triggerGameDefeat();
  720. }
  721. // === 公共方法 ===
  722. public setHealth(health: number) {
  723. this.currentHealth = Math.max(0, health);
  724. }
  725. public takeDamage(damage: number) {
  726. this.currentHealth = Math.max(0, this.currentHealth - damage);
  727. if (this.currentHealth <= 0) {
  728. this.triggerGameDefeat();
  729. }
  730. }
  731. public getCurrentState(): GameState {
  732. return this.currentState;
  733. }
  734. public restartGame() {
  735. this.currentState = GameState.PLAYING;
  736. this.gameStarted = false;
  737. this.gameStartTime = 0;
  738. this.gameEndTime = 0;
  739. this.currentHealth = this.initialHealth;
  740. this.totalEnemiesSpawned = 0;
  741. this.enemiesKilled = 0;
  742. this.currentWave = 1;
  743. this.currentWaveEnemyCount = 0;
  744. // 通知BlockManager游戏重置
  745. const blockManager = find('Canvas/GameLevelUI')?.getComponent('BlockManager');
  746. if (blockManager && blockManager['onGameReset']) {
  747. blockManager['onGameReset']();
  748. }
  749. }
  750. public isGameOver(): boolean {
  751. return this.currentState === GameState.SUCCESS || this.currentState === GameState.DEFEAT;
  752. }
  753. public forceGameSuccess() {
  754. this.triggerGameSuccess();
  755. }
  756. public forceGameDefeat() {
  757. this.triggerGameDefeat();
  758. }
  759. // === 获取EnemyController组件 ===
  760. public getEnemyController() {
  761. return this.enemyController;
  762. }
  763. // === 调试方法 ===
  764. public getEnemyStatus() {
  765. if (!this.enemyController) {
  766. return;
  767. }
  768. const currentCount = this.enemyController.getCurrentEnemyCount ?
  769. this.enemyController.getCurrentEnemyCount() : 0;
  770. const gameStarted = this.enemyController.isGameStarted();
  771. console.log('=== 敌人状态调试信息 ===');
  772. console.log(`敌人生成已开始: ${this.enemySpawningStarted}`);
  773. console.log(`当前敌人数量: ${currentCount}`);
  774. console.log(`曾生成最大敌人数: ${this.totalEnemiesSpawned}`);
  775. console.log(`EnemyController游戏已开始: ${gameStarted}`);
  776. console.log(`GameManager游戏状态: ${this.currentState}`);
  777. console.log(`GameManager游戏已开始: ${this.gameStarted}`);
  778. console.log(`当前血量: ${this.currentHealth}`);
  779. // 显示活跃敌人的详细信息
  780. if (this.enemyController.getActiveEnemies) {
  781. const activeEnemies = this.enemyController.getActiveEnemies();
  782. console.log(`活跃敌人列表 (${activeEnemies.length}个):`);
  783. activeEnemies.forEach((enemy, index) => {
  784. if (enemy && enemy.isValid) {
  785. console.log(` ${index + 1}. ${enemy.name} - 位置: (${enemy.position.x.toFixed(1)}, ${enemy.position.y.toFixed(1)})`);
  786. } else {
  787. console.log(` ${index + 1}. 无效敌人节点`);
  788. }
  789. });
  790. }
  791. }
  792. public forceStartEnemySpawning() {
  793. this.enemySpawningStarted = true;
  794. }
  795. public setTotalEnemiesSpawned(count: number) {
  796. this.totalEnemiesSpawned = count;
  797. }
  798. // === 测试方法 ===
  799. public testEnemyDetection() {
  800. const result = this.checkAllEnemiesDefeated();
  801. this.getEnemyStatus();
  802. return result;
  803. }
  804. // 测试组件获取是否正常
  805. public testComponentAccess() {
  806. console.log('=== 测试组件访问 ===');
  807. if (this.enemyController) {
  808. console.log('✅ EnemyController 访问正常');
  809. console.log(`当前敌人数量: ${this.enemyController.getCurrentEnemyCount()}`);
  810. console.log(`游戏是否开始: ${this.enemyController.isGameStarted()}`);
  811. } else {
  812. console.log('❌ EnemyController 未找到');
  813. }
  814. console.log('组件测试完成');
  815. }
  816. // === 测试敌人攻击 ===
  817. public testEnemyAttackWall() {
  818. console.log('=== GameManager: 测试敌人攻击墙体 ===');
  819. if (this.enemyController) {
  820. console.log(`攻击前墙体血量: ${this.enemyController.getCurrentWallHealth()}`);
  821. // 测试EnemyController的攻击功能
  822. const newHealth = this.enemyController.testEnemyAttack();
  823. console.log(`攻击后墙体血量: ${newHealth}`);
  824. // 强制所有敌人攻击
  825. this.enemyController.forceEnemyAttack();
  826. return newHealth;
  827. } else {
  828. console.error('EnemyController未找到');
  829. return -1;
  830. }
  831. }
  832. onDestroy() {
  833. // 清理按钮事件监听
  834. if (this.gameSuccessUI) {
  835. const buttons = this.gameSuccessUI.getComponentsInChildren(Button);
  836. buttons.forEach(button => {
  837. button.node.off(Button.EventType.CLICK);
  838. });
  839. }
  840. if (this.gameDefeatUI) {
  841. const buttons = this.gameDefeatUI.getComponentsInChildren(Button);
  842. buttons.forEach(button => {
  843. button.node.off(Button.EventType.CLICK);
  844. });
  845. }
  846. }
  847. // === 加载当前关卡配置 ===
  848. public async loadCurrentLevelConfig() {
  849. if (!this.levelConfigManager) {
  850. return null;
  851. }
  852. try {
  853. // 优先使用存档系统的关卡信息
  854. const currentLevel = this.saveDataManager ?
  855. this.saveDataManager.getCurrentLevel() :
  856. (this.levelManager ? this.levelManager.getCurrentLevel() : 1);
  857. console.log(`加载关卡 ${currentLevel} 配置`);
  858. const levelConfig = await this.levelConfigManager.getLevelConfig(currentLevel);
  859. if (levelConfig) {
  860. console.log(`关卡 ${currentLevel} 配置加载成功:`, levelConfig);
  861. this.applyLevelConfig(levelConfig);
  862. return levelConfig;
  863. } else {
  864. console.warn(`关卡 ${currentLevel} 的配置文件不存在`);
  865. return null;
  866. }
  867. } catch (error) {
  868. console.error('加载关卡配置失败:', error);
  869. return null;
  870. }
  871. }
  872. // === 应用关卡配置 ===
  873. private applyLevelConfig(levelConfig: any) {
  874. if (!levelConfig) return;
  875. // 应用关卡设置
  876. if (levelConfig.settings) {
  877. const settings = levelConfig.settings;
  878. if (settings.initialHealth !== undefined) {
  879. this.wallHealth = settings.initialHealth;
  880. this.initialHealth = settings.initialHealth;
  881. this.currentHealth = settings.initialHealth;
  882. }
  883. if (settings.checkInterval !== undefined) {
  884. this.checkInterval = settings.checkInterval;
  885. }
  886. }
  887. // 记录武器配置信息
  888. if (levelConfig.weapons) {
  889. console.log('关卡武器配置:', levelConfig.weapons);
  890. }
  891. // 记录敌人波次配置信息并初始化第一波
  892. if (levelConfig.waves && levelConfig.waves.length > 0) {
  893. this.levelWaves = levelConfig.waves;
  894. console.log('关卡敌人波次配置:', this.levelWaves);
  895. // 计算整关卡总敌人数
  896. this.levelTotalEnemies = this.levelWaves.reduce((levelTotal: number, wave: any) => {
  897. if (!wave || !wave.enemies) return levelTotal;
  898. const waveTotal = wave.enemies.reduce((t: number, g: any) => t + (g.count || 0), 0);
  899. return levelTotal + waveTotal;
  900. }, 0);
  901. console.log(`📊 本关卡共有敌人: ${this.levelTotalEnemies}`);
  902. // 初始化第一波
  903. const firstWave = this.levelWaves[0];
  904. if (firstWave && firstWave.enemies) {
  905. const totalEnemiesInFirstWave = firstWave.enemies.reduce((total: number, enemyGroup: any) => {
  906. return total + (enemyGroup.count || 0);
  907. }, 0);
  908. this.setCurrentWave(1, totalEnemiesInFirstWave);
  909. }
  910. }
  911. }
  912. // === 获取当前关卡信息 ===
  913. public async getCurrentLevelInfo() {
  914. const currentLevel = this.saveDataManager ?
  915. this.saveDataManager.getCurrentLevel() :
  916. (this.levelManager ? this.levelManager.getCurrentLevel() : 1);
  917. const levelProgress = this.saveDataManager ?
  918. this.saveDataManager.getLevelProgress(currentLevel) : null;
  919. const levelData = this.levelManager ?
  920. this.levelManager.getLevelData(currentLevel) : null;
  921. const levelConfig = await this.loadCurrentLevelConfig();
  922. return {
  923. level: currentLevel,
  924. maxUnlockedLevel: this.saveDataManager ?
  925. this.saveDataManager.getMaxUnlockedLevel() :
  926. (this.levelManager ? this.levelManager.getMaxUnlockedLevel() : 1),
  927. progress: levelProgress,
  928. data: levelData,
  929. config: levelConfig,
  930. playerData: this.saveDataManager ? {
  931. coins: this.saveDataManager.getCoins(),
  932. diamonds: this.saveDataManager.getDiamonds(),
  933. gems: this.saveDataManager.getGems(),
  934. playerLevel: this.saveDataManager.getPlayerLevel()
  935. } : null
  936. };
  937. }
  938. // === 更新波次显示 ===
  939. private updateWaveDisplay() {
  940. if (this.waveNumberLabel) {
  941. this.waveNumberLabel.string = this.currentWave.toString();
  942. }
  943. }
  944. // === 更新敌人数量显示 ===
  945. private updateEnemyCountDisplay() {
  946. if (this.enemyNumberLabel) {
  947. this.enemyNumberLabel.string = this.currentWaveTotalEnemies.toString();
  948. }
  949. }
  950. // === 设置当前波次 ===
  951. public setCurrentWave(wave: number, enemyCount: number = 0) {
  952. this.currentWave = wave;
  953. this.currentWaveEnemyCount = 0; // 重置当前敌人数量为0
  954. this.currentWaveTotalEnemies = enemyCount; // 设置该波次总敌人数
  955. this.updateWaveDisplay();
  956. this.updateEnemyCountDisplay();
  957. }
  958. // === 更新当前波次敌人数量 ===
  959. public updateCurrentWaveEnemyCount(count: number) {
  960. this.currentWaveEnemyCount = count;
  961. // 不应该修改总敌人数,总敌人数只在设置波次时确定
  962. // this.currentWaveTotalEnemies = count; // 移除这行
  963. // 敌人数量显示的是总数,不需要在这里更新
  964. // this.updateEnemyCountDisplay(); // 移除这行
  965. }
  966. // === 获取当前波次 ===
  967. public getCurrentWave(): number {
  968. return this.currentWave;
  969. }
  970. // === 获取当前波次敌人数量 ===
  971. public getCurrentWaveEnemyCount(): number {
  972. return this.currentWaveEnemyCount;
  973. }
  974. // === 获取当前波次总敌人数量 ===
  975. public getCurrentWaveTotalEnemies(): number {
  976. return this.currentWaveTotalEnemies;
  977. }
  978. // === 进入下一波 ===
  979. public nextWave() {
  980. this.currentWave++;
  981. // 根据关卡配置获取下一波敌人数
  982. let enemyTotal = 0;
  983. if (this.levelWaves && this.levelWaves.length >= this.currentWave) {
  984. const waveCfg = this.levelWaves[this.currentWave - 1];
  985. if (waveCfg && waveCfg.enemies) {
  986. enemyTotal = waveCfg.enemies.reduce((t: number, g: any) => t + (g.count || 0), 0);
  987. }
  988. }
  989. this.setCurrentWave(this.currentWave, enemyTotal);
  990. }
  991. /** 敌人被消灭时由 EnemyController 调用 */
  992. public onEnemyKilled() {
  993. this.enemiesKilled++;
  994. const remaining = Math.max(0, this.levelTotalEnemies - this.enemiesKilled);
  995. console.log(`⚔️ 已击杀: ${this.enemiesKilled}, 剩余敌人数量: ${remaining}`);
  996. // 如果需要在 UI 上实时显示剩余敌人数量,可在此赋值
  997. if (this.enemyNumberLabel) {
  998. this.enemyNumberLabel.string = remaining.toString();
  999. }
  1000. }
  1001. }