1be2a5ebe0
**README 重写(+231 行)** - 参照 UnoGame 风格,包含完整项目说明 - 功能特性、三平台构建命令(Linux/macOS/Windows) - 操作指南表格、玩法说明 - 完整目录树、核心模块职责详述 - 场景跳转流程图、计时机制表 - 版本日志 v16 → v19 **功能移除** - 删除 MEMBER 场景(开发人员页面) - 移除菜单中"相关人员"按钮,退出按钮上移填补空位 - 删除 images/开发人员界面.jpg - 清理 Game.h / Game.cpp / UI.h 中相关代码
231 lines
8.0 KiB
Markdown
231 lines
8.0 KiB
Markdown
# 纸牌上的坦克大战
|
||
|
||
基于 C++17 + SDL2 的 2D 坦克对战游戏,支持三种难度、实时战斗与胜负判定。
|
||
|
||
## 功能特性
|
||
|
||
- **3 档难度**:简单(HP 5 / ATK 1)、中等(HP 10 / ATK 2)、困难(HP 15 / ATK 3)
|
||
- **实时坦克对战**:WASD 移动 + 空格开火,敌人 AI 随机移动与射击
|
||
- **战场交互**:撞子弹扣血、踩残骸回血 + 提升攻击力、墙壁阻挡
|
||
- **胜负判定**:消灭全部 10 辆敌方坦克获胜,HP 归零失败
|
||
- **背景音乐**:循环 BGM 播放(静音自动降级)
|
||
- **跨平台**:Linux / Windows / macOS,CMake 一键构建
|
||
|
||
---
|
||
|
||
## 开发环境
|
||
|
||
| 依赖 | 版本要求 |
|
||
|------|----------|
|
||
| C++ | 17+ |
|
||
| CMake | 3.10+ |
|
||
| SDL2 | 2.x |
|
||
| SDL2_image | 2.x |
|
||
| SDL2_mixer | 2.x |
|
||
| SDL2_ttf | 2.x |
|
||
| 中文字体 | wqy-microhei 或 noto-cjk(用于界面文本渲染) |
|
||
|
||
### Linux
|
||
|
||
```bash
|
||
# Ubuntu / Debian
|
||
sudo apt install build-essential cmake \
|
||
libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev \
|
||
fonts-wqy-microhei
|
||
|
||
# Fedora
|
||
sudo dnf install gcc-c++ cmake \
|
||
SDL2-devel SDL2_image-devel SDL2_mixer-devel SDL2_ttf-devel \
|
||
wqy-microhei-fonts
|
||
|
||
# 构建
|
||
cmake -B build
|
||
cmake --build build
|
||
./build/tank_battles_on_the_scrap_paper
|
||
```
|
||
|
||
### macOS
|
||
|
||
```bash
|
||
brew install cmake sdl2 sdl2_image sdl2_mixer sdl2_ttf
|
||
cmake -B build
|
||
cmake --build build
|
||
./build/tank_battles_on_the_scrap_paper
|
||
```
|
||
|
||
### Windows
|
||
|
||
```powershell
|
||
# 1. 安装 CMake(https://cmake.org/download)
|
||
# 2. 安装 vcpkg 并安装 SDL2 依赖:
|
||
vcpkg install sdl2 sdl2-image sdl2-mixer sdl2-ttf
|
||
|
||
# 构建
|
||
cmake -B build -DCMAKE_TOOLCHAIN_FILE=<vcpkg-root>/scripts/buildsystems/vcpkg.cmake
|
||
cmake --build build
|
||
.\build\Release\tank_battles_on_the_scrap_paper.exe
|
||
```
|
||
|
||
---
|
||
|
||
## 操作指南
|
||
|
||
| 按键 | 功能 |
|
||
|------|------|
|
||
| W / ↑ | 向上移动 |
|
||
| S / ↓ | 向下移动 |
|
||
| A / ← | 向左移动 |
|
||
| D / → | 向右移动 |
|
||
| 空格 | 发射子弹 |
|
||
| ESC | 返回主菜单 |
|
||
|
||
鼠标左键点击按钮进行菜单导航。
|
||
|
||
---
|
||
|
||
## 玩法说明
|
||
|
||
1. 主菜单选择**开始游戏**(使用当前难度设置)或**难度设置**
|
||
2. 操控红色坦克在 20×20 地图中移动、射击敌方蓝色坦克
|
||
3. 踩到敌方坦克残骸(`is_taken`)可 +1 HP(上限 5)并 +1 攻击力
|
||
4. 撞到敌方子弹扣 1 HP
|
||
5. 击败全部 10 辆敌方坦克即**胜利**;玩家 HP 归零则**失败**
|
||
6. 子弹射到墙壁消失;敌方子弹射到玩家扣 HP 并消失
|
||
|
||
---
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
tank_battles_on_the_scrap_paper/
|
||
├── CMakeLists.txt # CMake 构建配置
|
||
├── README.md
|
||
├── tank_battles_on_the_scrap_paper/
|
||
│ ├── main.cpp # 入口:创建 Game 实例,调用 run()
|
||
│ ├── data_config.h # 全局常量(网格大小、数量上限、枚举)
|
||
│ ├── images/ # 58 张 PNG/JPG 素材
|
||
│ ├── music/ # 背景音乐 bgm.wav
|
||
│ └── src/
|
||
│ ├── Game.h / Game.cpp # 状态机主循环 + 游戏逻辑
|
||
│ ├── AssetManager.h / .cpp # 纹理 / 字体 / BGM 加载与缓存
|
||
│ ├── Renderer.h / .cpp # SDL 渲染封装
|
||
│ ├── Map.h / .cpp # 地图数据 + 碰撞检测
|
||
│ ├── Tank.h / .cpp # 坦克实体
|
||
│ ├── Bullet.h / .cpp # 子弹实体
|
||
│ └── UI.h # 界面按钮区域常量
|
||
└── .gitignore
|
||
```
|
||
|
||
`images/` 与 `music/` 在 CMake 构建时自动拷贝到 `build/` 目录,游戏通过 `SDL_GetBasePath()` 自动定位可执行文件所在目录加载资源。
|
||
|
||
---
|
||
|
||
## 核心模块
|
||
|
||
### `Game` — 状态机主循环
|
||
|
||
| 职责 | 说明 |
|
||
|------|------|
|
||
| 场景管理 | `enum class Scene { MENU, LEVEL, GAME, WIN, LOSE, QUIT }` 驱动主循环,彻底消除旧版递归函数跳转导致的栈溢出隐患 |
|
||
| 事件分发 | `handleEvents()` 统一处理 SDL 事件(退出 / ESC / 鼠标点击),根据当前场景路由到不同按钮命中检测 |
|
||
| 更新循环 | `updateGame()` 每帧执行:玩家输入 → 玩家移动 / 射击 → 敌人 AI 移动 / 射击 → 子弹移动与碰撞 → 地图同步 |
|
||
| 渲染调度 | `renderScene()` 根据场景调用对应渲染函数 |
|
||
|
||
**场景跳转流程**:
|
||
|
||
```
|
||
MENU ──开始游戏──→ GAME ──胜利──→ WIN ──返回──→ MENU
|
||
│ │ │
|
||
├──难度设置──→ LEVEL │ │
|
||
│ │ └──失败──→ LOSE ──返回──┘
|
||
│ └──返回──→ MENU
|
||
└──退出游戏──→ 退出
|
||
```
|
||
|
||
### `Map` — 地图与碰撞
|
||
|
||
| 方法 | 职责 |
|
||
|------|------|
|
||
| `reset()` | 初始化 20×20 网格:四周为 `WALL`,内部为 `BLANK` |
|
||
| `get(x, y)` | 返回指定坐标的 `CELL_Type` 枚举值 |
|
||
| `set(x, y, type)` | 写入单元,每帧同步坦克位置 |
|
||
| `peek(x, y, dir)` | 查看某方向前方一格的内容,供坦克和子弹碰撞检测 |
|
||
|
||
### `Tank` — 坦克实体
|
||
|
||
| 属性 | 说明 |
|
||
|------|------|
|
||
| `x, y` | 网格坐标 |
|
||
| `hp` | 生命值(玩家默认 5,敌人由难度决定) |
|
||
| `attack` | 攻击力(决定子弹伤害) |
|
||
| `dir` | 方向(`UP/DOWN/LEFT/RIGHT`) |
|
||
| `isTaken` | 仅敌方:残骸是否已被玩家拾取 |
|
||
|
||
方向向量 `dx(dir)` / `dy(dir)` 统一处理四方向位移,消除旧版中 4 份复制粘贴的 switch 逻辑。
|
||
|
||
### `Bullet` — 子弹实体
|
||
|
||
| 方法 | 职责 |
|
||
|------|------|
|
||
| `fire(x, y, dir, dmg)` | 初始化子弹(位置、方向、伤害值) |
|
||
| `peekAt(map)` | 检测前方一格的地图单元类型 |
|
||
| `step()` | 向前移动一格 |
|
||
| `isLive` | 是否存活(碰墙/命中后置 `false`) |
|
||
|
||
玩家子弹命中 `BLUE_TANK` 时遍历敌人数组扣血;敌方子弹命中 `RED_TANK` 时直接扣玩家 HP。子弹碰 `WALL` 立即消失。
|
||
|
||
### `AssetManager` — 资源管理
|
||
|
||
- **纹理缓存**:`std::unordered_map<string, SDL_Texture*>` 按路径缓存,避免重复加载
|
||
- **字体加载**:`TTF_OpenFont()` 带多路径回退(wqy-microhei → wqy-zenhei → noto-cjk)
|
||
- **BGM 管理**:`Mix_LoadMUS()` + `Mix_PlayMusic(-1)` 循环播放,失败静默降级
|
||
- **生命周期**:析构时自动释放全部纹理、字体、音频资源
|
||
|
||
### `Renderer` — 渲染封装
|
||
|
||
| 方法 | 职责 |
|
||
|------|------|
|
||
| `clear()` | 填充黑色背景 |
|
||
| `present()` | 提交帧缓冲区到屏幕 |
|
||
| `drawTexture()` | 渲染纹理到指定矩形区域 |
|
||
| `drawImage()` | 加载图片并渲染(通过 AssetManager 缓存) |
|
||
| `drawText()` | TTF 文字渲染(UTF-8 编码,`SDL_RenderCopy` 绘制) |
|
||
| `drawInt()` | 整数值渲染(`std::to_string` 后调用 `drawText`) |
|
||
|
||
### `UI` — 界面常量
|
||
|
||
| 常量 | 用途 |
|
||
|------|------|
|
||
| `BTN_START` | 开始游戏按钮区域 {50, 250, 150, 50} |
|
||
| `BTN_LEVEL` | 难度设置按钮区域 {50, 330, 150, 50} |
|
||
| `BTN_QUIT` | 退出游戏按钮区域 {50, 410, 150, 50} |
|
||
| `BTN_EASY/MEDIUM/HARD` | 难度选择按钮区域 |
|
||
| `BTN_BACK` | 返回按钮区域 {30, 550, 150, 50} |
|
||
| `hit(rect, mx, my)` | 鼠标命中检测辅助函数 |
|
||
|
||
---
|
||
|
||
## 计时机制
|
||
|
||
游戏使用 `SDL_GetTicks()` 替代跨平台不一致的 `clock()`,各逻辑模块以毫秒为间隔独立刷新:
|
||
|
||
| 模块 | 间隔 | 说明 |
|
||
|------|------|------|
|
||
| 玩家移动 | 100 ms | 按住方向键连续移动 |
|
||
| 玩家射击 | 500 ms | 按住空格连续发射 |
|
||
| 敌人移动 | 1000 ms | 随机方向移动 |
|
||
| 敌人射击 | 3000 ms | 每个存活敌人发射一发 |
|
||
| 玩家子弹 | 100 ms | 逐格前进 |
|
||
| 敌方子弹 | 500 ms | 逐格前进 |
|
||
|
||
---
|
||
|
||
## 版本日志
|
||
|
||
| 版本 | 变更 |
|
||
|------|------|
|
||
| v19 | 全面重构:1468 行单文件拆分为 8 个模块,状态机替代递归,全局变量清零,方向向量消除 4x 复制粘贴,修复 EnemiesMove 循环变量遮蔽 bug |
|
||
| v18 | 从 Windows/EasyX 迁移到 SDL2,支持跨平台;修复启动黑屏(`SDL_GetBasePath` 自动定位资源目录) |
|
||
| v17 | 修复返回菜单后 `InitMap()` 未调用导致地图脏数据 |
|
||
| v16 | 添加全局 BGM 背景音乐循环播放 |
|