news 2026/9/7 9:47:00

Qt飞机大战游戏开发:从项目拆解到打包发布全攻略

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt飞机大战游戏开发:从项目拆解到打包发布全攻略

简介:这是一份以Qt框架实现“飞机大战”游戏的完整工程,适合具有一定C++基础、正在学习Qt图形界面与游戏逻辑的开发者作为练习参考。资源共223个文件,压缩包约6.21MB,其中包含105个h头文件、32个cpp源文件、60个png图片素材,以及ui界面文件、qrc资源文件、glsl着色器、wav/ogg音频和ttf字体等,整体结构清晰,覆盖了游戏从界面搭建到资源装配的完整链路。目前已有276人学习下载。包内不仅包含游戏核心代码,还引入了cJSON、CJsonObject等数据解析模块,并实现了ai_pve、ai_pvp_ai1、ai_pvp_ai2等单人/双人飞机对战模式;结合plane.cpp、player.cpp等角色控制源码,读者可以系统梳理碰撞检测、动画渲染、音效播放和多线程逻辑处理等关键实现思路,获得一份便于二次开发的完整Qt游戏项目工程。 这一篇我来聊聊一个不少Qt初学者都会拿来练手的项目:飞机大战游戏。我做Qt开发这么多年,每次看到有人把这个项目打包成 zip 发到群里或者论坛上,都会忍不住点进去看一眼。因为飞机大战这个题材虽然看起来简单,但它其实把 Qt 桌面开发的几大核心模块全都串起来了:事件循环、信号槽、绘图、定时器、碰撞检测、资源管理,甚至还有窗口布局和打包发布。你把这个项目吃透了,Qt 的入门门槛基本就跨过去一半了。

这篇文章我不打算只讲游戏怎么玩,我想从项目拆解的角度,把这类“qt飞机大战游戏.zip”压缩包里通常会涉及的代码结构和核心机制讲清楚,同时把我们平时开发 Qt 项目时经常踩的坑、容易忽略的点、以及从“能跑”到“能发布”的完整链路都整理出来。不管你是刚装好 Qt 准备练手的新手,还是已经在写界面但没做过游戏类项目的开发者,这篇都能给你一些实操层面的参考。

1. 项目核心诉求拆解:不是“写个游戏”,而是练熟事件驱动和绘图

飞机大战这类项目之所以能成为 Qt 教程里的常青树,核心原因就是它的逻辑闭环特别完整:玩家有输入,程序有反馈,游戏有实时状态变化,还有扣血、加分、结束这些状态迁移。这些东西如果放在传统控制台程序里写,你会发现特别别扭,因为控制台程序天生就是顺序执行的。而 Qt 程序是事件驱动的,整个程序跑起来之后,不是“从上到下执行完就退出”,而是进入一个事件循环,不断去响应外部的输入信号、定时器信号、网络信号等等。

飞机大战游戏天然就适合这种事件驱动模型。玩家按键盘,这是一个 QKeyEvent;敌机移动,这是 QTimer 在驱动;子弹射中敌机,这是坐标碰撞的判断;分数变化,这是信号槽触发的界面更新。你把这些机制都跑通了,你对 Qt 的理解就远不止“能用 Designer 拖几个控件”这个层面了。

我见过很多初学者拿到一个飞机大战的压缩包,解压之后直接去找 main.cpp,然后试图顺着代码一行一行读下去。这种思路其实不太高效。更好的方式是先掌握几个关键类的职责划分。一般这种项目里会涉及主窗口类、游戏场景类,或者直接用 QGraphicsView/QGraphicsScene 体系来做。用 QGraphics 体系的好处是它提供了 Item 的概念,每架飞机、每颗子弹、每个敌人都是一个 QGraphicsItem,它可以有自己的坐标、自己的碰撞区域、自己的绘制逻辑,而且框架会自动帮你处理它们之间的叠放顺序和重绘。对于飞机大战这种多对象高频运动的场景,用 QGraphics 体系比手动 paintEvent 画全屏要省心很多。

2. 关键技术路线选择:为什么大多数项目选 QGraphicsView 而不是手动绘制

很多从零手写的老教程喜欢在 QWidget 上重写 paintEvent,然后自己维护一个对象列表,每次刷新都重新绘制。这种方案不是说不行,但它的痛点非常明显:一旦对象数量超过几十个,你手动管理刷新区域就很容易出现性能问题或者闪烁问题;而且碰撞检测、对象删除、层级管理这些全都得自己写。

