test_both_defeat_scenarios.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /**
  2. * 测试墙体血量为0和菜单退出两种失败场景的GameEnd动画触发
  3. * 验证两种情况是否都能正确显示GameEnd动画
  4. */
  5. // 模拟事件系统
  6. class MockEventBus {
  7. constructor() {
  8. this.listeners = new Map();
  9. this.eventLog = [];
  10. }
  11. on(event, callback, context) {
  12. if (!this.listeners.has(event)) {
  13. this.listeners.set(event, []);
  14. }
  15. this.listeners.get(event).push({ callback, context });
  16. }
  17. emit(event, ...args) {
  18. this.eventLog.push({ event, args, timestamp: Date.now() });
  19. console.log(`[EventBus] 触发事件: ${event}`);
  20. if (this.listeners.has(event)) {
  21. this.listeners.get(event).forEach(({ callback, context }) => {
  22. callback.call(context, ...args);
  23. });
  24. }
  25. }
  26. getEventLog() {
  27. return this.eventLog;
  28. }
  29. clearLog() {
  30. this.eventLog = [];
  31. }
  32. }
  33. // 模拟GameEvents
  34. const GameEvents = {
  35. GAME_DEFEAT: 'GAME_DEFEAT',
  36. WALL_DESTROYED: 'WALL_DESTROYED',
  37. GAME_RESUME: 'GAME_RESUME'
  38. };
  39. // 模拟AppState
  40. const AppState = {
  41. IN_GAME: 'in_game'
  42. };
  43. // 模拟Wall组件
  44. class MockWall {
  45. constructor(eventBus) {
  46. this.eventBus = eventBus;
  47. this.currentHealth = 100;
  48. this.maxHealth = 100;
  49. }
  50. takeDamage(damage) {
  51. this.currentHealth -= damage;
  52. console.log(`[Wall] 墙体受到伤害: ${damage}, 当前血量: ${this.currentHealth}`);
  53. if (this.currentHealth <= 0) {
  54. this.onWallDestroyed();
  55. }
  56. }
  57. onWallDestroyed() {
  58. console.log('[Wall] 墙体被摧毁,触发游戏失败');
  59. // 通过事件系统触发墙体被摧毁事件(保留用于其他监听器)
  60. this.eventBus.emit(GameEvents.WALL_DESTROYED, {
  61. finalHealth: this.currentHealth,
  62. maxHealth: this.maxHealth
  63. });
  64. // 统一失败处理:直接触发GAME_DEFEAT事件,与菜单退出处理保持一致
  65. console.log('[Wall] 直接触发GAME_DEFEAT事件,与菜单退出失败处理流程一致');
  66. this.eventBus.emit(GameEvents.GAME_DEFEAT);
  67. }
  68. }
  69. // 模拟MenuController
  70. class MockMenuController {
  71. constructor(eventBus, gameManager) {
  72. this.eventBus = eventBus;
  73. this.gameManager = gameManager;
  74. this.isMenuOpen = false;
  75. }
  76. async closeMenuWithoutResume() {
  77. if (!this.isMenuOpen) return;
  78. this.isMenuOpen = false;
  79. console.log('[MenuController] 菜单已关闭(未触发游戏恢复)');
  80. }
  81. async onBackButtonClick() {
  82. console.log('[MenuController] 退出游戏按钮被点击');
  83. const currentAppState = this.gameManager.getCurrentAppState();
  84. console.log(`[MenuController] 当前应用状态: ${currentAppState}`);
  85. if (currentAppState === AppState.IN_GAME) {
  86. console.log('[MenuController] 游戏中退出,触发GAME_DEFEAT事件显示游戏失败UI');
  87. // 先触发游戏失败事件
  88. this.eventBus.emit(GameEvents.GAME_DEFEAT);
  89. // 关闭菜单(不触发GAME_RESUME事件)
  90. await this.closeMenuWithoutResume();
  91. console.log('[MenuController] 菜单退出处理完成,已触发GAME_DEFEAT事件');
  92. }
  93. }
  94. }
  95. // 模拟GameManager
  96. class MockGameManager {
  97. constructor() {
  98. this.currentAppState = AppState.IN_GAME;
  99. }
  100. getCurrentAppState() {
  101. return this.currentAppState;
  102. }
  103. }
  104. // 模拟GameEnd组件
  105. class MockGameEnd {
  106. constructor(eventBus) {
  107. this.eventBus = eventBus;
  108. this.defeatProcessed = 0;
  109. this.animationShown = 0;
  110. this.setupEventListeners();
  111. }
  112. setupEventListeners() {
  113. this.eventBus.on(GameEvents.GAME_DEFEAT, this.onGameDefeat, this);
  114. console.log('[GameEnd] 已注册GAME_DEFEAT事件监听器');
  115. }
  116. onGameDefeat() {
  117. console.log('[GameEnd] 接收到GAME_DEFEAT事件');
  118. console.log('[GameEnd] 游戏失败事件处理,开始统一处理流程');
  119. this.defeatProcessed++;
  120. this.calculateAndShowRewards();
  121. }
  122. calculateAndShowRewards() {
  123. console.log('[GameEnd] 计算和显示奖励(包含面板动画显示)');
  124. this.animationShown++;
  125. }
  126. }
  127. // 测试函数
  128. function testBothDefeatScenarios() {
  129. console.log('=== 测试墙体血量为0和菜单退出两种失败场景 ===\n');
  130. const eventBus = new MockEventBus();
  131. const gameManager = new MockGameManager();
  132. const menuController = new MockMenuController(eventBus, gameManager);
  133. const gameEnd = new MockGameEnd(eventBus);
  134. const wall = new MockWall(eventBus);
  135. console.log('1. 测试墙体血量为0场景:');
  136. eventBus.clearLog();
  137. wall.takeDamage(100); // 墙体血量归零
  138. console.log('\n2. 测试菜单退出场景:');
  139. menuController.onBackButtonClick();
  140. console.log('\n=== 事件触发分析 ===');
  141. const eventLog = eventBus.getEventLog();
  142. eventLog.forEach((log, index) => {
  143. console.log(`${index + 1}. 事件: ${log.event}`);
  144. });
  145. console.log('\n=== 验证结果 ===');
  146. console.log(`GameEnd处理GAME_DEFEAT事件次数: ${gameEnd.defeatProcessed}`);
  147. console.log(`GameEnd显示动画次数: ${gameEnd.animationShown}`);
  148. // 分析事件
  149. const gameDefeatEvents = eventLog.filter(log => log.event === GameEvents.GAME_DEFEAT);
  150. const wallDestroyedEvents = eventLog.filter(log => log.event === GameEvents.WALL_DESTROYED);
  151. const gameResumeEvents = eventLog.filter(log => log.event === GameEvents.GAME_RESUME);
  152. console.log(`\n=== 事件统计 ===`);
  153. console.log(`GAME_DEFEAT事件数量: ${gameDefeatEvents.length}`);
  154. console.log(`WALL_DESTROYED事件数量: ${wallDestroyedEvents.length}`);
  155. console.log(`GAME_RESUME事件数量: ${gameResumeEvents.length}`);
  156. console.log(`\n=== 问题诊断 ===`);
  157. if (gameEnd.defeatProcessed === 2 && gameEnd.animationShown === 2) {
  158. console.log('✅ 两种失败场景都正确触发了GameEnd动画');
  159. } else {
  160. console.log('❌ 存在问题:某些失败场景没有正确触发GameEnd动画');
  161. console.log(` - 预期处理次数: 2, 实际处理次数: ${gameEnd.defeatProcessed}`);
  162. console.log(` - 预期动画次数: 2, 实际动画次数: ${gameEnd.animationShown}`);
  163. }
  164. if (gameDefeatEvents.length === 2) {
  165. console.log('✅ 两种场景都正确触发了GAME_DEFEAT事件');
  166. } else {
  167. console.log('❌ GAME_DEFEAT事件触发异常');
  168. }
  169. if (gameResumeEvents.length === 0) {
  170. console.log('✅ 没有事件冲突(无GAME_RESUME事件)');
  171. } else {
  172. console.log('❌ 存在事件冲突(检测到GAME_RESUME事件)');
  173. }
  174. }
  175. // 运行测试
  176. testBothDefeatScenarios();