# 战斗系统输入处理修复 ## 🐛 问题描述 ### 症状1:战斗中输入被错误处理 ``` >>> 你的回合 <<< 【战斗】> attack 无效选项。请输入1-5。 ❌ 错误:被大厅菜单处理器处理 ``` ### 症状2:不断显示战斗菜单 ``` 【战斗】> 1 ================================ 战斗中 ================================ 等待你的回合... ================================ 【战斗】> 2 ================================ 战斗中 ================================ 等待你的回合... ``` ### 症状3:连接崩溃 ``` terminate called without an active exception Aborted ``` ## 🔍 根本原因 ### 主循环逻辑问题 **修复前的代码**: ```cpp while (m_isRunning && m_isConnected) { if (!m_isAuthenticated) { showMainMenu(); } else if (m_inBattle) { showBattleMenu(); // ❌ 不管是否轮到玩家都调用 } else { showLobbyMenu(); } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } ``` **问题分析**: 1. 当 `m_inBattle = true` 但 `m_waitingForTurn = false` 时 2. `showBattleMenu()` 被调用 → 等待输入 3. 用户输入后,`handleBattleInput()` 检查 `!m_waitingForTurn` 直接返回 4. 循环继续,100ms 后再次调用 `showBattleMenu()` 5. **无限显示菜单** ### 状态机混乱 战斗有三个状态: - 未认证 → 显示主菜单 - 在大厅 → 显示大厅菜单 - 在战斗中 - **轮到玩家** → 显示战斗菜单,接受输入 - **不是玩家回合** → 静默等待,不显示菜单 原来的代码只区分了前两个状态,导致第三个状态处理错误。 ## ✅ 修复方案 ### 1. 改进主循环逻辑 ```cpp void GameClient::run() { if (!connect()) { return; } while (m_isRunning && m_isConnected) { if (!m_isAuthenticated) { showMainMenu(); } else if (m_inBattle && m_waitingForTurn) { // ✓ 只在战斗中且轮到玩家时才显示战斗菜单 showBattleMenu(); } else if (!m_inBattle) { // ✓ 不在战斗中,显示大厅菜单 showLobbyMenu(); } else { // ✓ 在战斗中但不是玩家回合,静默等待 std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } } ``` **关键改进**: - 添加 `m_waitingForTurn` 检查 - 只在 `m_inBattle && m_waitingForTurn` 时显示战斗菜单 - 不是玩家回合时进入等待状态,不显示任何菜单 ### 2. 简化战斗菜单 ```cpp void GameClient::showBattleMenu() { printTitle("战斗中"); std::cout << "输入 'attack' 或 '攻击' 使用普通攻击" << std::endl; printSeparator(); std::string input; showPrompt(); std::getline(std::cin, input); handleBattleInput(input); } ``` **移除了不必要的检查**,因为主循环已经保证只在正确时机调用。 ### 3. 改进输入处理 ```cpp void GameClient::handleBattleInput(const std::string& input) { if (input.empty()) { return; } if (input == "attack" || input == "攻击") { std::string msg = Protocol::buildMessage(Protocol::C2S_BATTLE_ACTION, {"0", "opponent"}); sendMessage(msg); m_waitingForTurn = false; // 行动后设置为 false } else { std::cout << "无效命令。请输入 'attack' 或 '攻击'" << std::endl; } } ``` **关键点**: - 执行攻击后设置 `m_waitingForTurn = false` - 添加友好的错误提示 ## 📊 状态转换流程 ### 正确的战斗流程 ``` 1. 玩家A邀请玩家B ↓ 2. 玩家B接受邀请 ↓ 3. 服务器发送 S2C_BATTLE_START → m_inBattle = true ↓ 4. 服务器发送 S2C_BATTLE_TURN (YOUR_TURN) → m_waitingForTurn = true ↓ 5. 主循环检测到 (m_inBattle && m_waitingForTurn) → 调用 showBattleMenu() ↓ 6. 玩家输入 "attack" → handleBattleInput() 处理 → 发送 C2S_BATTLE_ACTION → m_waitingForTurn = false ↓ 7. 主循环检测到 (m_inBattle && !m_waitingForTurn) → 进入等待状态(不显示菜单) ↓ 8. 服务器处理回合,发送战斗日志 → 显示战斗结果 ↓ 9. 服务器发送 S2C_BATTLE_TURN (OPP_TURN) → 保持 m_waitingForTurn = false → 继续等待 ↓ 10. 对手行动完毕,服务器发送 S2C_BATTLE_TURN (YOUR_TURN) → m_waitingForTurn = true → 回到步骤 5 ``` ## 🧪 测试步骤 ### 步骤1:重启客户端 ```bash cd /mnt/e/50425/Documents/Github/OnlineRpg ./build/bin/client ``` ### 步骤2:登录两个玩家 - 终端1:玩家A登录 - 终端2:玩家B登录 ### 步骤3:发起战斗邀请 **玩家A**: ``` 【玩家A】> 3 目标玩家用户名:玩家B用户名 ``` **玩家B**: ``` *** 玩家A 邀请你战斗!*** 输入 'accept 玩家A' 接受,或 'reject 玩家A' 拒绝 【玩家B】> accept 玩家A ``` ### 步骤4:战斗测试 **预期行为**: ``` *** 战斗开始!*** 对手:玩家B(Mage) ==================== >>> 你的回合 <<< 输入 'attack' 使用普通攻击 ================================ 战斗中 ================================ 输入 'attack' 或 '攻击' 使用普通攻击 ================================ 【战斗】> attack ← 输入攻击命令 【战斗】玩家A HP:150 ← 显示战斗日志 【战斗】玩家A 使用 NormalAttack 攻击 玩家B,造成 15 点伤害! ← 自动进入等待状态,不显示菜单 >>> 对手的回合... 【战斗】玩家B HP:85 【战斗】玩家B 使用 Fireball 攻击 玩家A,造成 28 点伤害! >>> 你的回合 <<< ← 再次轮到玩家 ================================ 战斗中 ================================ 输入 'attack' 或 '攻击' 使用普通攻击 ================================ 【战斗】> attack ``` **成功标志**: - ✅ 输入 `attack` 后正确执行攻击 - ✅ 不是自己回合时不显示菜单 - ✅ 没有"无效选项。请输入1-5。"错误 - ✅ 战斗日志正常显示 - ✅ 连接保持稳定,不崩溃 ## 🔧 相关文件 - `src/client/GameClient.cpp` - 主要修复文件 - `src/client/GameClient.h` - 状态变量定义 - `include/common/Protocol.h` - 协议定义 ## 📈 后续优化建议 1. **添加更多技能选择** ``` 【战斗】> skill 可用技能: 0. 普通攻击 1. 强力打击 (消耗10MP) 2. 防御姿态 (消耗5MP) 选择技能编号: ``` 2. **显示双方状态** ``` 你:玩家A (Warrior) HP:122/150 MP:15/20 对手:玩家B (Mage) HP:85/100 MP:10/50 ``` 3. **战斗历史查看** ``` 【战斗】> history 第1回合:玩家A 使用 普通攻击 造成 15 伤害 第2回合:玩家B 使用 火球术 造成 28 伤害 第3回合:玩家A 使用 强力打击 造成 30 伤害 ``` 4. **逃跑选项** ``` 【战斗】> flee 你逃离了战斗! ``` ## ✨ 总结 修复了战斗系统的输入处理逻辑,通过改进主循环状态判断,确保: - 战斗菜单只在正确时机显示 - 输入被正确的处理器处理 - 不是玩家回合时静默等待 - 避免了菜单无限显示和连接崩溃问题 现在战斗系统应该能够正常工作了!