用 QGraphicsView + QGraphicsScene + QGraphicsItem 这套组合拳来写飞机大战,逻辑会清晰得多。QGraphicsScene 负责管理场景中所有的 Item,QGraphicsView 负责把场景渲染到界面上。每个 Item 只需要自己去实现 boundingRect() 和 paint() 方法,框架就会在需要的时候调用,而 Qt 的视图框架本身做了局部重绘优化,不会每次全窗口都刷一遍,这就是顺滑感的重要来源。

当然,选这条路也有额外的学习成本。你首次接触 QGraphicsItem 时,最容易绕晕的一个点是坐标系统。Item 的坐标是相对于它自己的,Scene 的坐标是整个场景的,View 上的坐标是最终你看到的屏幕坐标,三套坐标系互相转换时特别容易出现物体“飘走”的问题,这个问题我在后面排查章节里还会专门展开。

还有一点值得提的是帧率控制。很多初版代码会在按键事件里让飞机直接跳一段固定距离,比如每次按一下移动 10 像素。这样做出来的手感会很生硬,因为不同电脑的按键重复速率不一样,按下时间长短也会影响移动距离。更专业的做法是引入一个 QTimer,设定在每秒 30 帧、60 帧这样的频次上刷新,每次刷新时根据当前按键状态来决定飞机的位移量。这样逻辑上就分成了“输入采集”和“游戏更新”两个阶段,后面你再去加子弹、加敌人、加变速效果就很自然了。

3. 用 QTimer 驱动游戏循环:搭出稳定主循环的三个要点

飞机大战的核心战斗力其实不在于飞机画得多好看,而在于主循环是否稳。主循环负责三件事:采集用户输入、更新游戏状态、触发重绘。

在 QGraphicsView 框架里,你不需要主动去调 update() 来重绘整个窗口,只需要在定时器里让场景里的所有 Item 坐标发生变化并调用 scene 的 update 方法即可。更省事的做法是每个 Item 的坐标有变化时,调用自身的 update(),或者直接依赖 QGraphicsScene 的刷新机制。但有一点要注意:当你让每个 Item 自己负责移动时,最终他们的移动节奏必须由同一个时钟源驱动,否则不同对象之间会出现肉眼可见的不同步。

我自己的习惯是只创建一个 QTimer,interval 设在 16ms 左右,对应大约 60 帧。然后在它的 timeout 信号里统一处理:先遍历玩家输入状态,再更新玩家飞机的位置,生成新的子弹,更新所有敌机的位置,检查碰撞,最后清理掉已经飞出场景的子弹和敌机。这样做的好处是整局的逻辑顺序始终一致,不会出现“子弹都打出去了,敌人还没刷新”这种错拍问题。

还有一个很多人忽略的小细节:QTimer 的精度并不适合直接用来做长时间精确计时。如果你是想统计游戏时长或者限制局数时间,不要简单地把定时器的触发次数乘以间隔,而应该用 QElapsedTimer 来记录真实的流逝时间。因为定时器在系统繁忙时可能会被延后触发,次数累加出来的时间会漂移。

4. 按键交互与移动手感:别让飞机“慢半拍”

飞机大战的操作手感直接决定这个游戏好不好玩。很多初版代码里都用 keyPressEvent 和 keyReleaseEvent 来记录按键。这里有一个经典坑点:如果你只在 keyPressEvent 里改变位置,那么会出现“按住一个方向键,飞机动了一下就停了”的现象。原因很简单,按键事件并不会连续不断地触发,系统响应按键按下操作之后,要过一段时间才会开始重复触发,而且这个重复节奏还不是你能轻易控制的。

解决思路有两个层面。第一个是维护一套 bool 类型的按键状态数组,在 keyPressEvent 里把对应方向的状态置为 true,在 keyReleaseEvent 里对应方向的状态置为 false。这样按键“按下了没有”就和“飞机怎么动”解耦了。第二个是在主循环里根据这套按键状态去改变飞机坐标,而不是在事件里直接改坐标。这套思路在很多游戏开发框架里叫“轮询输入”,比单纯依赖事件驱动更可控。

