
简介C结合EasyX图形库开发的青蛙过河游戏毕业设计项目面向计算机专业学生与游戏开发爱好者。项目提供图形界面与实时交互玩家以WSAD键控制青蛙过河木板移动和河道速度变化制造难度并设有积分与金币系统还预留难度设置、关卡设计等扩展接口适合作为课程设计或毕业设计的完整参考。资源包共32个文件大小1.05MB。内含10个h头文件与7个cpp源文件覆盖游戏逻辑、界面绘制、状态栏等模块附带Visual Studio工程文件sln、vcxproj与编译好的exe可快速运行验证另有5张jpg和2张gif展示界面与演示效果2个txt为项目说明。目录结构清晰便于导入开发环境学习。目前已有66人学习下载。读者可通过研读源码和工程组织快速掌握EasyX图形编程、事件处理与游戏框架设计思路理解一个完整小游戏从设计到发布的基本流程。1. 为什么毕业设计选青蛙过河C语言实例里最“划算”的图形界面项目如果你正在找C图形界面方向的毕业设计题目青蛙过河游戏几乎是最不容易翻车的选择。它比贪吃蛇多一层路径规划逻辑比俄罗斯方块少一个复杂的方块旋转系统难度刚好卡在“能讲清楚”和“值得写进论文”之间。整个项目的核心是让玩家控制青蛙从河岸一侧逐格跳到另一侧中途要躲避移动的车辆和顺流而下的圆木。放在C语言实例的语境里它天然覆盖了面向对象设计、图形界面渲染、实时交互事件处理、碰撞检测和游戏循环这五块内容正好对应开题报告里评审老师最爱问的“技术难点”和“创新点”。这篇笔记的目标是帮你把这条技术路线走通先用Qt搭出可运行的图形界面骨架再实现基于定时器的实时刷新与键盘交互最后把碰撞检测、关卡难度和计分系统串起来。这里不依赖任何外部游戏引擎从窗口创建到碰撞判定全部自己写答辩时每一步都能拿出代码来证明工作量。适合已经学过C语法、但对“怎么做一个带窗口的完整程序”还比较陌生的同学也适合想在毕设里避开过度依赖某框架的同学。2. 技术选型为什么是Qt而不是EasyX或SDL以及环境里必须先解决的两个问题2.1 图形界面方案对比从学生角度算一笔维护账青蛙过河这个题目的图形界面有三个常见做法但只有其中一个适合作为毕业设计主线。EasyX走的是老式Turbo C风格屏幕闪烁和定时器精度问题需要自己处理大量底层细节论文里很难写出有分量的代码SDL的跨平台编译链对Windows和Linux双系统用户不太友好需要额外配置CMake和SDL_image库Qt至今仍是国内C毕设中使用率最高的图形界面解决方案原因是它内置了QGraphicsScene图元框架拖动、换帧、碰撞检测都有现成接口托管给Qt的事件循环后项目代码量能压缩到合理范围。我给你的建议是主框架用Qt Widgets里的QGraphicsScene不要用Qt Quick QML。QML虽然做动画更快但它是声明式语言C代码在答辩PPT里不好展示评委容易质疑“这就是写了个配置文件”。QGraphicsScene下每一个游戏元素都是一个继承自QGraphicsItem的C类坦克、河流、圆木、青蛙全部能作为独立对象管理这正好支撑起论文里的“面向对象设计”章节。2.2 在Windows和WSL2 Ubuntu下分别跑通的最小环境清单Windows用户相对省事安装Qt时勾选MinGW 64-bit套件即可版本上选择Qt 6.5以上的长期支持版。需要注意在安装时取消勾选Qt Creator自带的WebEngine组件那东西会拉一个超过2GB的依赖包实际用不到。Linux用户如果走WSL2 Ubuntu图形界面路线建议直接使用Qt官方Linux套件不要用apt里的qt5-default那个版本老旧且安装后还需要手动配置qmake路径。下面给出一个最精简的配置验证流程。# Windows下在Qt Creator中新建QMainWindow项目后首先在.pro文件中确认模块 QT core gui widgets greaterThan(QT_MAJOR_VERSION, 4): QT widgets # 编译前检查编译器是否为MinGW 64-bit # 工具链路径类似C:\Qt\Tools\mingw1120_64\bin\mingw32-make.exe如果使用WSL2 Ubuntu图形界面开发还有一个断点需要提前踩平在WSL2中运行Qt程序之前必须先手动安装X11图形库并设置显示环境变量否则程序会以非零状态运行失败。sudo apt update sudo apt install libgl1-mesa-dev libxkbcommon-x11-0 libxcb-*0-dev # 必须设置DISPLAY环境变量并允许本地X客户端连接 export DISPLAY$(grep nameserver /etc/resolv.conf | awk {print $2}):0.0 sudo apt install x11-apps # 安装后用xclock验证X Server是否正常逻辑说明第一份代码解决的是Windows和Linux下Qt模块依赖差异问题第二份解决的是WSL2图形界面运行环境问题。如果你在配置时卡在一个奇怪的“QXcbConnection: Could not connect to display”错误那基本就是DISPLAY变量没设置不急把上面的xclock命令跑通再继续。参数上建议保留QGraphicsView的抗锯齿设置对游戏里的圆形青蛙和椭圆浮木反走样效果提升明显。2.3 MFC、无框架裸窗口和Web方案为什么不算最佳选项除Qt之外常被拿来问的还有MFC和纯Win32以及用浏览器套壳的方案。MFC的问题是文档资料偏老处理实时键盘事件和双缓冲绘制时要手写大量消息映射且在新版Visual Studio里调试配置繁琐答辩时也很难讲出新意。纯Win32裸窗口意味着连QPaint这种概念都要自己封装代码量和bug数量会同时上升。用Web技术在浏览器里做一个JavaScript版本则已经脱离C语言实例的范畴评委要求现场改一段算法时会陷入语言切换的尴尬。一个常被忽略的选项是ncurses字符界面它确实能在终端里跑但“图形界面”在题目里的权重很高字符画很难通过查重和截图审查不建议作为主交付物最多在项目报告里作为“非主流扩展方案”一句话带过就行。3. 拆解游戏核心从游戏循环、实时碰撞到关卡规则的完整实现路径3.1 用Qt定时器驱动游戏循环而不是用while死循环游戏循环是所有实时交互项目的地基。常见错误是学生在构造函数里写死循环然后界面彻底假死。在Qt里正确的做法是把循环交给事件系统托管用QTimer每隔固定毫秒数触发一次槽函数在槽函数中完成所有物体的坐标更新。下面给出一个最小可运行的定时器配置和帧更新逻辑。// GameEngine.h 核心头文件 class GameEngine : public QObject { Q_OBJECT public: explicit GameEngine(QObject *parent nullptr); void startGame(); void stopGame(); void setSpeedLevel(int level); // 关卡速度数值越大刷新间隔越短 private slots: void onTimerTick(); // 每个时间片内更新一次场景状态 private: QTimer m_timer; int m_elapsedTime; // 用毫秒累计游戏生存时间 }; // GameEngine.cpp 关键实现 GameEngine::GameEngine(QObject *parent) : QObject(parent), m_elapsedTime(0) { m_timer.setInterval(16); // 约60FPS16毫秒刷新一次 connect(m_timer, QTimer::timeout, this, GameEngine::onTimerTick); } void GameEngine::onTimerTick() { m_elapsedTime m_timer.interval(); // 按时间片移动所有动态障碍物 // 车辆向左或向右移动圆木沿河流方向漂移 // 注意移动速度使用像素/秒避免帧率变化导致速度不一致 const float moveDistance (m_elapsedTime / 1000.0f) * m_speedLevel; // 将moveDistance叠加到每个QGraphicsItem的position上 // 然后统一调用scene-update()触发重绘 }逻辑说明定时器是游戏循环的脉冲来源16毫秒对应60FPS刷新率这是人类视觉感知连续动画的经典阈值。移动距离和时间用时间差相乘而不是直接加固定像素是为了消除不同设备上帧率差异带来的速度偏差。参数上interval不要小于10毫秒否则Qt会频繁进入超时回调反而因为系统调度不稳定导致动画忽快忽慢。m_elapsedTime用int保存毫秒即可如果项目撑到超过47小时需要改成long long这个你在答辩时提一句就能显出工程思维。3.2 用QGraphicsItem派生类组织游戏角色碰撞检测用shapeIntersects而不是pos比较画在场景里的每一个元素都应该有独立的类。青蛙、车辆、圆木、河岸、终点线全部继承QGraphicsItem并重写boundingRect()与paint()。这一步直接关系到论文里的UML类图能不能画得好看。下面给出一个青蛙类的最小实现。// FrogItem.h class FrogItem : public QGraphicsItem { public: FrogItem(QGraphicsItem *parent nullptr); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; void moveUp(); void moveDown(); void moveLeft(); void moveRight(); bool isAtGoalRow() const; // 判断是否到达对岸目标行 private: int m_gridCol; int m_gridRow; }; // FrogItem.cpp 关键部分 FrogItem::FrogItem(QGraphicsItem *parent) : QGraphicsItem(parent), m_gridCol(0), m_gridRow(0) {} void FrogItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); painter-setBrush(Qt::darkGreen); painter-setPen(Qt::black); painter-drawEllipse(boundingRect().adjusted(2, 2, -2, -2)); // 画两只白色眼睛提升交互反馈感 painter-setBrush(Qt::white); painter-drawEllipse(QPointF(8, 8), 3, 3); painter-drawEllipse(QPointF(22, 8), 3, 3); }碰撞检测是另一个重灾区。不要比较两个对象的pos坐标是否相等因为浮点运算之后青蛙落在两辆车中间时可能微秒级跳过碰撞帧。正确方式是使用QGraphicsScene::collidingItems()或者item-shape()与other-shape()求交集。// 在GameEngine::checkCollision()中 QListQGraphicsItem * hitItems scene-items(frog-sceneBoundingRect()); for (QGraphicsItem *item : hitItems) { if (item ! frog item-type() VehicleItem::Type) { if (frog-shape().intersects(static_castVehicleItem*(item)-shape())) { frog-resetToStart(); // 被车撞到重置到起点 m_livesLeft--; return; } } }逻辑说明shape()返回一个QPainterPath对象intersects()检测的是实际像素轮廓相交比用pos做小于等于判断可靠得多。为什么不直接调collidesWithItem()因为那个方法默认用两个item的boundingRect做粗判矩形轮廓在圆形元素上会留下四个角上的假碰撞玩家会感觉到“明明没碰到却被弹回起点”。3.3 实时交互的事件锁与按键响应别在事件回调里改游戏状态键盘交互在Qt里通过重写QWidget::keyPressEvent()实现。几乎所有入门教程都只是让你在回调里直接修改青蛙坐标但这个做法在快速连按键盘时有个隐患Qt的事件循环会把键盘事件排成队列一个接一个地改变青蛙坐标并不会等场景刷新方向一旦连续按两下青蛙横移两格还是竖直跳两格完全凭手速决定。更可靠的做法是把按键意图记录进一个待处理队列然后在定时器的onTimerTick()里择机消费。// FrogController.h class FrogController : public QObject { Q_OBJECT public: enum class Direction { Up, Down, Left, Right }; public slots: void onKeyPressed(Direction dir); void onTick(); // 每帧消费一条指令 private: QQueueDirection m_pendingMoves; }; void FrogController::onTick() { while (!m_pendingMoves.isEmpty()) { Direction dir m_pendingMoves.dequeue(); switch (dir) { case Direction::Up: frog-moveUp(); break; case Direction::Down: frog-moveDown(); break; case Direction::Left: frog-moveLeft(); break; case Direction::Right: frog-moveRight(); break; } // 每次移动后立刻做落水或过关判定 // if (!frog-canStepOn(currentLane)) { frog-resetToStart(); } } }逻辑说明这个模式类似于游戏开发中常说的“事件锁”。按键回调只做入队状态变更统一放在帧刷新里完成保证同一帧内所有交互行为按确定顺序执行。队列在快速连按时会自然堆积系统忙时不会丢事件闲时也不会重复执行。参数上没有额外调优项唯一需要注意的槽函数连接方式onKeyPressed用Qt::DirectConnectiononTick用默认连接两者不要混在同一信号里。3.4 地图分车道设计公路、河流与草地的地形规则表地图是青蛙过河的灵魂。经典地图用数组描述每条车道的类型和内容我建议使用一个简单的二维数组来描述再配合一个车道属性结构体控制速度与方向。// MapConfig.h struct LaneConfig { int laneIndex; // 从河岸一侧的0开始 LaneType type; // 公路 / 河流 / 草地 / 安全岛 int objectCount; // 这条车道上障碍物的数量 float speed; // 单位是像素/秒 bool reverseDir; // 是否反向移动 float objectSpacing; // 障碍物之间的初始间距 }; const LaneConfig laneTable[] { {0, GrassLane, 0, 0, false, 0}, {1, HighwayLane, 3, 120, false, 280}, {2, RiverLane, 4, 90, true, 240}, {3, RoadLane, 3, 100, false, 320}, // 更多行按实际地图尺寸扩展 };这里的关键设计是让障碍物间距大于青蛙单步移动距离确保每一条车道总有安全的空档。如果间距太紧游戏难度会陡增玩家体验的是“随机的折磨感”而不是“路径规划的挑战感”。答辩时可以展示用速度、间距、车道宽度三个参数组合控制关卡难度要去证明你不用改代码库逻辑就能从简单调到困难这比任何一句“我做了三个难度等级”都有说服力。3.5 随机数在实时交互里的正确用法生成障碍物位置和圆木间隙游戏里需要生成随机初始位置如果不设置合理的种子每次启动游戏障碍物布局完全相同老玩家背板后直接通关实时交互的价值就消失了。C的std::mt19937配合std::uniform_int_distribution是正确的选择不要把srand(time(NULL))和rand()混在Qt事件循环里用。#include random class RandomHelper { public: static void initSeed() { std::random_device rd; // 用硬件熵作为初始种子 gen std::mt19937(rd()); } static float randomBetween(float min, float max) { std::uniform_real_distributionfloat dist(min, max); return dist(gen); } private: static inline std::mt19937 gen{std::random_device{}()}; };在生成一条车道时先随机出第一个障碍物的x坐标然后以“间距随机偏移量”的方式向下一个障碍物摆动生成。这种情况下即便同一关卡每局游戏布局也不一样玩家需要动态规划路径而不是靠死记硬背。要特别注意不要在gameStart()里把同一个rand()连续调用两次来生成“随机随机”坐标带来显著的低位模式周期这是老程序员都会踩的坑。4. 实时交互渲染链路从图形界面刷新到音效反馈如何让程序“活”起来4.1 用QGraphicsScene做实时渲染和后端逻辑分离很多人把“实时交互”理解为“游戏画面动得快”实际上它应该被拆成三个能力输入响应及时、状态更新确定、画面重绘流畅。这三者在Qt里分别对应键盘事件队列、游戏引擎定时器、QGraphicsScene::advance()或update()调用链。QGraphicsScene自带的索引和碰撞算法在几十个图元规模下性能完全充裕不需要自作聪明地做空间划分优化。青蛙过河场景中图元数量通常不超过五十个Qt内部用BSP树索引场景即使每个物体的boundingRect都变大一圈也不会造成明显的性能瓶颈。我在项目中一般会把场景分成三个层背景层河岸、草地、公路纹理、动态层所有会移动的物件、玩家层青蛙。三个层放在同一个场景里每帧刷新时动态层和玩家层需要重绘背景层不需要因为也没有变化。4.2 碰撞后的事件反应链从reset到音效再到分数扣减的窗口碰撞不能只写一句“死了然后回到起点”玩家需要从反馈中知道发生了什么。反馈链包括画面闪红、青蛙透明度减半、音效播放、生命值数字动画。下面给出一个碰撞反应的实际处理代码。void GameEngine::handleDeath() { // 1. 播放失败音效用异步播放不阻塞主线程 m_deathSound-play(); // 2. 青蛙做短暂闪烁动画 QPropertyAnimation *blink new QPropertyAnimation(frog, opacity); blink-setDuration(400); blink-setKeyValueAt(0, 1.0); blink-setKeyValueAt(0.5, 0.2); blink-setKeyValueAt(1.0, 1.0); blink-start(); // 3. 主场景更新生命值显示 m_livesLeft--; qDebug() 幸存次数剩余: m_livesLeft; }逻辑说明音效使用QSoundEffect类它内部走异步播放线程不会像老的QSound::play()那样阻塞。动画用QPropertyAnimation驱动完全不占用游戏循环时间片。生命值扣减必须放在碰撞处理的主流程里不能在paint函数里改状态这是前端渲染工程师常说的“不要在绘制阶段修改模型数据”。4.3 加分、计时与存档实时交互闭环里的状态持久化除核心玩法外还需要一两个支撑性功能来凸显“完整性”。我推荐加入基于到达终点的计分和本地最高分记录。存档最简单的方式是使用Qt自带的QSettings写成INI文件也可以把最高分写成一个JSON文件便于跨平台同步。下面展示的是用QSettings保存局最高分的方式。void GameEngine::saveHighScore(int score) { QSettings settings(MyUniversity, FrogCrossingGame); int oldHigh settings.value(game/highscore, 0).toInt(); if (score oldHigh) { settings.setValue(game/highscore, score); settings.sync(); } }这类代码非常不起眼但写进论文里能支撑“持久化模块”的章节。答辩时如果需要展示工程化能力可以再补一句“使用QSettings自动处理跨平台路径差异”Windows下写在注册表或ini文件Linux下写到~/.config目录这些属于Qt内部行为不需要你额外适配。5. 青蛙过河游戏开发避坑指南5个让毕业生熬夜的经典问题与解决办法5.1 中文乱码Qt Creator源码文件格式与MSVC编译器冲突现象在Windows上编译对话框中的文字显示为问号或者按钮上的中文完全错乱。原因Qt Creator在Windows上默认保存源码为UTF-8而MSVC编译器在旧版本中默认按本地ANSI代码页GBK解析字符串字面量导致多字节字符被错误解码。解决在项目配置里为MSVC指定UTF-8执行字符集或者在每个含中文的源文件顶部追加编译声明。最稳妥的方案是全部改用Qt的QString::fromUtf8()包裹中文字符串字面量同时将编辑器编码固定为UTF-8 BOM。在MinGW环境下这个问题通常不存在所以如果你全程用MinGW编译可以跳过这一条。5.2 碰撞判定太过灵敏青蛙跳出去一个身位就被判定死亡现象青蛙明明只在圆木边缘被擦到一下就直接死亡玩家反馈判定过于严格。原因boundingRect()默认返回QRectF的完整矩形包含大量透明区域。圆的矩形碰撞边界比视觉圆大了一圈尤其在四角处产生大量误判。解决将碰撞检测的几何形状从矩形改为真实形状。重写QGraphicsItem::shape()用QPainterPath添加一个椭圆或稍微缩小的多边形让检测边界贴合图形轮廓。如果仍然太灵敏就再加一个QPainterPathStroker扩展一层补偿给玩家更宽容的判定窗口。5.3 AltTab切出游戏再切回来青蛙瞬间瞬移一段距离现象切后台时青蛙原本在草地上回来时发现它已经在河里或者被撞死好像后台时间也被游戏循环处理了。原因定时器在窗口最小化时不会完全停止而是继续在后台触发onTimerTick而这段时间玩家的按键指令被系统拦截到输入队列中切回窗口时突然全部消费掉。解决在QMainWindow::changeEvent()里监听窗口失活状态失活时调用m_timer.stop()重新激活后调用m_timer.start()。同时把“按键入队事件”升级为“只在窗口激活状态才接受”这样切后台后不会有任何移动被中途积压。5.4 不同电脑上青蛙移动速度不一样有的快到失控现象在同一份代码中游戏在A同学电脑上青蛙每秒跳两格在B同学电脑上每秒跳四格。原因部分代码把移动逻辑写在paint()里而Qt的绘制调用与刷新频率不是固定值高刷新率显示器会触发更多paint调用导致移动更快。解决所有移动逻辑必须严格放在定时器槽函数中禁止在paint()里改坐标。速度单位统一改为“像素/秒”然后用前后两次QElapsedTimer的时间差换算出当前帧位移而不是直接累加固定像素值。5.5 答辩演示时青蛙每跳一步有一点卡顿感现象平时自己电脑上跑很流畅到答辩教室的电脑或远程演示环境下画面有一点掉帧。原因开发机Debug模式编译的程序在无Qt调试插件环境下性能下降或者在402秒连续运行之后内存碎片导致Qt动态堆分配缓慢。解决演示时务必用Release模式重新构建并关掉Qt Creator的调试输出窗口。在main.cpp的qputenv(QT_LOGGING_RULES, *.debugfalse)关闭所有调试日志输出。如果演示环境性能确实差就把帧率从60FPS降到50FPS重新编译一份肉眼差距很小但卡顿感大幅降低。6. 从开题报告到答辩PPT如何把C语言实例整理成一份撑得住质疑的毕业设计材料6.1 开题报告里的“研究内容”怎么写才能不空评审老师最反感“开发一个青蛙过河游戏”这种一句话研究内容。你的开题报告里至少要拆出四块图形界面交互响应模型从键盘事件到场景更新的时序关系、碰撞检测中的几何决策机制用shape而非矩形、动态难度调节的参数体系、面向对象设计在游戏对象管理中的应用。每一块能对应一段代码实现或一张截图就能构建一条从选题理由到技术手段的证据链。开题报告里还必须有项目时间规划。建议这样安排第2至3周做需求分析与技术摸索第4周完成地图配置和数据结构设计第5至8周集中实现图形界面与核心交互第9周完成碰撞和计分模块第10至11周进行多平台测试并修复BUG第12至13周撰写论文和准备答辩材料。如果和导师沟通后毕业设计时间只有十周就把多平台测试压缩到一周其他环节同步前移。6.2 论文结构如何突出C和实时交互而不会被判成“简单的游戏开发”论文标题里只要有“实时交互”就必须在正文里把实时解释清楚。什么是实时在这个项目里指的是输入事件在固定时间节拍内被消费动画在60FPS下流畅刷新碰撞结果在下一帧前得到反馈。这三者形成闭环后程序才叫实时交互否则只是批量处理。绪论一到两页介绍背景即可直接写“本课题选择C语言借助Qt图形界面框架实现一个具备实时交互特性的青蛙过河游戏”不要扩大到游戏产业宏大叙事。核心章节建议这样布局第三章写总体设计包含系统架构图、模块划分和UML类图第四章写详细设计与实现这里必须有你已经跑通的代码片段、地图配置表、类图映射第五章写系统测试重点展示三轮测试功能测试按键响应、过关失败判定、边界测试快速连按键盘、窗口后台切换和性能测试普通电脑上的帧率均值。每张图配上三句以上分析避免变成截图堆叠。6.3 答辩PPT的一页内容布局代码截图、运行效果和性能数据缺一不可答辩演示通常限制在十分钟左右PPT在10到14页之间最为合适。第一页直接亮题第二页放技术栈和开发环境第三页放游戏截图或动态录屏第四至六页各放一个核心模块的代码截图并配上讲解关键词第七页放运行结果表格帧率、内存占用、通过率第八页放困难和解决方案第九页总结不足与展望。答辩PPT最忌讳的是整页贴上密密麻麻的代码。你需要用圈注把关键行标出来——比如定时器设置的16毫秒、碰撞检测里的shape().intersects()、事件队列的onKeyPressed入队逻辑——然后口头展开。如果现场突然被问到“这个和其他人有什么区别”就用三条主线回答用事件队列而非直接改坐标来处理键盘输入、用速度乘时间而非固定位移保证跨设备一致、用车道配置表而非硬编码来控制关卡难度。6.4 答辩现场最可能被追问的问题和对应的应答策略“你的游戏能用鼠标玩吗”是几乎必问的问题。如果项目只做了键盘交互用“鼠标交互已通过计划中的接口预留但当前版本主要面向键盘实时操作场景”来回应同时可以在代码里留一个QMouseEvent的空槽函数现场演示时快速打一段注释说明如何将鼠标坐标映射到最近可行走的格点用代码预备方案证明不是没想过而是侧重点不同。“碰撞检测为什么不用图片像素判断”这个问题考验真实性。回答要突出性能与设计权衡像素级碰撞判断在1440p的4K屏上会带来更大计算量而且图元尺寸的缩放会让像素检测结果失真反而用QPainterPath的shape做轮廓检测在矢量缩放场景下更稳健。“如何证明你做的难度调节其实有效”则回应速度、密度、反应窗口时间三个可量化的参数指出反应窗口等于可安全移动距离除以障碍物车速这样从数学上就建立了通关难度与控制参数的映射关系。我的习惯是答辩前在本地跑三遍完整演示流程第一遍正常速通第二遍故意输掉一局展示碰撞判定和重置逻辑第三遍把窗口切到后台再切回来展示事件锁与暂停恢复的能力。这三次演下来评审会认为你对程序的每一个行为都能自圆其说。希望帮到你同时也祝你答辩顺利。本文还有配套的精品资源点击获取