/** * 综合失败场景测试 * 模拟实际游戏中的复杂情况,包括UI层级、其他组件干扰等 */ // 模拟事件系统 class MockEventBus { constructor() { this.listeners = new Map(); this.eventLog = []; } on(event, callback, context) { if (!this.listeners.has(event)) { this.listeners.set(event, []); } this.listeners.get(event).push({ callback, context }); console.log(`[EventBus] 注册事件监听器: ${event}`); } emit(event, ...args) { console.log(`[EventBus] 触发事件: ${event}`); this.eventLog.push({ event, timestamp: Date.now(), args }); if (this.listeners.has(event)) { const listeners = this.listeners.get(event); listeners.forEach(({ callback, context }) => { try { callback.call(context, ...args); } catch (error) { console.error(`[EventBus] 事件处理错误 ${event}:`, error); } }); } } off(event, callback, context) { if (this.listeners.has(event)) { const listeners = this.listeners.get(event); const index = listeners.findIndex(l => l.callback === callback && l.context === context); if (index !== -1) { listeners.splice(index, 1); console.log(`[EventBus] 移除事件监听器: ${event}`); } } } getEventLog() { return this.eventLog; } } // 模拟GameEvents const GameEvents = { GAME_DEFEAT: 'GAME_DEFEAT', GAME_RESUME: 'GAME_RESUME', GAME_START: 'GAME_START', RESET_UI_STATES: 'RESET_UI_STATES', CURRENCY_CHANGED: 'CURRENCY_CHANGED' }; // 模拟Wall组件 class MockWall { constructor(eventBus) { this.eventBus = eventBus; this.currentHealth = 100; this.maxHealth = 100; } takeDamage(damage) { console.log(`[Wall] 受到伤害: ${damage}, 当前血量: ${this.currentHealth}`); this.currentHealth -= damage; if (this.currentHealth <= 0) { console.log('[Wall] 墙体血量为0,调用onWallDestroyed'); this.onWallDestroyed(); } } onWallDestroyed() { console.log('[Wall] 墙体被摧毁,触发GAME_DEFEAT事件'); this.eventBus.emit(GameEvents.GAME_DEFEAT); } } // 模拟MenuController(修复后的版本) class MockMenuController { constructor(eventBus) { this.eventBus = eventBus; this.isMenuOpen = false; this.currentAppState = 'IN_GAME'; } async onBackButtonClick() { console.log('[MenuController] 返回按钮被点击'); if (this.currentAppState === 'IN_GAME') { console.log('[MenuController] 游戏中退出,触发GAME_DEFEAT事件显示游戏失败UI'); // 先触发游戏失败事件,让GameEnd面板显示 this.eventBus.emit(GameEvents.GAME_DEFEAT); // 关闭菜单(不触发GAME_RESUME事件,避免事件冲突) await this.closeMenuWithoutResume(); console.log('[MenuController] 菜单退出处理完成,已触发GAME_DEFEAT事件'); } } async closeMenuWithoutResume() { if (!this.isMenuOpen) return; this.isMenuOpen = false; console.log('[MenuController] 菜单已关闭(未触发游戏恢复)'); } } // 模拟GameEnd组件(完整版本) class MockGameEnd { constructor(eventBus) { this.eventBus = eventBus; this.animationCount = 0; this.isVisible = false; this.hasProcessedGameEnd = false; this.currentRewards = { money: -1, diamonds: -1 }; this.isGameSuccess = false; this.hasDoubledReward = false; this.setupEventListeners(); } setupEventListeners() { console.log('[GameEnd] 设置事件监听器'); this.eventBus.on(GameEvents.GAME_DEFEAT, this.onGameDefeat, this); this.eventBus.on(GameEvents.GAME_START, this.onGameStart, this); this.eventBus.on(GameEvents.RESET_UI_STATES, this.onResetUI, this); } onGameDefeat() { console.log('[GameEnd] 接收到GAME_DEFEAT事件'); console.log('[GameEnd] 游戏失败事件处理,开始统一处理流程'); this.isGameSuccess = false; this.calculateAndShowRewards(); } calculateAndShowRewards() { if (this.hasProcessedGameEnd) { console.log('[GameEnd] 游戏结束已处理过,跳过重复计算'); return; } this.hasProcessedGameEnd = true; console.log('[GameEnd] 计算和显示奖励'); // 模拟奖励计算 this.currentRewards = { money: 50, diamonds: 2 }; this.showEndPanelWithAnimation(); } showEndPanelWithAnimation() { console.log('[GameEnd] 开始显示结算面板动画'); this.animationCount++; this.isVisible = true; console.log(`[GameEnd] GameEnd面板弹出动画第${this.animationCount}次执行`); } onGameStart() { console.log('[GameEnd] 收到游戏开始事件,重置奖励显示'); this.currentRewards = { money: 0, diamonds: 0 }; this.hasProcessedGameEnd = false; this.hasDoubledReward = false; this.isGameSuccess = false; this.animationCount = 0; this.isVisible = false; } onResetUI() { console.log('[GameEnd] 重置UI状态'); // 重置所有状态,为下一局游戏做准备 this.hasDoubledReward = false; // 注意:不重置currentRewards,保持奖励显示直到下次游戏开始 this.isGameSuccess = false; this.hasProcessedGameEnd = false; console.log('[GameEnd] UI状态重置完成'); } getStatus() { return { animationCount: this.animationCount, isVisible: this.isVisible, hasProcessedGameEnd: this.hasProcessedGameEnd, currentRewards: { ...this.currentRewards }, isGameSuccess: this.isGameSuccess }; } } // 模拟UIStateManager class MockUIStateManager { constructor(eventBus) { this.eventBus = eventBus; this.setupEventListeners(); } setupEventListeners() { this.eventBus.on(GameEvents.RESET_UI_STATES, this.onResetUI, this); } onResetUI() { console.log('[UIStateManager] 接收到RESET_UI_STATES事件'); // 可能会影响其他UI组件 } } // 模拟GameManager class MockGameManager { constructor(eventBus) { this.eventBus = eventBus; this.gameState = 'PLAYING'; this.setupEventListeners(); } setupEventListeners() { this.eventBus.on(GameEvents.GAME_DEFEAT, this.onGameDefeat, this); } onGameDefeat() { console.log('[GameManager] 接收到GAME_DEFEAT事件'); this.gameState = 'DEFEAT'; console.log('[GameManager] 游戏状态切换为DEFEAT'); } onMainMenuClick() { console.log('[GameManager] 主菜单按钮被点击'); // 可能触发RESET_UI_STATES事件 this.eventBus.emit(GameEvents.RESET_UI_STATES); } } // 模拟MainUIController class MockMainUIController { constructor(eventBus) { this.eventBus = eventBus; this.setupEventListeners(); } setupEventListeners() { this.eventBus.on(GameEvents.CURRENCY_CHANGED, this.onCurrencyChanged, this); } onCurrencyChanged() { console.log('[MainUIController] 货币变化事件处理'); } onReturnToMainUI() { console.log('[MainUIController] 返回主界面'); this.eventBus.emit(GameEvents.CURRENCY_CHANGED); } } // 测试函数1:墙体血量为0场景 function testWallDefeatScenario() { console.log('\n=== 测试1:墙体血量为0失败场景 ==='); const eventBus = new MockEventBus(); const wall = new MockWall(eventBus); const gameEnd = new MockGameEnd(eventBus); const gameManager = new MockGameManager(eventBus); const uiStateManager = new MockUIStateManager(eventBus); const mainUIController = new MockMainUIController(eventBus); console.log('\n--- 初始状态 ---'); console.log('墙体血量:', wall.currentHealth); console.log('GameEnd状态:', gameEnd.getStatus()); console.log('\n--- 模拟墙体受到致命伤害 ---'); wall.takeDamage(100); console.log('\n--- 检查结果 ---'); const status = gameEnd.getStatus(); console.log('GameEnd状态:', status); return { scenario: 'wall_defeat', success: status.animationCount === 1 && status.isVisible, status: status, eventLog: eventBus.getEventLog() }; } // 测试函数2:菜单退出场景 function testMenuDefeatScenario() { console.log('\n=== 测试2:菜单退出失败场景 ==='); const eventBus = new MockEventBus(); const menuController = new MockMenuController(eventBus); const gameEnd = new MockGameEnd(eventBus); const gameManager = new MockGameManager(eventBus); const uiStateManager = new MockUIStateManager(eventBus); const mainUIController = new MockMainUIController(eventBus); console.log('\n--- 初始状态 ---'); console.log('GameEnd状态:', gameEnd.getStatus()); console.log('\n--- 模拟菜单退出 ---'); menuController.onBackButtonClick(); console.log('\n--- 检查结果 ---'); const status = gameEnd.getStatus(); console.log('GameEnd状态:', status); return { scenario: 'menu_defeat', success: status.animationCount === 1 && status.isVisible, status: status, eventLog: eventBus.getEventLog() }; } // 测试函数3:UI重置干扰场景 function testUIResetInterferenceScenario() { console.log('\n=== 测试3:UI重置干扰场景 ==='); const eventBus = new MockEventBus(); const wall = new MockWall(eventBus); const gameEnd = new MockGameEnd(eventBus); const gameManager = new MockGameManager(eventBus); const uiStateManager = new MockUIStateManager(eventBus); const mainUIController = new MockMainUIController(eventBus); console.log('\n--- 初始状态 ---'); console.log('GameEnd状态:', gameEnd.getStatus()); console.log('\n--- 模拟墙体血量为0 ---'); wall.takeDamage(100); console.log('\n--- 模拟UI重置事件干扰 ---'); gameManager.onMainMenuClick(); // 触发RESET_UI_STATES console.log('\n--- 检查结果 ---'); const status = gameEnd.getStatus(); console.log('GameEnd状态:', status); return { scenario: 'ui_reset_interference', success: status.animationCount === 1 && status.isVisible && status.currentRewards.money > 0, status: status, eventLog: eventBus.getEventLog() }; } // 运行所有测试 function runAllTests() { console.log('\n🧪 开始综合失败场景测试'); const results = []; // 测试1:墙体血量为0 results.push(testWallDefeatScenario()); // 测试2:菜单退出 results.push(testMenuDefeatScenario()); // 测试3:UI重置干扰 results.push(testUIResetInterferenceScenario()); console.log('\n=== 综合测试结果分析 ==='); results.forEach((result, index) => { console.log(`\n测试${index + 1} (${result.scenario}):`); console.log(' 测试通过:', result.success ? '✅' : '❌'); console.log(' 动画执行次数:', result.status.animationCount); console.log(' 面板可见性:', result.status.isVisible); console.log(' 奖励数据:', result.status.currentRewards); console.log(' 处理状态:', result.status.hasProcessedGameEnd); const defeatEvents = result.eventLog.filter(log => log.event === GameEvents.GAME_DEFEAT); const resumeEvents = result.eventLog.filter(log => log.event === GameEvents.GAME_RESUME); const resetEvents = result.eventLog.filter(log => log.event === GameEvents.RESET_UI_STATES); console.log(' GAME_DEFEAT事件:', defeatEvents.length); console.log(' GAME_RESUME事件:', resumeEvents.length); console.log(' RESET_UI_STATES事件:', resetEvents.length); }); const allPassed = results.every(r => r.success); console.log('\n=== 最终结果 ==='); if (allPassed) { console.log('🎉 所有测试通过!失败处理流程工作正常。'); } else { console.log('⚠️ 部分测试失败,需要进一步调试。'); const failedTests = results.filter(r => !r.success); console.log('失败的测试场景:'); failedTests.forEach(test => { console.log(` - ${test.scenario}`); }); } return { allPassed, results, summary: { total: results.length, passed: results.filter(r => r.success).length, failed: results.filter(r => !r.success).length } }; } // 运行测试 const testResults = runAllTests(); console.log('\n📊 测试统计:'); console.log('总测试数:', testResults.summary.total); console.log('通过数:', testResults.summary.passed); console.log('失败数:', testResults.summary.failed); console.log('通过率:', Math.round(testResults.summary.passed / testResults.summary.total * 100) + '%'); if (testResults.allPassed) { console.log('\n✨ 综合测试结论:失败处理流程已完全修复,两种失败场景都能正常工作!'); } else { console.log('\n🔍 需要进一步调试的问题:'); testResults.results.forEach(result => { if (!result.success) { console.log(` - ${result.scenario}: 动画${result.status.animationCount}次,可见${result.status.isVisible}`); } }); }