GameManager.ts 36 KB

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