移动手感上的另一个关键点是加速度。直接给飞机一个固定速度虽然简单,但玩起来会显得很呆。你可以在键盘状态为 true 时逐步把当前速度向量向目标方向插值,比如每次循环把速度加上一个加速量,同时做一个上限限制。这样玩家控制飞机转向的时候会有轻微的惯性感,操作体验会好很多。对于新手来说不需要追求特别复杂的物理模型,一个简单的线性加速加阻尼就已经能让手感有明显提升。

5. 碰撞检测的实用套路:矩形碰撞为主,shapes 相交为辅

碰撞检测是飞机大战里最容易出“玄学 bug”的地方。很多人的第一版实现是遍历所有子弹,逐个判断子弹坐标是否落在敌机矩形范围内。这种方式在小规模情况下确实可行,但写起来容易出两类问题:一类是因为坐标系不统一,子弹明明看上去打中了,代码却判定未命中;另一类是因为需要遍历所有子弹和所有敌机,当对象数量多了以后,性能会出现指数级的下降。

在 QGraphicsItem 框架中,最简单的碰撞检测方式就是调用 QGraphicsItem::collidesWithItem() 或者直接使用 shape() 相交运算。框架默认情况下会用 Item 的 boundingRect 来做碰撞判断,但如果你希望判断更精确一点,可以重写 shape() 方法,返回一个更精确的 QPainterPath,比如去掉图片四角透明区域的外轮廓。用 QPainterPath 相交来判断碰撞,直觉上更好用,不过需要注意 shape() 的性能开销,如果场景里的对象特别多,还是建议在碰撞检测前先做一个大致的区域筛选,比如只检查同一片 X 坐标范围内的对象。

我还踩过一个非常经典的坑:把碰撞检测放在 Item 的 paint() 里做。那是在一个很早期的项目里,我看到 paint() 里能拿到当前 Item 的位置,就觉得“顺手”把碰撞逻辑也写进去了。结果就是实际的画面重绘和游戏逻辑被强行耦合在了一起,一旦你调用 update() 的频率发生变化,碰撞结果也跟着变,有的子弹甚至会直接“穿墙”。后来我把所有碰撞检测全部挪到了统一的主循环里去做,问题就消失了。

6. 对象管理与内存释放:防止游戏越玩越卡

游戏越玩越卡,这是飞机大战类项目里除了崩溃之外最容易被抱怨的问题。绝大多数情况下,这种卡顿不是 Windows 的问题,而是对象没释放。子弹射出去了,飞出屏幕边界了,代码里如果不做清理,QGraphicsScene 里的 Item 就会越积越多。场景里的 Item 数量一旦上千,即使它们都是不可见的,也会拖慢整个场景的刷新和碰撞判断。

处理办法是在主循环里定期扫描场景里的对象,把飞出边界的子弹、被击中的敌机、爆炸特效的动画 Item 等都从 Scene 中移除。移除时要区分了 deleteLater() 和直接 delete 的区别。在信号槽处理过程中直接 delete 一个对象可能会引发难以追踪的崩溃,尤其是当这个对象还和某些信号槽关联时。我的习惯是:先把对象从 Scene 移除,然后调用它的 deleteLater() 方法,让它安全地在事件循环的后续阶段被销毁。如果你用的是 QGraphicsScene::removeItem(),记得不要让原指针变成悬挂指针,最好的做法是移除后立刻将指针置空。

这里也顺带提一个性能优化思路:不要频繁地 new 和 delete 子弹对象。比较进阶的做法是对象池,在游戏初始化时预创建一批子弹 Item,发射子弹时从池子里取一个“活的”,飞出边界时把它标记为“死的”并归还池子。对象池不是必须的,但当你的游戏想上强度,一屏同时存在几百颗子弹时,你就会明白它有多香。

7. 界面设计与反馈:从能玩到“像样”的关键一跃

很多初版飞机大战的界面就是一张黑色背景加几个色块,能玩,但没有游戏的感觉。想让项目看起来完整,主要需要补三块:一是合理的游戏状态管理,比如开始界面、游戏进行中、暂停、结束;二是分数和生命值这类信息的实时展示;三是击中敌人、爆炸这类视觉反馈。

用 Qt 做状态切换的常用方式有两种。一是用 QStackedWidget 堆叠不同的页面:开始界面是一页、游戏场景是一页、结束界面是一页。二是用状态机或者单纯在同一个 Widget 里用 if 区分状态。对于飞机大战这种规模,用 QStackedWidget 会更清晰,因为三个页面的 UI 完全不一样,硬塞在一个界面里会让布局互相干扰。

