SerenityOS 内置小游戏 Flappy Bug 完全指南:玩法、源码实现与运行方式
Flappy Bug 是 SerenityOS 官方仓库中自带的迷你游戏,基于 2013 年风靡一时的 Flappy Bird 玩法重制,并加入了 SerenityOS 的 Bug 主题美术风格。本文以系统自带的手册文档 FlappyBug.md 为核心骨架,结合 Userland/Games/FlappyBug/ 下的完整源码,系统讲解该游戏的操作方法、玩法机制、源码实现原理以及如何在系统内外运行,帮助读者从玩家与开发者两个视角吃透这个经典小游戏。
基本信息与启动方式
命令入口
Flappy Bug 作为 SerenityOS 的终端命令(man 分类 6,即游戏手册),在终端中直接输入命令名即可启动:
$ FlappyBug
运行后会弹出一个 560×480 的固定尺寸游戏窗口(不可调整大小),窗口标题为 "Flappy Bug"。除命令行外,也可以从系统的游戏(Games)菜单中启动——应用注册文件 FlappyBug.af 将其归类为 &Games 类别,可执行文件指向 /bin/FlappyBug。
构建与安装
该游戏通过 CMakeLists.txt 集成进 SerenityOS 构建系统,并被标记为 RECOMMENDED 组件,因此使用标准的 SerenityOS 构建流程即可编译并安装到系统镜像中。编译产物的链接依赖包括 LibCore、LibGfx、LibGUI、LibConfig、LibMain、LibDesktop 与 LibURL,覆盖了窗口绘制、配置读写、帮助文档启动等能力。
游戏玩法与操作
核心目标
Flappy Bug 的目标非常简单直接:尽可能长时间地让 Bug 存活,避开沿途的障碍物。游戏画面中,玩家控制的 Bug 处于屏幕左侧固定横坐标(源码中 x = 50),它会因为重力作用自动下落,玩家按下任意按键即可让它向上"扑腾"一下。
操作方式
| 操作 | 效果 |
|---|---|
| 任意按键(方向键/字母键/空格等) | Bug 向上扑腾(flap),或开始/重新开始游戏 |
| 鼠标左键 | 与按键等效,同样触发扑腾 |
Esc |
立即退出游戏 |
从源码 Game.cpp 可以看到按键处理的细节:keydown_event 会先过滤掉带修饰键(如 Ctrl/Alt)的按键以及 F1、F11 等系统功能键,随后对 Esc 直接调用 GUI::Application::the()->quit() 退出应用,其余按键统一进入 player_input();鼠标按下事件 mousedown_event 同样调用 player_input()。也就是说,几乎任何普通的键盘输入或点击鼠标都能让 Bug 扑腾,上手零门槛。
游戏流程
- 首次启动时画面中央显示 "Press any key to start"(按任意键开始);
- 按下任意键后游戏进入活动状态,Bug 开始受重力下落,玩家需要不断按键维持高度;
- 游戏中屏幕右上角实时显示当前得分(白色数字);
- Bug 撞到上下障碍物、飞出屏幕顶端或底端即游戏结束;
- 结束后画面中央显示本局得分与历史最高分,短暂冷却后提示 "Press any key to play again"(按任意键再来一局)。
源码级原理剖析
Flappy Bug 的全部游戏逻辑位于 Game.h 与 Game.cpp 两个文件中,核心类 FlappyBug::Game 继承自 GUI::Frame,通过 LibGUI 的事件系统驱动。理解它有助于把玩法描述落回到可验证的实现细节上。
物理模型:重力、扑腾与速度
Bug 的物理行为由 Bug 结构体实现,全部采用浮点坐标:
- 重力:每帧调用
fall(),velocity += 1.0f(重力加速度恒为 1); - 扑腾:每次输入调用
flap(),velocity = -10.0f,即给 Bug 一个向上的瞬时冲量; - 位移:
apply_velocity()中y += velocity更新纵坐标。
游戏每 16 毫秒触发一次定时器(约 60 FPS)驱动物理与逻辑更新,因此一个扑腾带来的上升效果大约在 10 帧内被重力完全抵消,玩家需要持续、有节奏地按键才能保持高度。
障碍物与碰撞检测
障碍物由 Obstacle 结构体表示,宽度固定为 20 像素,颜色为深灰(Color::DarkGray):
- 每次重置时,障碍物从屏幕右侧(
x = game_width + width)出现,中间缺口(gap)的顶部位置gap_top_y在0到game_height - gap_height之间随机生成,缺口高度gap_height = 175; - 障碍物每帧向左移动
4 + m_difficulty / 16.0f像素,速度会随游戏进行逐渐加快,这正是"难度递进"的实现方式; - 碰撞判定使用矩形相交:Bug 的圆形包围盒(以
(50, y)为圆心、半径 16)与障碍物的上矩形、下矩形做intersects检测,一旦相交立即game_over();同时 Bug 的 y 坐标超出屏幕范围(y > game_height || y < 0)也判负。
得分与难度递进
- 活动状态下每帧
m_difficulty += 1.0f / 16.0f,得分即当前难度值,最终通过get_final_score()四舍五入取整显示; - 难度值同时参与障碍物与云朵的移动速度计算,游戏越久,画面整体移动越快;
- 游戏结束时会通过
on_game_end回调把最终得分交给主程序。
云朵与背景:纯装饰的视差层
为了增强视觉层次,游戏加入了装饰性的云朵层 Cloud:
- 云朵从三张不同的位图(
cloud_0.png、cloud_1.png、cloud_2.png)中随机选取一张,随机出现在屏幕上半部; - 云朵以
m_difficulty / 16.0f的慢速向左飘动,飘出屏幕后重新在右侧生成; - 背景使用平铺位图
background.png填充整个画布,Bug 则根据当前速度方向切换两套美术资源:上升时(velocity < 0)显示falling.png,否则显示flapping.png。
最高分的持久化
最高分不会因退出而丢失。主程序 main.cpp 通过 LibConfig 读写配置:
- 启动时读取
Config::read_i32("FlappyBug", "Game", "HighScore", 0)载入历史最高分; - 每局结束,若当前得分高于最高分,则通过
Config::write_i32("FlappyBug", "Game", "HighScore", score)写回配置域FlappyBug的Game分组。
这套配置与 SerenityOS 的全局配置系统(LibConfig)无缝集成,最高分会持久化保存在系统配置中,重启游戏依然有效。
窗口与菜单
主程序还做了三项值得留意的初始化工作(对应 main.cpp):
- 权限收窄:通过
pledge/unveil系统调用将进程权限收紧到只读/res资源目录与启动门户,体现了 SerenityOS 的"最小权限"设计哲学; - 帮助文档集成:向启动器(Launcher)白名单注册了当前这份手册文档,菜单栏的 Help 项可直接用系统帮助程序打开本页手册;
- 标准菜单栏:包含 Game(退出)、View(全屏切换
F11)、Help(命令面板、帮助、关于)三组菜单,与系统其他应用保持一致的交互习惯。
常见问题与实用提示
- 如何退出游戏? 按
Esc键,或点击菜单栏 Game → Quit。 - 如何查看帮助? 在游戏菜单栏 Help 中打开帮助,或直接在终端运行
man FlappyBug阅读本文档对应的手册页。 - 为什么游戏不可调节窗口大小? 因为
window->set_resizable(false)将窗口固定为 560×480,这是开发者有意为之,保证碰撞判定与美术布局的一致性。 - 最高分存在哪里? 由 LibConfig 管理,位于配置域
FlappyBug/ 分组Game/ 键HighScore,重启系统与游戏后依然保留。
总而言之,Flappy Bug 虽然是一个体量小巧的休闲游戏,却在源码中完整示范了 SerenityOS 的 GUI 事件循环、定时器驱动动画、矩形碰撞检测、位图资源加载与配置持久化等基础能力。无论是想在系统里放松几分钟,还是想研究一个"麻雀虽小、五脏俱全"的 LibGUI 示例项目,它都是非常合适的入口。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.21 K636- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python80
jforgamejforgame是一个一站式游戏服务器开发框架。包含游戏服务器开发所需要的各种组件,比如网关,socket服务端与客户端,自定义高效消息编解码,游戏热更新,游戏通用工具等等。包含游戏服,跨服,匹配服,后台管理系统等实现,同时提供大量业务案例以供学习。亦可用于其他socket应用,例如及时聊天等。Java201
fizz-gateway-nodeAn Aggregation API Gateway in Java . FizzGate 是一个基于 Java开发的微服务聚合网关,是拥有自主知识产权的应用网关国产化替代方案,能够实现热服务编排聚合、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理、回调管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。Java110
certd开源SSL证书管理工具;全自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔;https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署JavaScript120
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python300