新闻详情

新闻详情

首页 / 资讯中心 / 详情

C++ Qt飞机大战开发全解析:从环境搭建到碰撞检测与信号槽

发布时间:2026/10/1 13:48:03来源:尧图网络
C++ Qt飞机大战开发全解析:从环境搭建到碰撞检测与信号槽
简介基于C与Qt框架实现的飞机大战小游戏完整工程面向计算机相关专业在校学生、教师以及希望快速上手Qt开发的初学者。项目将游戏核心逻辑拆分为多个模块地图绘制、英雄机控制、敌机生成、子弹发射与碰撞检测均由独立源文件实现并配有工程配置文件与资源列表。压缩包共五十八个文件容量约三十三兆字节主要包含七份C源码、七份头文件、多张透明背景战机与子弹图片、背景图像、音效文件和窗口图标素材与代码分离结构清晰。已有三百五十二人学习下载既可直接运行体验完整玩法也适合作为课程设计、毕业设计或项目初期演示。在此基础上补充计分、关卡或特殊技能较为容易有助于深入理解事件循环、定时器、绘图与键盘交互等内容下载后建议先查阅项目说明文件相关内容仅供学习参考。1. 一套能跑起来的 Qt 飞机大战真正的门槛在环境匹配接触过不少 C 课程设计的人会有同感代码逻辑写起来并不难真正卡人的是环境。这套基于 C/Qt 开发的飞机大战小游戏文件数量不算多核心类也就 mainscene、heroplane、enemyplane、bullet、bomb、map 这几个但它把 Qt 工程的完整骨架、素材打包方式和游戏循环都凑齐了适合做 Qt 入门练习、课程设计或者毕业设计的前期演示。素材里既有背景图、飞机图、子弹图也有 bg.wav、bomb.wav 这类音效资源整套东西拿到手不是看代码就能完事而是要能在自己的机器上把它跑起来、改得动。对新手来说最难的不是理解碰撞检测而是先搞定 Qt 版本和编译套件那一关。2. 工程结构拆解.pro、res.qrc 与六个类的分工2.1 工程文件组读懂.pro和res.qrc的职责解压这个 zip 后第一眼看到的应该是AirplaneWar.pro、AirplaneWar.pro.user、config.h、plane.rcc、res.qrc等文件。.pro是 qmake 的工程描述文件它决定了哪些源文件参与编译、链接哪些 Qt 模块.pro.user是 Qt Creator 自动生成的用户配置里面记录着你选择的是哪个 Qt 版本、哪个编译套件这个文件换台机器基本是废的直接忽略就好。常见的一份.pro内容长这样QT core gui greaterThan(QT_MAJOR_VERSION, 4): QT widgets TARGET AirplaneWar TEMPLATE app CONFIG c11 SOURCES \ main.cpp \ mainscene.cpp \ heroplane.cpp \ enemyplane.cpp \ bullet.cpp \ bomb.cpp \ map.cpp HEADERS \ mainscene.h \ heroplane.h \ enemyplane.h \ bullet.h \ bomb.h \ map.h \ config.h RESOURCES \ res.qrc这段配置里QT widgets很关键Qt 5 之后 GUI 控件从 QtGui 模块拆到了 QtWidgets如果工程里用了 QWidget 却没加这一行编译直接报 undefined reference。CONFIG c11指定 C 标准飞机大战这类项目用不到太新的特性但基于范围 for 的遍历、auto 类型推导能简化代码建议保留。RESOURCES指向资源文件意味着所有图片和音效会被编译进二进制运行时不依赖外部图片目录这是很多初学者容易忽视的优势。res.qrc是资源清单作用是把散落的图片、音频文件映射成 Qt 内部路径比如fileres/bg.wav/file对应的是:/res/bg.wav。qrc 里的路径是虚拟的运行时打开资源文件用的是冒号开头的路径不是磁盘上的相对路径。资源会被 rcc 工具编译成二进制数据嵌进 exe所以发布单个可执行文件也能正常运行不必带一整包图片。plane.rcc这个文件从名字看是早期 rcc 工具生成的预编译资源二进制文件可能在某些版本里被用来加速资源编译也可以作为资源文件直接加载。如果工程里没有用RCC变量引用它那它大概率是历史遗留物不用管它。2.2 核心类的划分谁在管理游戏对象这个项目里没有明确的抽象基类文件名但按常规 Qt 游戏写法通常会有一个基类保存坐标、速度和碰撞矩形再让 heroplane、enemyplane、bullet、bomb 继承它。即便原工程里没有你自己改的时候也会想补一个否则每个类都重复写 setPos、getRect 逻辑太啰嗦。代码里常见的基类设计是这样// gameobject.h #ifndef GAMEOBJECT_H #define GAMEOBJECT_H #include QPixmap #include QRect class GameObject { public: GameObject(); virtual ~GameObject() {} virtual void update() 0; // 子类各自更新位置或状态 QRect getRect() const { return m_rect; } void setPosition(int x, int y); protected: QPixmap m_pixmap; int m_x; int m_y; int m_speed; QRect m_rect; // 碰撞判定用矩形 }; #endif这段代码里最关键的是 m_rect 和 getRect()它把“画在哪”和“碰撞范围”解耦。飞机图片本身可能是带透明背景的矩形的实际碰撞范围应该比图片略小这样玩家手感不会太糟。实际项目中我一般会在这里面留一个偏移量设置比如 m_rect 在构造时赋QRect(x 8, y 8, pixmap.width() - 16, pixmap.height() - 16)具体偏移根据图片边框试出来的。mainscene.h大概是主逻辑所在它持有玩家飞机、敌机列表、子弹列表、炸弹列表和地图对象。基类虚函数 update() 的设计意图是主场景里的定时器每触发一次就遍历所有对象调用它们的 update()再统一刷新画面。这样新增一种飞机类型时不需要改动主循环你只需要创建对象并且把它塞进相应列表。2.3 信号槽机制在这个项目里怎么用Qt 的信号槽是这个项目的核心机制之一。比如玩家被击中后主场景需要知道那就不应该让 heroplane 自己处理死亡而是让它发一个信号由 mainscene 决定是结束游戏还是扣一条命。常用的做法是// heroplane.h 中声明 signals: void heroDied(); // heroplane.cpp 检测到生命值归零 if (m_hp 0) { emit heroDied(); } // mainscene.cpp 连接信号 connect(m_hero, HeroPlane::heroDied, this, MainScene::gameOver);信号槽最大的好处是解耦。子类不需要知道主场景做了什么主场景可以自由替换游戏结束的处理逻辑比如弹窗、播放失败音效、写分数文件。有一点要提醒信号发射的那一帧不要立刻 delete 发射对象否则槽函数执行时对象已经没了。正确方式是先标记状态为死亡等定时器下一轮统一清理或者用QTimer::singleShot(0, obj, QObject::deleteLater)延迟删除。3. 构建与运行Qt Creator、命令行与 config.h 的参数3.1 用 Qt Creator 跑起来的完整步骤先明确一点这个资源能跑的前提是你的 Qt 版本和编译器套件与工程兼容。如果你之前没装过 Qt去 Qt 官网下载一个开源版就行。选择版本时注意两点一是 Qt 5.15.2 这个版本非常经典资料多、坑少网上绝大多数的改动技巧都基于它二是 Qt 6.x 系列对 QWidget 也兼容但如果原工程是用 Qt 5 写的直接拿 Qt 6 打开可能会遇到模块调整或废弃 API 的问题。我的习惯是先用QT core gui widgets看工程能不能兼容 Qt 6如果遇到编译错就去查对应 API。具体步骤用解压工具把 zip 释放到一个纯英文路径下比如D:/games/AirplaneWar不要放在带中文和空格的目录。打开 Qt Creator选择“打开项目”找到AirplaneWar.pro。首次打开会弹出套件选择窗口选择你安装的 Kit。常见组合是 MSVC 2019 64bit 或 MinGW 8.1.0 64bit。注意 Debug 和 Release 要确定一种不要混着选。点击左下角绿色三角运行按钮或者用快捷键 CtrlR。如果编译通过后出现窗口说明环境正常如果报错先看 Qt Creator 下方的“编译输出”面板不要只看“问题”列表那里有时候不显示完整信息。这个流程里最容易翻车的是套件选择。很多新手机器上装了多个 Qt 版本比如 5.9 和 6.5然后发现编译一直报 “cannot mix incompatible qt library”原因就是编译器和 Qt 库版本对不上。你选的那个 Kit 里显示的 Qt 版本必须是实际存在的最好在 Kit 管理里专门建一个 “Qt 5.15.2 MinGW 64bit” 的组合后续所有 Qt 项目都用它这样能省掉大量环境问题。3.2 命令行构建不用 Qt Creator 也能编译如果你擅长用命令行或者想在 CI 环境里走一遍编译可以用 qmake 加 make 的方式。步骤也很固定# 进入工程目录Windows 下用 MinGW 套件时 D:\games\AirplaneWar qmake AirplaneWar.pro D:\games\AirplaneWar mingw32-make.exe -j4 D:\games\AirplaneWar release\AirplaneWar.exeqmake会根据 .pro 生成 Makefile-j4是让编译并行 4 个线程加快速度。如果编译器是 MSVC编译命令则是nmake。有一点要特别注意命令行里执行 qmake 之前需要先确保 Qt 的 bin 目录已经加入了 PATH 环境变量否则系统会提示 “qmake 不是内部或外部命令”。在 Qt Creator 里运行时它会自动处理好环境所以新手优先用 IDE 方式启动。运行产物在 release 目录里exe 文件默认只包含代码没有 Qt 的 DLL。如果直接把 exe 拿到别的机器上跑需要有相应的运行库。Qt 提供了一个 windeployqt 工具能把需要的 DLL 自动复制到 exe 旁边这个后面发布时用得上。3.3 config.h 是改手感的第一入口config.h 这个文件在多数 Qt 游戏工程里承担全局配置职责我看到这个资源里包含它推测作者把窗口宽度、定时器间隔、对象初始速度这类常量集中到里面了。这套设计的好处是调整游戏难度时不需要到处改 magic number只改这一个文件就能试出整体手感。常见的参数定义方式#ifndef CONFIG_H #define CONFIG_H #define GAME_WIDTH 512 #define GAME_HEIGHT 768 #define GAME_TITLE 飞机大战 #define GAME_FPS 60 #define GAME_INTERVAL 1000 / GAME_FPS // 约 16 毫秒一帧 #define HERO_SPEED 6 #define HERO_HP 3 #define BULLET_SPEED 8 #define ENEMY_SPEED 4 #define BOMB_COOLDOWN 2000 // 炸弹冷却时间单位毫秒 #define ENEMY_INTERVAL 3000 // 敌机生成间隔 #endif这几个参数分别是窗口尺寸、帧率、定时器间隔、玩家移动速度、玩家生命数、子弹移动速度、敌机移动速度、炸弹冷却时间。GAME_INTERVAL 是核心定时器每隔这么多毫秒触发一次刷新逻辑数值越小游戏越流畅但 CPU 占用也越高16 毫秒是主流 60 FPS 的标准。如果你想要游戏节奏更紧张把 ENEMY_INTERVAL 调小一点就行想要玩家更容易操作把 HERO_SPEED 调大。注意这里用的是宏定义不是 constexpr 的变量。宏定义在头文件里被展开没有任何类型检查好处是旧编译环境也能用坏处是调试时看不到值。如果原工程本来用的就是宏建议保持风格一致如果你要把这个工程移植到 Qt 6 环境顺手把它们改成inline constexpr int也是不错的优化。4. 玩法逻辑落地定时器驱动、碰撞检测与音效触发4.1 游戏循环QTimer 驱动的一帧刷新飞机大战这一类游戏核心就是一个循环不断读键盘状态、更新物体位置、检测碰撞、重绘画面。用 Qt 去写最自然的做法是 QTimer。mainscene.cpp 里的构造函数大概率像这样// mainscene.cpp MainScene::MainScene(QWidget *parent) : QWidget(parent) { // 初始化窗口和场景对象 initScene(); initHero(); initEnemies(); initTimer(); } void MainScene::initTimer() { m_timer new QTimer(this); m_timer-setInterval(GAME_INTERVAL); connect(m_timer, QTimer::timeout, this, MainScene::updateGame); m_timer-start(); } void MainScene::updateGame() { m_map.update(); // 背景向下滚动 m_hero.update(); // 根据按键状态移动 for (EnemyPlane *e : m_enemies) { e-update(); // 敌机向下飞行 } for (Bullet *b : m_bullets) { b-update(); } checkCollision(); // 子弹 vs 敌机、敌机 vs 玩家 update(); // 调用 paintEvent 重绘 }注意看 setInterval 和 update() 分离的设计一个负责“逻辑更新”一个负责“界面重绘”。如果你的电脑性能不够重绘函数耗时长定时器回调里就会累积事件。常见的优化方案是把 update() 挪到 paintEvent 里让 Qt 自己决定什么时候绘制逻辑更新只管改坐标。定时器触发的频率不等于实际刷新率但作为课程设计这个精度完全够用。有些新手会在这里用 while(1) 加 QThread::sleep 去做游戏循环这是 Qt 游戏最常见的翻车点主线程被阻塞后窗口消息无法处理按键事件队列会被积压整个界面会假死。QTimer 是事件驱动的原理跟主循环不同这也是为什么这个项目的做法值得保留。4.2 碰撞检测矩形相交与销毁回收碰撞检测是整个飞机大战里逻辑最集中的地方。用到的函数就是 QRect 的 intersects判断两个矩形是否相交。典型逻辑是先遍历子弹列表再遍历敌机列表看有没有重叠void MainScene::checkCollision() { for (int i m_bullets.size() - 1; i 0; --i) { Bullet *bullet m_bullets[i]; bool bulletUsed false; for (int j m_enemies.size() - 1; j 0; --j) { EnemyPlane *enemy m_enemies[j]; if (bullet-getRect().intersects(enemy-getRect())) { enemy-beHit(); // 敌机扣血 bulletUsed true; if (enemy-isDead()) { m_enemies.removeAt(j); delete enemy; m_score enemy-scoreValue(); // 加分 } break; // 一颗子弹只穿一个目标 } } if (bulletUsed) { m_bullets.removeAt(i); delete bullet; } } }这段代码有两个值得注意的地方。一个是从尾部开始遍历。因为删除元素后索引会变从前往后遍历会出现跳过元素的问题从尾部处理最安全。另一个是循环里直接 delete 对象这是课程设计常见写法但如果敌人和子弹比较多频繁 new/delete 容易产生内存碎片性能也会下降。进阶做法是维护两个对象池死亡对象不销毁而是标记不可用下次生成时复用。这个项目里如果用不到那么大的并发量保持简便可读反而更重要。碰撞判定里还有一个隐藏坑子弹的矩形应该用“移动后的位置”判断不能用旧的坐标。所以正确的调用时机是在 update 阶段完成所有移动之后、重绘之前调用 checkCollision。原工程里如果有一步到位把移动和碰撞写在同一个函数里的方式你会发现子弹因为速度太快会穿过敌机这是矩形相交检测在高速移动下的固有问题。要彻底解决就要做连续碰撞检测CCD但课程设计里把子弹速度控制在 8 像素/帧以内就完全够用。4.3 音效触发QSoundEffect 与播放时机音效资源里 bg.wav 和 bomb.wav 是背景音乐和炸弹音效。Qt 播放 wav 最简单的方式是 QSoundEffect它对资源加载友好支持循环播放延迟低非常适合游戏音效场景。而背景音乐用 QMediaPlayer 更合适或者直接把 QSoundEffect 的 loopCount 设成 QSoundEffect::Infinite 让它循环#include QSoundEffect // 在 MainScene 构造函数里 m_bgMusic new QSoundEffect(this); m_bgMusic-setSource(QUrl(qrc:/res/bg.wav)); m_bgMusic-setLoopCount(QSoundEffect::Infinite); m_bgMusic-setVolume(0.5f); m_bgMusic-play(); // 炸弹引爆时 m_bombSound new QSoundEffect(this); m_bombSound-setSource(QUrl(qrc:/res/bomb.wav)); m_bombSound-setVolume(0.8f); m_bombSound-play();注意 qrc 路径开头必须写qrc:前缀这是 Qt 的资源寻址协议很多新手只写/res/bg.wav结果资源加载失败没有任何报错游戏就是一个静音状态。QSoundEffect 也要求 wav 是标准 PCM 格式有些工具转出来的 wav 带非标准编码头播放会直接失败或者有爆音。如果遇到音效无法播放先用格式工厂或者 ffmpeg 转成 44.1kHz、16bit、单声道的 wav 再放回去试试。还有一点容易被忽视QSoundEffect 在 Ubuntu 或者树莓派这类 Linux 环境下需要系统的音频设备可用比如 ALSA 或者 PulseAudio。在容器或 CI 环境里没有声音设备时play() 不会报错但也不会有声音不要误以为是 bug这是运行环境的限制。4.4 地图滚动的实现方式游戏里背景在持续向下滚动这是飞机大战的标配。map.cpp 里一般会用两张图交替叠加产生循环void Map::update() { m_y1 MAP_SPEED; m_y2 MAP_SPEED; if (m_y1 GAME_HEIGHT) { m_y1 m_y2 - GAME_HEIGHT; } if (m_y2 GAME_HEIGHT) { m_y2 m_y1 - GAME_HEIGHT; } } void Map::paint(QPainter painter) { painter.drawPixmap(0, m_y1, m_pixmap); painter.drawPixmap(0, m_y2, m_pixmap2); }关键在于 m_y1 和 m_y2 超过窗口高度时要做循环回绕而不是让它无限增长。如果直接用一个 y 坐标画图然后把它重置为 0视觉上会出现明显的背景瞬移跳变手感就被破坏了。用两张图交替绘制视觉上元感知。资源里能看到 img_bg_level_1.jpg 到 img_bg_level_5.jpg 五种背景图说明这个工程本身就支持不同关卡切换背景这个逻辑在后面的扩展里可以结合起来用。5. 避坑手册五个常见故障的现象、原因与解决以下是我在实际运行这类 Qt 小游戏时踩过的坑每条都按“现象 → 原因 → 解决”来写按优先级从高到低排。5.1 运行时提示 qt.qpa.plugin: could not find the Qt platform plugin linuxfb现象程序编译成功但双击 exe 或者用命令行运行时弹出类似qt.qpa.plugin: could not find the Qt platform plugin linuxfb然后退出。这种情况在树莓派交叉编译 Qt 的机器上尤其常见。原因Qt 的图形后端插件没有找到。Qt 在运行时需要 plugins/platforms 目录下的动态库比如 qwindows.dll 或 libqlinuxfb.so。如果打包时没有把相应插件带上或者跨平台编译时 platform plugin 没有编译进去就会触发这个问题。很多人交叉编译 Qt 时只编译了 Qt 库本身没有把插件的生产物复制到目标设备上。解决在 exe 所在目录建 plugins/platforms 目录把 Qt 安装目录里对应编译器的 plugins/platforms 下文件复制进去然后在程序启动时设置QApplication::addLibraryPath(plugins)或环境变量QT_QPA_PLATFORM_PLUGIN_PATHplugins。另外常见的一种原因是你安装的是精简版 Qt没有包含 xcb 或者 linuxfb 插件需要回到 Qt 安装管理器勾选对应的平台插件重新安装。5.2 编译报错 fatal: cannot mix incompatible qt library (version ex50601) with this librar现象项目一编译就报fatal: cannot mix incompatible qt library (version ex50601) with this librar错误信息里有一串类似 ex50601、ex60500 的字符串。这类报错在网上一搜一大片。原因ex50601 代表 Qt 5.6.1 版本号编码ex60500 代表 Qt 6.5.0。你编译时使用的头文件和链接的库分别来自不同的 Qt 版本。比如 IDE 里使用了 Qt 5 的头文件但链接器的库路径却指向了 Qt 6或者之前构建时缓存了旧版 Qt 的 moc 文件。解决第一步检查 Qt Creator 里 Kit 的“Qt 版本”和“编译器”是否匹配把编译器切换到对应 Qt 版本比如 MinGW 64bit 配 Qt 5.15.2。第二步清理构建目录建议把 build-AirplaneWar-Desktop_Qt_5_15_2_MinGW64_bit-Release 整个文件夹删掉重新 qmake 再构建。第三步如果机器上同时装了多个 Qt 版本确保环境变量 PATH 里排在最前面的是你要用的那个 Qt 的 bin 路径否则命令行下 qmake 会找错版本。5.3 图片显示不出来窗口一片黑或只有背景滚动现象程序能运行窗口正常但飞机、子弹、菜单全部不显示或者一部分图片正常一部分空白。没有报错只是安静地黑屏。原因一个可能是图片路径用成了相对路径但运行时的工作目录不是 exe 所在目录。另一个可能是 qrc 文件里的路径与资源实际文件名不一致例如你在磁盘上把图片命名为img-plane_1.png但 qrc 里写的是img/plane_1.pngQt 无法解析这个虚拟路径时直接忽略。解决如果用的是 qrc 路径打开 res.qrc逐个确认file标签里的相对路径与真实文件名一致在代码里引用时加上qrc:/前缀。如果用的是磁盘相对路径干脆把程序启动目录改成 exe 所在目录或者在 main.cpp 里用 QDir::setCurrent 设置工作路径。调试这类问题最快的方式是写一句qDebug() QFile::exists(:/res/img-plane_1.png);如果输出 false说明资源没编进去如果 true说明问题出在绘制逻辑上跟资源无关。5.4 键盘按键没反应飞机不动现象窗口出现了画面在滚动但是上下左右按键无法控制玩家飞机也没有任何报错。原因QWidget 默认没有打开键盘焦点或者焦点被其他子控件抢走了。keyPressEvent 只有在窗口接收键盘事件时才会触发一旦焦点落在别的控件上事件就被拿走了。解决在 mainscene 构造函数里加上setFocusPolicy(Qt::StrongFocus);并在需要时调用setFocus();。如果窗口里还有按钮、输入框之类的子组件按键事件会被它们先接收可以重写 keyPressEvent 后调用event-ignore()让事件继续传递到父窗口。调试时可以先用 qDebug() 打印 key 值确认事件有没有到达这个类。5.5 zip 解压后文件损坏或提示密码错误现象压缩包下载后某些解压软件提示“文件损坏”或“密码错误”但是重新下载现象依旧。原因现在很多网络资源在打包时做过伪加密处理就是 zip 的全局加密位被置为 1但实际内容并没有加密。部分解压软件尤其是某些版本的 WinRAR 或 360 压缩会对这种 zip 报错让人误以为资源有问题。还有可能是传输过程中文件不完整但伪加密占了大多数情况。解决换用 7-Zip 解压7-Zip 对这种伪加密的宽容度更高如果 7-Zip 还是报错用 zip 修复工具修正加密位再解压。如果资源本身就带密码注意看下载页面有没有附带密码说明。同时下载后最好校验一下压缩包大小和页面描述是否一致避免被断点续传导致的截断文件坑到。6. 进阶把单关卡做成多关卡以及一个暂停功能的加装技巧6.1 启用多套背景与关卡号绑定资源里已经提供了五张不同风格的背景图img_bg_level_1.jpg 到 img_bg_level_5.jpg这说明作者本来就规划了多关卡。把单关卡扩展成多关卡最直接的做法是给 MainScene 增加一个关卡编号字段并在进入新关卡时更换 m_map 的背景图void MainScene::switchLevel(int level) { m_currentLevel level; QString bgPath QString(:/res/img_bg_level_%1.jpg).arg(level); m_map-setBackground(QPixmap(bgPath)); m_enemies.clear(); m_bullets.clear(); m_enemyInterval ENEMY_INTERVAL - level * 300; // 关卡越高出敌越快 m_enemySpeed ENEMY_SPEED level * 2; }通过关卡参数表可以快速调整每关的难度曲线关卡背景图资源敌机生成间隔敌机速度说明1img_bg_level_1.jpg3000ms4新手引导节奏松弛2img_bg_level_2.jpg2700ms6开始加量3img_bg_level_3.jpg2400ms8需要频繁躲避4img_bg_level_4.jpg2000ms10容易出现子弹与敌机同屏5img_bg_level_5.jpg1500ms12高端局濒临帧率瓶颈切换关卡时要注意清空旧的敌机和子弹列表。如果不清理上一关的残留敌机会以旧速度继续飞行带来不可复现的 bug。6.2 加暂停键的实操技巧飞机大战这种快节奏游戏玩家的暂停诉求很强。最常见的实现方式是在 keyPressEvent 里拦截 P 键切换一个 m_paused 标志。void MainScene::keyPressEvent(QKeyEvent *event) { if (event-key() Qt::Key_P) { m_paused !m_paused; if (m_paused) { m_timer-stop(); } else { m_timer-start(GAME_INTERVAL); } return; } QWidget::keyPressEvent(event); }这个做法有一个隐藏细节玩家松开 P 键后按键事件已经被拦截处理不需要担心继续触发移动。但值得注意的是暂停期间如果窗口被最小化再恢复定时器不会自动启动所以稳妥的做法是在 paintEvent 或者 resizeEvent 里检查一次是否处于非暂停状态。真正进阶的暂停逻辑还会涉及音效暂停QSoundEffect 没有 pause 接口只能 stop 后记住播放位置恢复时再 play这个项目里为了简化可以省略。从那以后我每次接这类课设项目都会强制把 config.h 里的核心参数、键位绑定、音效开关这三类东西先过一遍再去看游戏逻辑避免在别人设好的“暗坑”里翻来覆去。这个习惯让我从 Qt 5.3 时代一路走到 Qt 6几乎没有再被构建环境反复折磨过。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