分数的实时展示,新手最容易直接放在 paint() 里画文字,这么做不是不行,但会让分数逻辑散落在绘图代码里。更好的办法是:在场景中放一个 QGraphicsTextItem,或者单独一个得分 label 放在主窗口的布局里。当得分变化时,通过信号槽去更新文本内容。这样数据层和显示层就解耦了,后面无论是加音效、加震动、加弹窗,你都会觉得顺手得多。

爆炸反馈这部分,最省事的方式是做一个小动画,让一个 Item 在生命周期内逐渐变大并且透明度逐渐降低。透明度变化可以通过 QGraphicsOpacityEffect,也可以用最原始的 QPainter 设置 opacity。对于初学者,我个人建议直接用定时器配合 setScale 和 setOpacity 这两个属性做简单缩放淡出效果,代码量小,视觉上又比直接删除物体自然很多。

8. 项目工程组织与资源管理:压缩包解压后能不能直接跑起来

拿到任何一个 Qt 项目压缩包,最让人头疼的往往不是核心逻辑,而是工程缺东少西。一个标准的 Qt Widgets 项目,不管是不是飞机大战,最基本的文件结构应该包括:.pro 工程文件、main.cpp、主窗口的实现和头文件、游戏场景或 Item 类的实现和头文件,以及如果有图片资源的话,还要有一个资源文件。

在 .pro 文件里,有几个配置需要注意。如果项目里用了 QGraphicsView 相关的类,一般需要加 QT += widgets,因为 Qt5 以上把 widgets 模块从 core/gui 里拆出来了。如果你用了多媒体播放音效,那还要加 QT += multimedia。如果用了网络请求,那就是 QT += network。很多新手把代码从别人的压缩包里抄过来,遇到“找不到头文件”的报错,八成就是 .pro 里的模块没写对。

资源文件也是一个大坑。有些压缩包里的项目是用相对路径直接加载图片的,比如 QPixmap(":/images/player.png") 这种写法,冒号开头表示项目资源文件里的路径;但有些旧项目写的是 QPixmap("images/player.png"),这种相对路径在 Qt Creator 里调试时可能能跑,但打包发布后大概率会找不到图片。真正稳妥的做法是:把所有图片资源放进 .qrc 资源文件里,统一用冒号开头的资源路径访问。这不仅能保证发布后图片不丢,还能把这些二进制数据直接编译进可执行文件,省去你到处拷图片的麻烦。

资源管理这一块,我实际经验是:能用 qrc 就用 qrc,除非你会用 Qt 的部署工具做精细化的外部资源目录管理。qrc 最大的好处是单一可执行文件就能完整运行整个程序,这对后面做“绿色版”分发特别方便。

9. 编译问题与运行环境排查:那些高频出现的报错怎么处理

飞机大战这种工程一旦编译报错,常见场景其实挺集中的。我这里按出现概率排个序:

第一个高发问题是“dependent 路径下找不到 include 文件”。这种报错通常长这样::-1: error: dependent '........\allinstall\qt\5.15.2\msvc2019\include\QtWidgets\qwidget.h' does not exist。很多初学者看到这串路径会一脸懵。其实这是 Qt Creator 在工程配置时记录了一个已经失效的 Qt 安装路径。解决办法通常是:清理构建目录,在 Qt Creator 里重新选择当前正确的 Qt Kit,或者手动把工程文件重新构建一遍。如果顽固复现,还要检查是否安装了多个版本的 Qt 导致环境变量混乱。

第二个高发问题是“No such file or directory”或者“cannot find -lQt5Widgets”。这种一般是 Qt 库依赖没找到,尤其在换电脑或者换 Qt 版本之后比较常见。Windows 上优先检查 PATH 环境变量里是否包含 Qt 的 bin 目录,因为你编译链接时不仅需要库文件本身,运行程序时还需要对应的动态链接库。

