🔷 第十六章 坦克动荡游戏
📄 一句话概括

《坦克动荡》是一个实时对战小游戏:迷宫地图里两台坦克互相攻击,子弹撞墙会反弹, 而反弹回来的子弹照样能打爆自己 —— 这就是"动荡"两个字的由来。 本章是全书的收尾项目:前面十五章学的是零件,这一章要把它们装成一台能跑起来的机器。

📝 本节和前面几节的关系

第十五章解决的是「数据怎么活过这一次运行」(文件),本章解决的是「这些东西怎么动起来、怎么被看见」。 本章是一章合并结算课,把前面几乎所有的账都结一遍: - 10~11 章(类与对象、继承与多态)→ 游戏对象体系(坦克、子弹、地图都是一种"对象"); - 12~13 章(模板与 STL)→ 用 vector 装一堆对象、用算法做碰撞检测; - 14 章(RTTI 与异常)→ 出错时不让游戏直接崩掉; - 15 章(文件操作)→ 读地图、存成绩、加载素材。 一句话:本章不教新语法,只教「怎么把学过的用在一起」。

一、这是一个什么游戏

《坦克动荡》(Tank Trouble)的规则,五句话能说完:

  1. 一张迷宫地图 —— 由"墙"和"空地"组成的格子阵;
  2. 两台坦克 —— 一个玩家控制一台(也可以人机对战、双人对战);
  3. 坦克能移动、能转向 —— 而且不是只走上下左右四方向,是任意角度自由开;
  4. 炮弹撞墙会反弹 —— 弹一次、两次、很多次都行;
  5. 谁被打中谁出局 —— 而打中你的,很可能是你自己反弹回来的那一发。

第 5 条是这个游戏和"坦克大战"最大的区别:

传统坦克大战 坦克动荡
移动方向 上 / 下 / 左 / 右 四方向 任意角度
子弹 打墙就消失 打墙会反弹
最刺激的地方 抢老家、守基地 算好角度 —— 因为乱开枪会打死自己

"算角度"就是这个游戏的核心乐趣 —— 地图越复杂、能反弹的路线越多,玩起来越像打台球。

二、为什么拿它当收尾项目

它是整本书里知识覆盖面最广的一个例子:

你会用到的 来自哪几章 在这个游戏里干什么
类与对象 10 章 把坦克、子弹、地图都封装成"类"
继承与多态 11 章 坦克、子弹都是"可移动对象"的子类
虚函数 11.4 让"移动""绘制"各自表现不同
vector 13.1 装一堆子弹(子弹会越打越多)
排序 / 查找 13.3 自动寻路时挑"走得最近的那一步"
文件操作 15 章 存地图文件、读图片素材
异常处理 14.2 图片加载失败时不崩、给个提示

一句话:它不是"又一个例子",而是"一次结业考"。

三、开工前要知道的三件事(尤其第一件)

第 1 件:这次要换工具了

本书前面十五章一直用 Dev-C++(写控制台程序)。本章必须换到 Visual Studio —— 因为:

不是 Dev-C++ 不好,而是它面向控制台,写窗口程序不合适。工具要跟着任务换。

本节后面第五部分会手把手把 Visual Studio 装上,并跑出第一个窗口。

第 2 件:本章要用的三样东西

东西 一句话说明 负责什么
Windows API 操作系统提供的一套 C 函数 建窗口、收鼠标键盘、开定时器
GDI+ Windows 的绘图层 画线、画图、贴图片
C++ 标准库 你已经学的那些 组织对象、装容器、读写文件

前两样是新面孔,第三样是你的老朋友。 本章的新知识,九成都在前两样上。

第 3 件:思路比代码重要

本章代码量比前面任何一章都大,但真正要带走的是三个思路:

  1. 游戏循环 —— 程序不再是"从上到下跑一遍就结束",而是每秒重复几十次;
  2. 对象分工 —— 谁负责画、谁负责动、谁负责算碰撞;
  3. 状态管理 —— 菜单、游戏中、结算,同一个窗口在不同状态下做不同的事。

这三件事想清楚了,代码是水到渠成;想不清楚,代码抄下来也改不动。

四、本章的八节怎么走

