尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

C++小游戏实战:从猜数字到丧尸生存,串联高频语法考点

C++小游戏实战:从猜数字到丧尸生存,串联高频语法考点 “C常见小游戏12篇”这个系列是我把C入门最容易劝退的语法点全部绑到小游戏项目上的一次尝试。如果你正在学C或者学完基础语法但不知道能做什么又或者想找一套能顺便应付面试“八股”的实战练习这12篇应该能帮上忙。我不是写那种“复制粘贴就能跑”的玩具代码而是把每一个游戏背后真正值得讲的C特性——从随机数、排序、字符串初始化到const/static/final、结构体链表、回调函数、快速幂这些高频考点全部串进项目里边做边解释为什么这么写。这篇文章就把整套系列的核心思路、12个游戏的拆解、以及我在配置环境、调试报错时踩过的坑一次性讲清楚。1. 为什么是“12篇小游戏”而不是“一套大项目”很多教程喜欢一开始就让你做一个完整的“项目”但实际效果往往很差。新手拿到一个几百行的项目代码第一反应是“我是不是不行”因为里面混入了类、继承、多态、文件读写、图形库初始化什么都讲了又什么都没讲透。我选“12个小游戏”而不是“一个大项目”核心原因是每个小游戏只重点训练2到3个语法点难度一把一把地往上加。这样每一篇都能独立消化不会出现“学完第5章忘了第2章”的情况。而且游戏这东西天然适合做练习目标明确、反馈即时、状态边界清晰。你写一个猜数字跑起来几分钟就能验证逻辑对不对你写一个贪吃蛇方向控制写错了马上就能感觉到“蛇不走直线”这种即时反馈是纯算法练习题给不了的。另一个很现实的原因是面试。你看近几年C面试八股的高频词const、static、final、快速幂、单调栈、按位与、ABA问题、回调函数、链表、运算符优先级——这些单独背很枯燥但在游戏代码里它们都是“刚需”。比如怪物血量和伤害计算里用快速幂按键状态判断用按位与UI事件用回调函数背包系统用链表。12篇小游戏做完这些考点不是背下来的是写代码的时候自然用熟的。1.1 选题逻辑难度递进与语法点覆盖我按四条线来组织这12篇控制台热身级第1到3篇猜数字、数字华容道、打字反应测试。只需要main函数、循环、分支、数组目标是让人先跑起来。矩阵与状态类第4到6篇贪吃蛇、扫雷、2048。核心是二维数组建模、状态更新、碰撞检测开始接触“坐标思维”。地图与AI逻辑类第7到9篇推箱子、俄罗斯方块、井字棋/五子棋。地图建模、旋转数组、简单AI策略难度明显上一档。综合项目型第10到12篇迷宫生成与寻路、飞机大战、丧尸末日文字生存。把前面所有知识点串起来再加上链表、结构体、事件系统。每一篇我都给了一个难度系数和建议用时方便你按自己的水平跳着看。比如已经会写冒泡排序的人可以直接跳到第4篇贪吃蛇只学过C语言语法、没碰过C STL的人建议从头开始。1.2 这些游戏背后覆盖的知识点全景把这12篇做完你基本能覆盖这些高频考点随机数生成、冒泡排序与sort底层对比、字符串数组初始化、C风格数组与std::string/vector切换、const/static/final的用法边界、运算符优先级陷阱、结构体与链表、快速幂、单调栈、按位与、ABA问题、回调函数与std::function。这些我在第4章会单独挑出来细讲因为它们是面试里最容易翻车的点也是游戏代码里最常被“一笔带过”但实际很重要的部分。2. 环境准备VSCode配置C/C最容易翻车的几个细节开始写游戏之前环境得先折腾明白。很多新人卡在第一天不是不会写代码而是编译器没配好。我把VSCode配置C/C环境的过程拆开讲按这套配置基本不会出错。2.1 工具链选型MinGW-w64 还是 MSVC还是 ClangC没有官方IDE但它有官方标准。你用什么编译器主要看平台Windows VSCode主流选MinGW-w64g轻量、免费、调试用GDB社区资料多。缺点是MSVC专属的某些特性不支持但新手阶段完全够用。Windows Visual Studio用MSVC企业里最常见调试器很强但新建项目路径比较重不适合“随手写个小游戏”的快节奏。macOS 或 Linux自带Clang或GCCVSCode配置相对更简单launch.json里的调试器改成gdb或lldb即可。我建议你们学小游戏阶段统一用MinGW-w64 VSCode。原因有三启动快、配置透明、出问题容易搜到答案。等以后进公司或者做大型项目再换Visual Studio的MSVC也不迟编译器只是工具C标准是同一套。安装MinGW-w64时注意两个坑第一路径不要带空格不要装在C:\Program Files下面这会导致后续tasks.json和launch.json的命令解析出各种莫名其妙的问题第二安装后一定要把...\bin目录加进系统PATH否则你在终端里输入g --version会提示“不是内部或外部命令”。2.2 VSCode里那四个配置文件到底怎么填VSCode跑C需要四个文件tasks.json编译任务、launch.json调试配置、c_cpp_properties.jsonIntelliSense配置、settings.json编辑器设置。很多人在这一步直接复制网上的配置然后报错因为没搞懂每个字段什么意思。先说tasks.json。它本质上是告诉VSCode“按什么命令把源码变成可执行文件”。单文件编译最简单的配置是这样{ tasks: [ { type: cppbuild, label: C: g 编译当前文件, command: C:/msys64/mingw64/bin/g.exe, args: [ -fdiagnostics-coloralways, -g, -Wall, ${file}, -o, ${fileDirname}\\${fileBasenameNoExtension}.exe ], group: { kind: build, isDefault: true } } ] }这个配置里-g是生成调试信息-Wall是打开所有常见警告${file}表示当前打开的文件${fileDirname}是它所在的目录。等做到多文件项目比如第5章以后的游戏${file}要改成${workspaceFolder}\\src\\*.cpp因为一个游戏会拆成多个.cpp文件一起编译只编译当前文件会报“undefined reference”。再说launch.json。它负责把编译好的exe跑起来并附加调试器{ version: 0.2.0, configurations: [ { name: C 调试, type: cppdbg, request: launch, program: ${fileDirname}\\${fileBasenameNoExtension}.exe, args: [], stopAtEntry: false, cwd: ${fileDirname}, environment: [], externalConsole: true, MIMode: gdb, miDebuggerPath: C:/msys64/mingw64/bin/gdb.exe, setupCommands: [ { description: enable pretty printing, text: -enable-pretty-printing, ignoreFailures: true } ], preLaunchTask: C: g 编译当前文件 } ] }这里preLaunchTask的值必须和tasks.json里的label完全一致否则会报“找不到任务”。我见过太多人卡在这一步label写的是“C: g 编译当前文件”launch里写的是“C/C: g build active file”对不上于是F5按下去永远报错。配置这种东西抄不是问题但抄完要能说清每个字段是干什么的出了问题才查得明白。2.3 关于Visual C Redistributable的执念热搜里反复出现“microsoft visual c redistributable”“visual c redistributable 安装包免费下载”“visual c redistributable 安装失败”这里说清楚一件事Redistributable不是编译器它是运行库。你用MSVC编译出来的程序在别人电脑上运行时需要它提供一堆动态链接库比如msvcp140.dll。如果你只用MinGW-w64的g程序用的是MinGW自带的运行库不需要装这个。但如果你用Visual Studio写了程序发给同学跑对方提示“缺少VCRUNTIME140.dll”那就是对方机器上没有对应的Redistributable。解决方案就是去微软官网下载对应版本注意x86和x64的区别安装完重启即可。这个组件是官方发布的系统运行库不是“风险软件”放心装就行。安装失败最常见的原因是系统里残留了旧版本或损坏的VC运行库文件。可以先在“控制面板—程序和功能”里把已有的“Microsoft Visual C 20xx Redistributable”全部卸载再重新安装最新的合集版一般能解决。3. 12个小游戏逐个拆解代码骨架与核心难点这一章是整套系列的主干。我不贴完整代码而是把每个游戏的代码量级、核心语法点、最容易写错的那个点讲清楚你跟着思路自己去写收获比直接抄代码大得多。3.1 热身级猜数字、数字华容道、打字反应测试猜数字约30行这个游戏的核心就三个语法点srand和rand配合生成随机数、while循环、if-else分支判断。经典代码骨架#include iostream #include cstdlib #include ctime using namespace std; int main() { srand(static_castunsigned(time(nullptr))); int target rand() % 100 1; int guess 0; while (true) { cout 请输入1-100之间的数字: ; cin guess; if (guess target) cout 大了 endl; else if (guess target) cout 小了 endl; else { cout 猜对了 endl; break; } } return 0; }别看它简单这里有个很隐蔽的坑rand() % 100 1生成的是1到100但如果你想要0到99必须写rand() % 100很多新手会把两者搞混导致边界判断出错。另外srand的种子不要写在循环里面否则每一轮随机数都一样——我之前见过有人把srand(time(0))放进了while循环结果每次猜完重新生成目标数字游戏逻辑直接乱掉。数字华容道约80行数字华容道的核心是二维数组建模。用一个4x4数组表示4x4的格子其中一个空格用0表示玩家通过移动数字来归位。难点在于“把坐标变化映射到数组下标”玩家输入方向后你要先找到0的位置再判断要移动的数字是否在边界内。这里第一次引入“方向”的概念我会让读者用两个数组int dx[] {-1, 1, 0, 0}; int dy[] {0, 0, -1, 1};来表示上下左右这一步虽然多写了几个变量但换来的可读性是巨大的。以后写贪吃蛇、迷宫、飞机大战都能复用这套方向数组。打字反应测试约60行这个游戏适合练习随机数和计时。屏幕上出现一个随机字符玩家按对应键程序用clock()测量反应时间。它能让你第一次感受到“随机数 时间函数 键盘输入”组合起来是个完整的小程序也顺便复习了字符型数组的初始化char chars[] abcdefghijklmnopqrstuvwxyz;然后用chars[rand() % 26]取一个随机字符。3.2 矩阵与状态类贪吃蛇、扫雷、2048贪吃蛇约150行贪吃蛇是二维数组建模的经典。整个游戏的核心就是四个状态蛇的当前位置、蛇的方向、食物的位置、是否撞墙或撞自己。最常用的做法是拿一个vectorpairint, int存蛇身每一节的坐标新头插前面尾巴看是否吃到食物再决定删不删。难点在“碰撞检测的顺序”。必须先算新头坐标再判断新头是否撞墙或撞到蛇身最后再移动。很多新手把移动和判断的顺序写反了导致蛇头已经撞墙了下一秒还能继续走或者撞到自己时算成了吃到食物。另外键盘输入用_getch()它是conio.h里的函数不是C标准库这一点要提前说明免得在Linux上编译不过去。扫雷约200行扫雷的核心难点是“递归展开”。当点到空白格时要把周围一圈为空的格子全部翻开这需要递归或栈。对应C考点就是函数的递归调用、二维数组的越界检查。还有两个细节容易踩坑布雷时要保证“第一次点击不踩雷”很多人没考虑这个导致连续两次开局就死计算周围雷数时要小心数组越界用偏移数组遍历周围8个格子的写法配合if (x 0 || x n || y 0 || y m) continue;是最稳的。那个“在边界处把边界情况包进去”的套路以后写寻路算法也要用。2048约180行2048比前两个复杂在“移动合并逻辑”。每一行向左移动时需要先把非零数字全部靠拢再合并相邻相同的数字合并之后还要继续靠拢。这个逻辑写不好会产生连锁bug比如2 2 4 0向左移动如果合并两次会得到8 0 0 0如果合并顺序不对会得到4 4 0 0。我的建议是拆成两个函数mergeRow(vectorint row)负责合并一行返回得分moveLeft/MoveRight/MoveUp/MoveDown负责把矩阵旋转成“逻辑上的左移”再调mergeRow。矩阵旋转有几种写法最直观的是转置加行反转代码短且不容易错。3.3 地图与AI类推箱子、俄罗斯方块、井字棋/五子棋推箱子约220行推箱子的核心是地图建模和碰撞检测。地图用二维数组存每个格子有几种状态空地、墙、箱子、目标点、人物。难点在“人物推箱子”的判断要移动的目标格子如果是箱子就得再检查箱子前面的格子是否是空地不是空地就不能推。这里会第一次用到“状态机”思想玩家按方向键不是直接改坐标而是先判断目标格子的状态走 “空地则移动、箱子且箱子前方为空则移动人和箱子、其他情况不移动” 这套分支。这个套路以后在飞机大战的对象管理里也会用到。俄罗斯方块约250行俄罗斯方块的难点不是旋转而是方块形状的表示。我用一个int shapes[7][4][4]的数组存七种方块的4x4矩阵旋转就是矩阵转置加行反转。这个游戏能练到的方法不少数组初始化、深拷贝、定时器Sleep控制下落间隔、状态检测消行、边界检测。最容易出错的是“旋转后越界”。方块旋转后可能超出右边界或下边界必须先检查旋转后的位置是否合法不合法就不旋转。很多新手先旋转再判断结果弹出一个“数组下标越界”的异常。井字棋/五子棋约180行井字棋的AI判断很简单先检查自己有没有能赢的位置再检查堵对手能赢的位置都没有就下在中心/角上。五子棋则要写“赢棋检测”遍历所有棋子检查四个方向横、竖、左斜、右斜是否连续五子。这个检测逻辑里用方向数组dx[4] {1, 0, 1, -1}; dy[4] {0, 1, 1, 1};是最干净的。这里可以顺带练一个面试常问的点类的基本封装。棋盘、当前玩家、落子判断这些可以很自然地封装成class Board。这个游戏是12篇里第一次真正需要“面向对象思维”的地方。3.4 综合项目型迷宫生成与寻路、飞机大战、丧尸末日文字生存迷宫生成与寻路约280行迷宫生成可以做随机DFS从起点开始随机找一面墙拆掉继续递归直到所有格子都被访问。寻路可以做BFS或者A*。这两个算法分别对应栈递归本质是栈和队列都是C数据结构的基础。这个游戏能练到的点特别多二维数组、递归、栈、队列、方向数组、路径记录。最值钱的是A星算法的启发式函数——曼哈顿距离在网格地图里比欧氏距离更符合“只能走上下左右”的规则。写一遍A星你对priority_queue的用法和greaterpairint,int比较器的理解都会深一层。飞机大战约300行飞机大战是“对象管理”的入门。子弹、敌机、爆炸特效都是对象需要在每一帧里遍历并更新它们的状态。这里我建议用vectorBullet bullets;存所有子弹每帧遍历子弹y坐标减去速度、超过屏幕就erase掉、敌机和子弹碰撞就都消失。碰撞检测一般用矩形相交|x1 - x2| halfWidth1 halfWidth2 |y1 - y2| halfHeight1 halfHeight2。这个公式不仅飞机大战能用以后写游戏、做仿真都通用。我还额外讲了“擦除迭代器时要注意失效问题”——vector.erase()返回新的迭代器否则continue时会访问无效迭代器。这个点也是面试链表题和STL避坑里常见的。丧尸末日文字生存约350行这就是热搜里那个“如何用C制作一个僵尸末日小游戏”的来源。我把它做成了文字生存版本玩家在一个地图上移动搜索物资、遭遇丧尸、战斗、生存天数。这个游戏有三块硬骨头结构体数组管理物品与敌人链表、随机事件系统用switch按概率触发、回合制的状态更新状态机。这部分我用上了结构体链表每个敌人是一个struct Zombie串成链表玩家攻击时遍历链表更新血量。讲到链表时我特意对比了list和vector的erase差异vector删除中间元素要移动后续所有元素list删除任意位置都是常数时间。这个对比如果能用自己的话说出来面试时“vector和list区别”这道题就不用背了。4. 游戏里反复用到的C语法点随机数、数组初始化、const/static/final、链表、回调函数很多人在学C的时候语法点都是零散学的不知道什么时候该用。我把这12篇里反复出现、且面试常问的语法点单独拎出来结合游戏场景重新讲一遍。4.1 随机数rand/srand已经不够用了前面猜数字用rand() % 100能跑但这套老API有两个问题一是低位的随机性不够好二是种子容易写错导致“伪随机变假随机”。C11开始推荐用random头文件里的mt19937引擎搭配uniform_int_distribution#include iostream #include random using namespace std; int main() { random_device rd; mt19937 gen(rd()); uniform_int_distributionint dist(1, 100); cout dist(gen) endl; return 0; }这套写法看着比rand()多两行但好处是分布可控、种子更可靠。在丧尸生存游戏里物资稀有度和暴击率都用uniform_real_distributiondouble dist(0.0, 1.0)来判断“是否触发”比rand() % 100 30这种写法直观得多也更容易调整概率。4.2 字符串数组初始化从C风格到STL小游戏里经常要存“装备名”“怪物名”“对话文本”这就要初始化字符串数组。很多人卡在这一步是因为C风格字符串和C的std::string混着用// C风格字符数组每个元素是一个字符 char levelNames[3][20] {EASY, NORMAL, HARD}; // C风格string数组每个元素是字符串 string monsterNames[] {丧尸, 变异犬, 精英丧尸};写贪吃蛇的时候用string数组存“得分排行榜”特别方便vectorstring rankNames; rankNames.push_back(playerName);。刷题时可能不觉得但写游戏就知道std::string的拼接、比较、拷贝比C风格字符串省心太多。4.3 final、static、const三兄弟这几个修饰符在面试里出现频率极高但脱离场景很容易背混。在游戏代码里它们其实很直观const定义“不可变”的配置常量比如const int MAX_HP 100;、const int MAP_WIDTH 40;。写游戏时把地图尺寸、初始生命、子弹速度这些全用const定义后面改参数只改一处。static局部静态变量比如“总击杀数”要跨函数累计可以写成static int totalKills 0;类里的静态成员则属于整个类所有比如Player::count统计玩家实例数量。final用在类名或虚函数后面表示这个类不能被继承、这个虚函数不能再被覆盖。写飞机大战的敌机类体系时如果规定了“BossEnemy”是最终形态就可以加final让代码意图非常明确。这三兄弟组合起来最大的作用是让编译期帮我们抓错误把不该改的写成const编译器会在你误改时报错把不该继承的类写成final以后编码时防止别人乱扩展。这种“用类型系统约束行为”的思路比运行时查找bug高效得多。4.4 冒泡排序、快速幂、单调栈热搜词里出现“冒泡排序算法c”“快速幂算法c”“单调栈算法c”说明这几块是真正的痛点。冒泡排序在猜数字排行榜里可以自己写但我建议写完一版冒泡后立刻去用std::sort并了解它的底层是内省排序快排堆排插入排序的组合最坏复杂度是O(n log n)。面试如果问“冒泡和std::sort的区别”你不能只说“std::sort更高级”要能说出它的底层策略。快速幂在丧尸生存游戏的伤害倍率计算里很有用假设玩家攻击力每提升一级伤害变成原来的1.2倍那么升到50级后的伤害倍率就是1.2^50。直接用pow或者循环乘50次都行但快速幂写出来是O(log n)double fastPower(double base, int exp) { double result 1.0; while (exp 0) { if (exp 1) result * base; base * base; exp 1; } return result; }这段代码里有按位与exp 1和右移exp 1正好能把“按位与”也串起来讲。单调栈用在迷宫寻路的“视野计算”里更直观判断一个格子是否被墙体遮挡可以用单调栈维护“最近的可视遮挡高度”或者“最近更大的元素”。面试经典题“每日温度”“最大矩形”都是用单调栈但你不妨先在迷宫项目的可视范围计算里用它。4.5 结构体链表与回调函数丧尸游戏的敌人列表用链表实现这是“结构体链表”的天然练习。定义一个节点struct Zombie { string name; int hp; int attack; Zombie* next; };然后写addZombie、removeZombie、traverse三个函数构造链表、遍历、删除全都有了。面试如果问“链表和数组的区别”你就用丧尸列表举例数组适合“已知数量且频繁访问”链表适合“频繁增删且数量不定”这是有场景的答案不是背出来的。回调函数在飞机大战的“死亡事件”里很典型主角被击落时要触发游戏结束UI、播放音效、保存最高分、生成爆炸特效。这些动作如果在主循环里一步步写主循环会越来越长。用回调函数把“死亡事件”定义成函数指针或std::function然后在需要的地方直接调用#include functional using DeathCallback std::functionvoid(int score); void onPlayerDead(int score) { // 更新排行榜、显示死亡界面 } void gameLoop(DeathCallback cb) { // ... if (player.isDead()) cb(player.score); } int main() { gameLoop(onPlayerDead); return 0; }这套设计模式在游戏UI系统里叫“事件回调”比在每一帧里写死逻辑要优雅得多。面试问“C回调函数怎么用”你甩出这个例子再解释std::function的用途比背概念强多了。4.6 运算符优先级、按位与、ABA问题运算级优先级是游戏代码里最容易踩的隐性地雷。比如if (dir w x 0 y MAP_HEIGHT)这种看着没什么问题但如果少写一个括号把和||混在一起结果就全变了。我的建议是所有复杂的比较表达式一律加括号不考记忆防出错。按位与和位掩码在飞机大战的按键状态管理里非常好用一个int变量存多个按键状态用keyState | KEY_LEFT设置用keyState KEY_LEFT判断如果需要同时判断“按住左键且空格”就用组合。这比开一堆bool变量清爽得多也是游戏行业很早以前就在用的经典技巧。ABA问题出现在并发场景对一个共享变量做CASCompare-And-Swap时如果内存地址在比较和交换之间被其他线程改回原值CAS就会误判为“没变过”。我在丧尸生存的网络对战扩展可选里提到过控制台小游戏用不上但它是一个很好的深入话题。面试如果被问到可以用现实场景解释两个人同时抢最后一份物资A看到数量是1B把它改成0又改成1A再CAS就误判成“还有物资”实际已经抢完了。这个例子一出来面试官基本能确认你是真懂。5. 常见报错与排查技巧实录最后分享一下我在写这12篇时遇到的问题很多是真实读者的高频提问我直接整理成问答抄作业即可。5.1 C#调用C出现Access Violation C0000005热搜里“c#调用c出现access violation c0000005”很高频。这个错误本质上是C侧的内存访问违例你的程序试图访问一块它没有权限访问的内存地址。常见原因有三个函数签名不一致C#的[DllImport]声明的参数类型和C函数的实际签名对不上。比如C函数接收int*你在C#里声明的却是个int调用时就会栈破坏。遇到C0000005先排查这个。指针生命周期问题C返回了指向局部变量或已释放内存的指针C#拿到后访问就会崩溃。缓冲区溢出C往一个固定大小的数组里写入了超长数据把内存写坏了。常见于字符串拷贝strcpy改成strncpy或std::string能大幅降低这类崩溃。排查时别在C#侧反复看堆栈先到C侧看是谁在“非法访问”。我一般直接在C侧加日志把每次DLL导出函数的入参打印出来定位到第一次崩溃的调用点问题就解决一半了。5.2 捕获到标准C异常有关详细信息请参见系统日志文件这句提示在一些工业软件比如UG/NX调用外部C模块时报出来对应的场景一般是C代码抛了未捕获的异常比如std::out_of_range、std::bad_alloc、迭代器越界。看到这句话别慌它有固定排查路径检查所有std::vector的下标访问是否越界优先用at()代替[]做一次定位at()会抛异常能告诉你具体错在哪。检查迭代器的失效问题对vector执行erase后之前保存的迭代器全部失效继续使用就会触发未定义行为。检查析构函数里有没有删除已被删除的指针这是二次释放必然崩溃。我在代码里加了大量断言和边界检查目的就是让这个异常在“能定位的时候”尽早暴露。5.3 中文乱码、编译不出exe、VSCode终端不吃输入这套问题在Windows VSCode里太经典了。中文乱码Windows下源文件默认GBKVSCode默认UTF-8两者冲突就乱码。最简单的办法是在代码文件第一行写#pragma execution_character_set(utf-8)MSVC/ 或者统一用GBK保存。但用MinGW-w64的话代码里一般SetConsoleOutputCP(CP_UTF8)能解决控制台中文输出。编译不出exe大部分是tasks.json里的command路径不对或者文件名带空格。建议把工程文件放在D:\CppProjects\Game01这种不带中文和空格的路径。VSCode终端不吃输入游戏需要_getch()或cin读键盘但VSCode的集成终端对快捷键处理有干扰按键直接给了编辑器。把launch.json里的externalConsole设为true让程序运行在新开的控制台窗口中基本能解决。5.4 排查速查表现象常见原因解决动作C0000005访问违例函数签名不一致、悬空指针、越界检查DllImport声明、打印C侧入参、开启Address Sanitizer标准C异常vector越界、迭代器失效、bad_alloc改用 at()、检查erase后迭代器、检查内存膨胀中文输出乱码编码不一致SetConsoleOutputCP(CP_UTF8) 或改源码编码编译不通过/不出exeg路径错误、文件路径含中文与空格检查command路径、修改文件路径F5后“找不到任务”launch.json的preLaunchTask与label不一致严格对齐两个字段运行时闪退数组越界/栈溢出开启调试器逐步执行、加边界检查6. 关于这套系列我最后想说的几句心里话把12个小游戏写完最深的感受是语法点单独学是散的放进游戏里就有必然性。比如“静态变量”放在猜数字里教你统计猜测次数你会觉得多此一举但放在丧尸生存里就会明白“整个游戏共享一个幸存者总数”只能靠static。没有具体约束条件语法特性显得多余有了约束条件语法就成了唯一解。我个人建议把这12篇当成“三个月的小计划”不要一口气全写完。一个星期做一篇到两篇保持手感和思考量比突击两周做完更能沉淀下来。做完全部之后把第12篇的丧尸生存扩展成“可以存档、可以在终端里存档继续玩”的文字Roguelike那就等于亲手做了一个别人看起来“有点意思”的完整小项目了面试聊起来也更有底气。最后再分享一个调试小技巧写小游戏时别着急整个功能写完再测试写完“移动”就测移动写完“碰撞”就测碰撞每加一个功能跑一次出了问题范围立刻缩小。很多人卡在贪吃蛇上一天就是因为他一口气写了200行最后报错把整个屏幕和状态都卷进去了查起错来像大海捞针。代码是写给人看的顺便让机器跑一下而已这句话做项目的时候体会最深。
返回列表