Files
OnlineRpg/战斗系统修复说明.md
2025-10-26 20:44:58 +08:00

291 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 战斗系统输入处理修复
## 🐛 问题描述
### 症状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战斗测试
**预期行为**
```
*** 战斗开始!***
对手玩家BMage
====================
>>> 你的回合 <<<
输入 '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
你逃离了战斗!
```
## ✨ 总结
修复了战斗系统的输入处理逻辑,通过改进主循环状态判断,确保:
- 战斗菜单只在正确时机显示
- 输入被正确的处理器处理
- 不是玩家回合时静默等待
- 避免了菜单无限显示和连接崩溃问题
现在战斗系统应该能够正常工作了!