节 干什么 一句话
16.1 开发背景 做什么、为什么、用什么(就是本节)
16.2 系统功能设计 先把功能列清楚、把流程画出来,再动手
16.3 创建项目 建工程、备素材、把空窗口跑起来
16.4 创建游戏框架 窗口 + 游戏循环 + 鼠标响应
16.5 绘图库 GDI+ 的使用 学会"往屏幕上画东西"
16.6 游戏功能的详细设计 坦克、子弹、地图、碰撞、寻路
16.7 实现完整的游戏 把所有零件装进一个 CGame 类
16.8 本章总结 收账 + 全书收官

注意顺序:先设计(16.2)再动手(16.3 起) —— 这是本章想教的第一条工程习惯。

五、动手 Demo:把"黑框框"换成"窗口"

第 1 步:装 Visual Studio

  1. 到微软官网下载 Visual Studio Community(社区版,免费);
  2. 安装时在"工作负载"里勾上「使用 C++ 的桌面开发」 —— 这一项必须勾,否则后面建不了 C++ 项目;
  3. 装完打开,确认能看到"创建新项目"。

第 2 步:跑一个最小的窗口程序

新建 → 选 Windows 桌面应用程序(语言 C++ / 平台 Windows / 类型 桌面)→ 项目名填 TankTurmoil。

把生成代码里的消息处理函数 WndProc 改一处,让它往窗口上画一行字:

// 消息处理函数:系统把"窗口需要重画"的消息发到这里
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_PAINT: {                        // 系统说:这块地方要重画了
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);    // 开始画
        // 先用 GDI 的"画字"函数试水(16.5 会换成 GDI+)
        TextOut(hdc, 20, 20, L"坦克动荡 · 窗口已就绪", 11);
        EndPaint(hWnd, &ps);                // 画完了
        return 0;
    }
    case WM_DESTROY:                        // 窗口被关掉
        PostQuitMessage(0);                 // 让消息循环退出 → 程序结束
        return 0;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);   // 其余消息交给系统默认处理
}

看到什么算成功:

读结果:

六、30 秒实验

  1. 把 TextOut 那一行注释掉再跑 → 窗口还在,但一片空白。说明"窗口存在"和"窗口上有内容"是两件事。
  2. 把 WM_DESTROY 分支整段注释掉再跑 → 关掉窗口后,任务管理器里还能看到进程。这就是"消息循环没退出"。
  3. 把窗口样式里的 WS_OVERLAPPEDWINDOW 换成只带 WS_BORDER → 窗口不能改大小、没有最大化按钮。体会"窗口样式"就是一堆选项按位或起来(和 15.1.3 的位标志一个套路)。

七、常见误区

  1. "我 Dev-C++ 用得挺熟,本章也能用" —— 不行。Dev-C++ 面向控制台,本章要窗口和 GDI+,请用 Visual Studio。工具跟着任务换,不是工具不好。
  2. "窗口程序就是 main 里一路 cout" —— 不是。窗口程序的核心是消息循环:程序不"从头跑到尾",而是等系统发消息、你处理消息。
  3. "照着抄完代码就算学会了" —— 不算。本节第三部分那三个思路(游戏循环、对象分工、状态管理)才是要带走的;代码只是它们的载体。
  4. "应该先把坦克、子弹都写出来再调试" —— 反过来。本章顺序是先设计 → 再建框架 → 再画图 → 最后堆功能。一次只让一个新东西动起来。
  5. "游戏和普通程序是两个世界" —— 不是。底子还是你学过的:类、继承、容器、文件 —— 只不过外面套了一层"窗口"的壳。
自测三问(点开对答案) 1. **《坦克动荡》和传统坦克大战最大的区别是什么?** —— **子弹打墙会反弹,反弹的子弹能打到自己**;而且**坦克可以任意角度移动**,不是四方向。**"算角度"成了核心玩法。** 2. **为什么这一章必须从 Dev-C++ 换成 Visual Studio?** —— **因为本章要写窗口程序**(需要 Windows API 和 GDI+),**而 Dev-C++ 面向控制台,不适合**。**工具要跟着任务换。** 3. **本章真正要学的三个"思路"是什么?** —— **① 游戏循环**(每秒重复几十次);**② 对象分工**(谁画、谁动、谁算碰撞);**③ 状态管理**(菜单 / 游戏中 / 结算,同一窗口做不同事)。

相关笔记