门店SaaS资金安全设计:权限最小化、操作留痕与对账闭环 2026/10/1 14:37:13

门店SaaS资金安全设计:权限最小化、操作留痕与对账闭环

一、权限模块:最小化 数据模型 权限设计采用经典的 RBAC(Role-Based Access Control) 细粒度权限点: 岗位即角色:收银员、技师、部长、店长、老板五套标准模板,可复制可微调权限点下沉到按钮:开…

阅读更多 →
大型集团人才画像怎么在HR系统里落地?从五维度数据模型到标签引擎,提升人岗匹配效率 2026/10/1 14:37:13

大型集团人才画像怎么在HR系统里落地?从五维度数据模型到标签引擎,提升人岗匹配效率

面向 HRIS 实施与 HR 数智化团队:结论先说——人才画像不是一份 Word 模板,而是一套「数据集成 标签引擎 能力建模 匹配推荐」的可计算链路。本文给出从五维度数据模型到工程落地的完整拆解,读完可照着在自有系统跑通。 人才画像的本质&am…

阅读更多 →
干货!这 8 款 AI 编程工具,帮你少走弯路!TaoToken 统一 Key 接入实测 2026/10/1 14:37:13

干货!这 8 款 AI 编程工具,帮你少走弯路!TaoToken 统一 Key 接入实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
钉钉机器人对接 OpenClaw 2.7.9 本地部署实操(附安装包与 TaoToken 配置) 2026/10/1 14:37:13

钉钉机器人对接 OpenClaw 2.7.9 本地部署实操(附安装包与 TaoToken 配置)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
轻松入门SpringAI:用TaoToken统一Key接入Spring AI其他模型 2026/10/1 14:37:13

轻松入门SpringAI:用TaoToken统一Key接入Spring AI其他模型

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
VSCode+EIDE开发STM32:把编译烧录链路改到TaoToken统一通道 2026/10/1 14:37:06

VSCode+EIDE开发STM32:把编译烧录链路改到TaoToken统一通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