GameManager.ts 34 KB

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