test_realtime_gameend_debug.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /**
  2. * 实时GameEnd调试脚本
  3. * 模拟实际游戏环境,检查墙体血量为0时GameEnd的显示问题
  4. */
  5. // 模拟GameEvents
  6. const GameEvents = {
  7. GAME_DEFEAT: 'GAME_DEFEAT',
  8. GAME_RESUME: 'GAME_RESUME',
  9. RESET_UI_STATES: 'RESET_UI_STATES'
  10. };
  11. // 模拟EventBus
  12. class MockEventBus {
  13. constructor() {
  14. this.listeners = new Map();
  15. }
  16. on(event, callback, context) {
  17. if (!this.listeners.has(event)) {
  18. this.listeners.set(event, []);
  19. }
  20. this.listeners.get(event).push({ callback, context });
  21. }
  22. emit(event, ...args) {
  23. console.log(`[EventBus] 触发事件: ${event}`);
  24. if (this.listeners.has(event)) {
  25. this.listeners.get(event).forEach(({ callback, context }) => {
  26. callback.call(context, ...args);
  27. });
  28. }
  29. }
  30. off(event, callback, context) {
  31. if (this.listeners.has(event)) {
  32. const listeners = this.listeners.get(event);
  33. const index = listeners.findIndex(l => l.callback === callback && l.context === context);
  34. if (index !== -1) {
  35. listeners.splice(index, 1);
  36. }
  37. }
  38. }
  39. }
  40. // 模拟UIOpacity组件
  41. class MockUIOpacity {
  42. constructor() {
  43. this.opacity = 255;
  44. }
  45. }
  46. // 模拟Node
  47. class MockNode {
  48. constructor(name, siblingIndex = 0) {
  49. this.name = name;
  50. this.active = true;
  51. this.siblingIndex = siblingIndex;
  52. this.scale = { x: 1, y: 1, z: 1 };
  53. this.position = { x: 0, y: 0, z: 0 };
  54. this.children = [];
  55. this.parent = null;
  56. this.components = new Map();
  57. }
  58. setScale(x, y, z) {
  59. this.scale = { x, y, z };
  60. }
  61. setPosition(x, y, z) {
  62. this.position = { x, y, z };
  63. }
  64. getComponent(componentClass) {
  65. return this.components.get(componentClass);
  66. }
  67. addComponent(componentClass) {
  68. const component = new componentClass();
  69. this.components.set(componentClass, component);
  70. return component;
  71. }
  72. getSiblingIndex() {
  73. return this.siblingIndex;
  74. }
  75. setSiblingIndex(index) {
  76. this.siblingIndex = index;
  77. }
  78. getNodeStatus() {
  79. return {
  80. name: this.name,
  81. active: this.active,
  82. siblingIndex: this.siblingIndex,
  83. scale: this.scale,
  84. position: this.position,
  85. opacity: this.getComponent(MockUIOpacity)?.opacity || 'N/A'
  86. };
  87. }
  88. }
  89. // 模拟GameEnd组件(重点关注实际问题)
  90. class MockGameEnd {
  91. constructor(eventBus) {
  92. this.eventBus = eventBus;
  93. this.node = new MockNode('GameEnd', 2);
  94. this.animationDuration = 0.3; // 默认动画时长
  95. this.hasProcessedGameEnd = false;
  96. this.isVisible = false;
  97. this.animationCount = 0;
  98. this.debugMode = true;
  99. // 添加UIOpacity组件
  100. this.node.addComponent(MockUIOpacity);
  101. this.setupEventListeners();
  102. this.initializeHiddenStateKeepActive();
  103. }
  104. setupEventListeners() {
  105. console.log('[GameEnd] 设置事件监听器');
  106. this.eventBus.on(GameEvents.GAME_DEFEAT, this.onGameDefeat, this);
  107. this.eventBus.on(GameEvents.RESET_UI_STATES, this.onResetUI, this);
  108. }
  109. onGameDefeat() {
  110. console.log('\n=== GameEnd.onGameDefeat() 开始 ===');
  111. console.log('[GameEnd] 接收到GAME_DEFEAT事件');
  112. // 检查是否已处理过
  113. if (this.hasProcessedGameEnd) {
  114. console.log('[GameEnd] ⚠️ 已处理过游戏结束,跳过重复处理');
  115. return;
  116. }
  117. console.log('[GameEnd] 开始处理游戏失败逻辑');
  118. // 记录处理状态
  119. this.hasProcessedGameEnd = true;
  120. // 调试:检查节点状态
  121. if (this.debugMode) {
  122. console.log('[GameEnd] 🔍 调试信息 - 处理前节点状态:');
  123. console.log(' - 节点激活:', this.node.active);
  124. console.log(' - 节点层级:', this.node.siblingIndex);
  125. console.log(' - 节点缩放:', this.node.scale);
  126. console.log(' - 透明度:', this.node.getComponent(MockUIOpacity)?.opacity);
  127. console.log(' - 动画时长:', this.animationDuration);
  128. }
  129. // 显示结算面板
  130. this.showEndPanelWithAnimation();
  131. console.log('=== GameEnd.onGameDefeat() 结束 ===\n');
  132. }
  133. showEndPanelWithAnimation() {
  134. console.log('[GameEnd] 🎬 开始显示结算面板动画');
  135. // 调试:检查动画前状态
  136. if (this.debugMode) {
  137. console.log('[GameEnd] 🔍 动画前状态检查:');
  138. console.log(' - animationDuration:', this.animationDuration);
  139. console.log(' - 节点激活状态:', this.node.active);
  140. console.log(' - 当前透明度:', this.node.getComponent(MockUIOpacity)?.opacity);
  141. console.log(' - 当前缩放:', this.node.scale);
  142. }
  143. // 确保节点激活
  144. if (!this.node.active) {
  145. this.node.active = true;
  146. console.log('[GameEnd] ✅ 激活GameEnd节点');
  147. }
  148. // 检查动画配置
  149. if (this.animationDuration <= 0) {
  150. console.log('[GameEnd] ⚠️ 动画时长为0或负数,直接显示面板');
  151. this.directShow();
  152. return;
  153. }
  154. // 播放动画
  155. console.log(`[GameEnd] 🎭 开始播放动画,持续时间: ${this.animationDuration}秒`);
  156. this.playShowAnimation();
  157. this.animationCount++;
  158. this.isVisible = true;
  159. console.log('[GameEnd] ✅ 显示面板流程完成');
  160. }
  161. playShowAnimation() {
  162. console.log('[GameEnd] 🎯 执行显示动画');
  163. // 获取UIOpacity组件
  164. const uiOpacity = this.node.getComponent(MockUIOpacity);
  165. if (!uiOpacity) {
  166. console.error('[GameEnd] ❌ UIOpacity组件缺失!');
  167. return;
  168. }
  169. // 设置初始状态
  170. this.node.setScale(0.3, 0.3, 1);
  171. uiOpacity.opacity = 0;
  172. console.log('[GameEnd] 🎬 设置动画初始状态 - 缩放: 0.3, 透明度: 0');
  173. // 模拟动画执行
  174. setTimeout(() => {
  175. this.node.setScale(1, 1, 1);
  176. uiOpacity.opacity = 255;
  177. console.log('[GameEnd] ✨ 动画完成 - 缩放: 1, 透明度: 255');
  178. // 调试:检查最终状态
  179. if (this.debugMode) {
  180. console.log('[GameEnd] 🔍 动画完成后最终状态:');
  181. console.log(' - 节点激活:', this.node.active);
  182. console.log(' - 节点缩放:', this.node.scale);
  183. console.log(' - 透明度:', uiOpacity.opacity);
  184. console.log(' - 是否可见:', this.isVisible);
  185. }
  186. }, this.animationDuration * 1000);
  187. }
  188. directShow() {
  189. console.log('[GameEnd] 🚀 直接显示面板(无动画)');
  190. this.node.setScale(1, 1, 1);
  191. const uiOpacity = this.node.getComponent(MockUIOpacity);
  192. if (uiOpacity) {
  193. uiOpacity.opacity = 255;
  194. }
  195. this.isVisible = true;
  196. console.log('[GameEnd] ✅ 直接显示完成');
  197. }
  198. initializeHiddenStateKeepActive() {
  199. const uiOpacity = this.node.getComponent(MockUIOpacity) || this.node.addComponent(MockUIOpacity);
  200. uiOpacity.opacity = 0;
  201. this.node.setScale(0.3, 0.3, 1);
  202. console.log('[GameEnd] 🔧 初始化为隐藏状态(保持激活)');
  203. }
  204. onResetUI() {
  205. console.log('[GameEnd] 🔄 重置UI状态');
  206. this.hasProcessedGameEnd = false;
  207. this.isVisible = false;
  208. this.node.active = false;
  209. }
  210. getStatus() {
  211. return {
  212. animationCount: this.animationCount,
  213. isVisible: this.isVisible,
  214. hasProcessedGameEnd: this.hasProcessedGameEnd,
  215. nodeStatus: this.node.getNodeStatus()
  216. };
  217. }
  218. }
  219. // 模拟Wall组件
  220. class MockWall {
  221. constructor(eventBus) {
  222. this.eventBus = eventBus;
  223. this.currentHealth = 100;
  224. this.maxHealth = 100;
  225. }
  226. takeDamage(damage) {
  227. this.currentHealth -= damage;
  228. console.log(`[Wall] 受到伤害: ${damage}, 剩余血量: ${this.currentHealth}`);
  229. if (this.currentHealth <= 0) {
  230. this.onWallDestroyed();
  231. }
  232. }
  233. onWallDestroyed() {
  234. console.log('\n🧱 [Wall] 墙体被摧毁!');
  235. console.log('[Wall] 即将触发GAME_DEFEAT事件');
  236. // 触发游戏失败事件
  237. this.eventBus.emit(GameEvents.GAME_DEFEAT);
  238. console.log('[Wall] GAME_DEFEAT事件已触发\n');
  239. }
  240. }
  241. // 测试函数
  242. function testWallDefeatGameEndDisplay() {
  243. console.log('\n🎮 === 墙体血量为0时GameEnd显示测试 ===\n');
  244. const eventBus = new MockEventBus();
  245. const gameEnd = new MockGameEnd(eventBus);
  246. const wall = new MockWall(eventBus);
  247. console.log('📋 初始状态:');
  248. console.log(' - GameEnd状态:', gameEnd.getStatus());
  249. console.log(' - Wall血量:', wall.currentHealth);
  250. console.log('\n🎯 开始测试:让墙体血量归零...');
  251. // 模拟墙体受到致命伤害
  252. wall.takeDamage(100);
  253. // 等待动画完成
  254. setTimeout(() => {
  255. console.log('\n📊 测试结果:');
  256. const finalStatus = gameEnd.getStatus();
  257. console.log(' - 动画执行次数:', finalStatus.animationCount);
  258. console.log(' - 面板是否可见:', finalStatus.isVisible);
  259. console.log(' - 是否已处理游戏结束:', finalStatus.hasProcessedGameEnd);
  260. console.log(' - 节点最终状态:', finalStatus.nodeStatus);
  261. // 判断测试结果
  262. const success = finalStatus.animationCount === 1 &&
  263. finalStatus.isVisible === true &&
  264. finalStatus.hasProcessedGameEnd === true &&
  265. finalStatus.nodeStatus.active === true &&
  266. finalStatus.nodeStatus.opacity === 255;
  267. console.log('\n🏆 测试结论:', success ? '✅ 成功' : '❌ 失败');
  268. if (success) {
  269. console.log('🎉 墙体血量为0时GameEnd动画正常显示!');
  270. } else {
  271. console.log('⚠️ 墙体血量为0时GameEnd动画显示异常!');
  272. console.log('🔍 可能的问题:');
  273. if (finalStatus.animationCount === 0) {
  274. console.log(' - 动画未执行:可能是事件监听器未正确注册');
  275. }
  276. if (!finalStatus.isVisible) {
  277. console.log(' - 面板不可见:可能是动画执行失败或被其他UI遮挡');
  278. }
  279. if (!finalStatus.hasProcessedGameEnd) {
  280. console.log(' - 未处理游戏结束:可能是onGameDefeat方法未被调用');
  281. }
  282. if (!finalStatus.nodeStatus.active) {
  283. console.log(' - 节点未激活:可能是节点状态被意外修改');
  284. }
  285. if (finalStatus.nodeStatus.opacity !== 255) {
  286. console.log(' - 透明度异常:可能是动画未正确执行或被重置');
  287. }
  288. }
  289. return success;
  290. }, 500); // 等待动画完成
  291. }
  292. // 对比测试:菜单退出vs墙体血量为0
  293. function compareDefeatScenarios() {
  294. console.log('\n🔄 === 对比测试:菜单退出 vs 墙体血量为0 ===\n');
  295. // 测试1:菜单退出
  296. console.log('📱 测试1:菜单退出触发GAME_DEFEAT');
  297. const eventBus1 = new MockEventBus();
  298. const gameEnd1 = new MockGameEnd(eventBus1);
  299. eventBus1.emit(GameEvents.GAME_DEFEAT); // 直接触发
  300. setTimeout(() => {
  301. const status1 = gameEnd1.getStatus();
  302. console.log(' 结果:', status1.isVisible ? '✅ 显示正常' : '❌ 显示异常');
  303. // 测试2:墙体血量为0
  304. console.log('\n🧱 测试2:墙体血量为0触发GAME_DEFEAT');
  305. const eventBus2 = new MockEventBus();
  306. const gameEnd2 = new MockGameEnd(eventBus2);
  307. const wall2 = new MockWall(eventBus2);
  308. wall2.takeDamage(100); // 通过Wall组件触发
  309. setTimeout(() => {
  310. const status2 = gameEnd2.getStatus();
  311. console.log(' 结果:', status2.isVisible ? '✅ 显示正常' : '❌ 显示异常');
  312. // 对比结果
  313. console.log('\n📊 对比结果:');
  314. console.log(' 菜单退出 - 动画次数:', status1.animationCount, '可见性:', status1.isVisible);
  315. console.log(' 墙体血量0 - 动画次数:', status2.animationCount, '可见性:', status2.isVisible);
  316. const consistent = status1.isVisible === status2.isVisible &&
  317. status1.animationCount === status2.animationCount;
  318. console.log('\n🎯 一致性检查:', consistent ? '✅ 一致' : '❌ 不一致');
  319. if (!consistent) {
  320. console.log('⚠️ 发现不一致!这可能解释了为什么墙体血量为0时动画不显示。');
  321. console.log('🔍 建议检查:');
  322. console.log(' 1. Wall组件的事件触发时机');
  323. console.log(' 2. EventBus实例是否一致');
  324. console.log(' 3. 是否有其他组件在Wall触发事件后干扰GameEnd');
  325. }
  326. }, 500);
  327. }, 500);
  328. }
  329. // 运行测试
  330. console.log('🚀 开始实时GameEnd调试测试...');
  331. testWallDefeatGameEndDisplay();
  332. setTimeout(() => {
  333. compareDefeatScenarios();
  334. }, 1500);
  335. console.log('\n💡 如果测试显示正常但实际游戏仍有问题,请检查:');
  336. console.log(' 1. Cocos Creator编辑器中GameEnd节点的animationDuration属性');
  337. console.log(' 2. GameEnd节点在Canvas中的层级位置(siblingIndex)');
  338. console.log(' 3. 是否有其他UI组件在运行时修改GameEnd节点状态');
  339. console.log(' 4. EventBus实例在实际游戏中是否一致');
  340. console.log(' 5. 动画系统在实际环境中的表现');