第三个高发问题和打包相关,具体报错是“no Qt platform plugin could be initialized”。这种错误几乎每个人在把自己的 Qt 程序拷到别的电脑上跑时都会遇到一次。它背后的原因很简单:你的 exe 找不到 platforms 目录下的 qwindows.dll。Qt 的窗口程序在启动时会通过插件系统加载平台集成插件,如果插件缺失,程序就起不来。这里顺带说一句,很多人看到这个报错就跑去网上找各种“破解方案”,其实最正规的办法就是用 Qt 自带的 windeployqt 工具来部署,它会自动把你的 exe 依赖的所有库和插件整理到一个目录下,完事之后那个目录就是一份干净的绿色发布包。

编译器类型也值得说一嘴,特别是你用 MSVC 还是 MinGW 编译的。MSVC 编译出来的程序依赖 VC 运行库,目标电脑如果没有装对应版本的 Visual C++ Redistributable,程序会崩溃或者闪退;而 MinGW 编译出来的则依赖 libgcc、libstdc++ 和对应的 Qt 库。整体来说打包时建议用 windeployqt 跟着编译器走,配套发布,不要混用。

10. 扩展与进阶:飞机大战项目还能往哪些方向升级

飞机大战这种项目最妙的地方是它的扩展空间特别大,一个基础版本你完全可以从不同方向去强化,学习价值非常高。

进阶方向一:加网络对战。Qt 的 QTcpSocket 和 QUdpSocket 模块都是现成的,你可以把玩家的坐标和按键状态通过 UDP 包发送给对方,实现一个简单的双人实时对战。这个方向会把游戏开发和网络通信结合起来,做出来之后的成就感很足。不过要注意网络包的频率控制,不要每秒发几百个包,很容易把网关打懵。类似地,如果你用 HTTP 的 post 请求发送游戏成绩到服务端排行榜,这也能串起 Qt 的 QNetworkAccessManager 模块,和很多人搜的“qt get方式”和“qt post方式”用法正好能对上。

进阶方向二:加音效和背景音乐。Qt 多媒体模块可以直接播放 wav 和 mp3 文件,打击感会得到大幅提升。这里有个细节:音效文件尽量采用短小的 wav 文件,因为它的加载性能好,循环播放和即时触发的响应速度都优于 mp3。配乐则用 mp3 或 ogg 都可以,重点在于用 QMediaPlayer 时要正确设置播放列表。

进阶方向三:加特殊道具、Boss 战、波次刷新。这就是把游戏策划的思想引入进来了。你会发现当项目复杂度上升后,代码结构的设计比堆功能更重要。子弹、敌人、道具能不能抽象成统一的“游戏实体”基类?敌人生成能不能用“波次配置表”来驱动,而不是硬编码在代码里?如果我们想把这些内容做开发维护,引入配置文件或者简单的脚本驱动机制就顺理成章了。有人可能因此就开始琢磨怎么接一个 Lua 或者 JavaScript 的脚本引擎,这也是 Qt 项目通往大型游戏开发的自然路径。

进阶方向四:和视觉图表类库联动。你可能会觉得奇怪,飞机大战怎么做数据可视化?其实可以做得很炫,比如把整局游戏的实时击发数、移动轨迹、存活时间等参数采集下来,用 QCustomPlot 绘制成曲线图展示在结算页面。QCustomPlot 本身是一个成熟的 Qt 绘图库,很多人搜“qcustomplot 时域图转频域图”主要是做信号分析,但用它来画游戏数据曲线一样顺手。如果你把飞机移动的轨迹数据经过 FFT 转换,甚至能得到一个“玩家操作频谱”,这种跨界玩法拿来放在作品集里,非常加分。

11. 从代码到可执行文件:最终打包发布的完整流程

当你的飞机大战游戏在 Qt Creator 里能正常运行后,下一步是把它变成一份可以发给朋友的绿色可执行文件目录。

以 Windows 平台为例,我用的是 Qt 5.15.2 + MSVC 2019 那一套工具链,流程大概是这样的:

  • 先在 Qt Creator 里选择 Release 模式,重新构建一遍整个项目,确保没有任何编译错误和链接错误。
  • 构建完成后,去项目的构建目录下找到生成的 exe 文件,把它单独复制到一个新的文件夹里。
  • 打开 Qt 文件夹对应编译器版本目录下的命令提示符,也就是 Qt 5.15.2 MSVC 2019 64-bit 那个入口。
  • 把当前目录切换到刚才那个新的文件夹,执行命令 windeployqt 你的程序名.exe。
  • 等待工具跑完,它会自动把需要的 Qt 库、platforms 插件、styles 插件等全部复制进来。
  • 如果你用到了音效、图片等外部资源,手动把它们统一放进来。如果你用的是 qrc 资源文件,其实这一步可以省掉一部分。
  • 最后将整个文件夹压缩成 zip,这份就是最终可以分发的成品。

发布到其他电脑后,只要它不欠 VC 运行库,基本双击就能跑。如果双击没反应,用命令行手工启动,看看输出的报错信息,通常已经很直白了。

打包这件事,我自己以前也偷懒过,把整个 Debug 目录整个扔给别人跑,结果体积巨大还依赖一堆开发环境,最后对方还是跑不起来。后来规矩了,一律 Release 构建加 windeployqt 发布,基本上再也没被反馈过环境问题。

12. 常见问题速查表

最后整理一份高频问题清单,这些都是我在网上帮别人看代码时经常碰到的问题,你可以直接当速查表用:

现象常见原因解决思路
飞机按住方向键只动了一下在 keyPressEvent 里直接改坐标改为按键状态布尔数组加主循环轮询
场景里对象多了之后越来越卡子弹/敌机对象未清理定时清理边界外对象,使用 deleteLater 删除
图片加载不出来图片资源路径写错统一使用 .qrc 资源,路径以冒号开头
编译时报找不到 include工程里记录的 Qt 路径失效清理构建目录并重新选择 Qt Kit
程序拷贝到别的电脑后启动报 no Qt platform plugin缺少 platforms 目录或插件使用 windeployqt 正确部署
子弹打中敌人但代码判断没中Item 的坐标体系和场景坐标混淆明确区分 item 坐标、scene 坐标和 view 坐标
按住按键后飞机移动速度忽快忽慢使用了按键事件重复触发而不是轮询在主循环中统一读取按键状态
分数显示更新不及时分数变量和界面文本耦合不佳用信号槽连接游戏逻辑与界面更新
程序运行后闪退但没有明显报错访问了已删除的对象检查删除指针后是否置空,是否存在悬空指针
音效播放有延迟使用了较大的 mp3 文件做即时音效使用短小的 wav 文件做特效音

飞机大战这个项目做下来最值钱的地方,并不是游戏本身有多好玩,而是它能强迫你把 Qt 的事件循环、绘图机制、对象生命周期管理、信号槽协作这些核心概念全部过一遍。等你把这些东西内化之后,再去写界面工具、写工业上位机、写数据可视化面板,都会明显顺手不少。我见过好几个同事的入职练手项目都是从这类小游戏开始,慢慢过渡到正经的 Qt 业务开发的。这个压缩包,建议不要只是解压看一眼,最好亲手再敲一遍,踩上几个真实的坑,那才是真正学到东西的时刻。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 9:46:59

半球积分 Ω:渲染方程中的核心数值挑战

一、开场:为何 2π sr 是个工程难题 渲染方程最简洁的形式是: L_o(p, ω_o) = L_e(p, ω_o) + ∫_Ω f_r(p, ω_i, ω_o) L_i(p, ω_i) (n ω_i) dω_i那个看似无害的 ∫_Ω 符号,描述的是着色点 p 上方整个半球(立体角 2π sr)上的连续积分。这个积分在数学上无法解…

作者头像 李华
网站建设 2026/9/7 9:45:13

STM32F103C8T6点灯Demo硬核拆解:从GPIO到工程调试全流程

简介:一份基于STM32F103的32x64双色点阵屏静态显示演示工程,面向嵌入式显示驱动开发与STM32入门学习者。工程采用HUB08接口连接双色LED点阵屏,通过连续更新像素状态实现静态图像输出,覆盖系统时钟与GPIO初始化、PWM亮度控制、显示…

作者头像 李华
网站建设 2026/9/7 9:41:40

minimaxh3漫剧落地:ComfyUI工作流搭建与批量生产指南

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

作者头像 李华
网站建设 2026/9/7 9:40:06

赛车开奖动画实战:基于原生JS与CSS的状态机驱动实现

简介:赛车开奖动画源码是一套基于HTML5、CSS和JavaScript及jQuery实现的互动式赛车开奖展示程序,适合前端开发者、游戏爱好者或需要搭建趣味抽奖场景的运营人员学习与二次开发。资源以北京赛车为视觉主题,通过精致的PNG/GIF素材与CSS动画模拟…

作者头像 李华