Flipper Zero 小行星游戏(flipper-asteroids)完全指南:玩法操作、安装部署与可复用的 2D 游戏引擎
【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper
本指南围绕开源仓库 flipper-asteroids 展开,介绍这款运行在 Flipper Zero 上的经典《小行星(Asteroids)》游戏实现——它不仅是可玩的完整游戏,还内置了一个可以复用到其他游戏的轻量 2D 引擎。读完本文,你将掌握该游戏的完整操作方式、高分存档机制、预编译.fap与源码两种安装路径,并从 app.c 的源码层面理解其渲染、物理与输入系统是如何在 128×64 单色屏上运转的。
一、项目概览:经典玩法 + 可复用的 2D 引擎
flipper-asteroids是经典街机游戏《小行星》在 Flipper Zero 上的一份实现。原版 README 明确指出,项目内包含一个简单的 2D 引擎,可以被复用来开发其他游戏——这一点在源码结构中得到充分印证:整个游戏的所有逻辑(渲染、物理、输入、存档)都集中在单个 app.c 文件中,大约 790 行,未依赖任何游戏框架,仅使用 Flipper Zero 官方固件提供的底层 API(GUI、输入、存储、通知服务)。
需要特别说明的是版本血缘:这个版本是SimplyMinimal 对 Antirez(Salvatore Sanfilippo)版本的 fork,并在原版基础上做了多处修改。源码文件头版权声明为Copyright (C) 2023 Salvatore Sanfilippo,而 LICENSE 文件显示版权归属 2022-2023 年。
应用的元信息定义在 application.fam 中,从中可以看到这个外部应用的完整身份:
| 字段 | 值 | 说明 |
|---|---|---|
appid | asteroids | 应用唯一标识,./fbt构建时使用 |
name | Asteroids | 菜单中显示的应用名 |
apptype | FlipperAppType.EXTERNAL | 外部应用,以.fap插件形式分发 |
entry_point | asteroids_app_entry | 应用入口函数 |
requires | ["gui"] | 依赖 GUI 子系统 |
stack_size | 8*1024 | 8 KB 栈空间 |
fap_category | Games_Extra | 归入游戏扩展分类 |
二、相对原版的改进(What's New)
这一 fork 的核心价值在于一批对游戏体验的增强。README 的 "What's New" 列表逐项如下,每一项都能在源码中找到对应实现:
- 自动连发(Auto rapid fire):按住 OK 键即可连续射击,同时减少按键物理损耗。源码中
asteroids_update_keypress_state()在检测到InputKeyOk按下时立即置位app->fire标志(app.c),game_tick()中则通过 200 毫秒的最小射击间隔(bullet_min_period)控制连发节奏(app.c)。 - 上键应用推进器(Up button applies thrusters):短按上键即可加速,同时屏幕会绘制推进火焰并触发震动反馈。
- 触觉反馈与 LED 特效:源码中定义了
sequence_thrusters、sequence_brake、sequence_crash、sequence_bullet_fired四组通知序列(app.c),分别对应推进、刹车、碰撞、开火事件;其中碰撞序列sequence_crash包含message_red_255,即被击中时屏幕红色 LED 亮起,配合震动马达模拟撞击感。 - 高分系统(High Score system):
AsteroidsApp结构体中有独立的score、highscore与is_new_highscore字段(app.c),击碎小行星得分后实时与历史最高分比较。 - 高分自动保存与加载:无需任何手动操作,游戏进程会自动将最高分写入 SD 卡(详见下文"高分存档机制"章节)。
- 部分玩法元素调整:例如游戏结束时生命显示重置为 3 条、小行星被击碎时的碎片分裂逻辑等,均与经典版本略有差异。
未来的计划
原文档同时列出了作者规划中的功能(尚未在当前源码中实现,属于路线图信息):
- 设置界面(Settings screen)
- 音效开关(可配置开启/关闭的声音效果)——源码中开火与碰撞序列里
message_note_g5、message_note_e5等声音消息目前均被注释掉,注释注明"需要 On/Off 菜单设置"(app.c),与路线图相互印证 - 道具系统(Power Ups)
三、操作方式:完整控制说明
README 给出的官方按键映射如下:
| 按键 | 动作 |
|---|---|
| 左键 / 右键 | 飞船左右旋转 |
| OK 短按 | 点射(发射少量子弹) |
| OK 长按 | 自动连发 |
| 上键 | 加速(应用推进器) |
| 下键 | 减速 |
| 长按返回键(Back) | 退出游戏,并自动保存最高分 |
结合源码可以更深入理解这些控制是如何被解析的:
- 旋转:
game_tick()中检测pressed[InputKeyLeft]/pressed[InputKeyRight],每帧将飞船旋转角ship.rot增减0.35弧度(app.c)。 - 加速与减速:上键按下时沿飞船朝向施加
0.5的加速度分量;下键则把当前速度乘以0.75实现阻尼减速(app.c)。 - 长按与短按的区分:
pressed[]数组记录每个键被按下的时间戳,key_pressed_time()据此返回按键持续时长(app.c);游戏结束画面中同样用key_pressed_time(app, InputKeyOk) > 100判断 OK 键长按以重新开局(app.c)。 - 退出:主循环中检测
InputTypeLong+InputKeyBack组合,在退出前若本局刷新了纪录会先行save_game()(app.c)。
高分会自动保存。这意味着退出游戏后再次进入,最高分会从 SD 卡恢复,与好友竞争纪录无需任何额外操作。
四、安装与部署
方式一:直接安装预编译二进制(无需构建)
从发行版(releases)下载asteroids.fap文件,放入 Flipper Zero 的以下目录:
/ext/apps/Games其中ext表示 SD 卡根目录。如果你不方便使用 Android(或其他)配套应用上传文件,可以直接取出 SD 卡插入电脑,把.fap文件复制到apps/Games目录下即可完成安装。结合上文application.fam中的fap_category="Games_Extra"可知,安装后在应用菜单的"游戏"分类下即可找到该应用。
方式二:从源码构建并安装
如果你希望自行编译或在此基础上继续开发,可以按以下步骤操作:
- 下载 Flipper Zero 官方固件开发套件并构建:
mkdir -p ~/flipperZero/official/ cd ~/flipperZero/official/ git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git ./ ./fbt- 将本应用文件夹复制到
official/application_user目录。 - 通过 USB 连接 Flipper。
- 构建并安装到设备:
./fbt launch_app APPSRC=asteroidsAPPSRC=asteroids对应 application.fam 中定义的appid。也可以直接把asteroids.fap放入设备后手动安装运行。
五、源码架构与实现原理
整个游戏是"单文件应用"的典范,理解它的结构对在 Flipper Zero 上开发其他小游戏非常有参考价值。
5.1 常量定义与全局参数
源码开头集中定义了核心游戏参数(app.c):
SCREEN_XRES = 128、SCREEN_YRES = 64:Flipper Zero 屏幕分辨率;GAME_START_LIVES = 3:初始生命数;TTLBUL = 30:子弹存活时间(tick 数);MAXBUL = 5:屏幕内最大子弹数;MAXAST = 32:屏幕内最大小行星数;SHIP_HIT_ANIMATION_LEN = 15:飞船被击中后的无敌动画帧数;SAVING_DIRECTORY = "/ext/apps/Games"、SAVING_FILENAME = "/ext/apps/Games/game_asteroids.save":高分存档路径。
5.2 数据结构:游戏状态如何组织
AsteroidsApp是贯穿全游戏的主结构体(app.c),分为四组:GUI 句柄(Gui*、ViewPort*、事件队列)、游戏状态(运行标志、游戏结束、tick、分数、最高分、生命、被击动画)、飞船状态(位置/速度/旋转角)以及子弹与小行星数组。飞船、子弹、小行星共用相似的位置-速度模型,旋转采用2*PI弧度制。
5.3 2D 绘制引擎:多边形、旋转与伪随机形状
这是 README 声称"可复用"的核心部分:
- 多边形抽象:
Poly结构最多容纳POLY_MAX = 8个顶点,rotate_poly()预先计算sin(a)/cos(a)后对每个顶点做旋转矩阵变换,避免重复调用三角函数(app.c)。飞船本体ShipPoly与推进火焰ShipFirePoly都是预定义的三角形。 - 小行星随机外形:为了让每颗小行星形状唯一但又保持稳定,作者用8 位 LFSR(线性反馈移位寄存器)生成可预测的伪随机序列,将每个顶点的半径在
0.7 ~ 1.3之间缩放,最终绘制为旋转后的八边形轮廓(app.c)。 - 子弹渲染:单像素在 128×64 屏上不够醒目,因此用 "+" 形五点图案绘制(app.c)。
- 屏幕回绕:所有物体越出屏幕边缘后会从对侧重新出现,这是《小行星》的标志性物理行为(app.c)。
- 界面元素:
render_callback()负责整屏绘制——清屏、左上角分数、右上角剩余生命(用小飞船图标表示)、飞船、子弹、小行星以及游戏结束画面(app.c)。游戏结束时最高分会居中放大显示,若刷新纪录则显示 "New High Score!" 提示。
5.4 游戏逻辑:碰撞检测与碎片分裂
- 碰撞检测的优化:
objects_are_colliding()用平方距离比较代替开方运算,避免在低性能 MCU 上做昂贵的sqrt()(app.c),并支持factor参数微调碰撞判定宽容度。 - 子弹发射:
ship_fire_bullet()让子弹从船头(而非中心)射出,速度叠加飞船自身速度,符合真实物理直觉(app.c)。 - 小行星生成:
add_asteroid()保证新生成的小行星与飞船保持至少20 + size像素的安全距离,避免"出生即死亡"(app.c)。 - 碎片分裂:
asteroid_was_hit()中,尺寸大于 6 的小行星会被击碎为 2 个以上碎片,碎片数量由尺寸决定;只有击碎小尺寸小行星才得分并更新最高分(app.c)。
5.5 主循环与游戏节奏
asteroids_app_entry()是应用入口(app.c):它分配应用状态、创建周期定时器,以furi_kernel_get_tick_frequency() / 10的频率触发game_tick()——即每秒约10 帧。源码注释解释了这一设计取舍:受 Flipper 屏幕刷新延迟限制,更高的 FPS 没有意义(app.c)。主循环通过furi_message_queue_get()消费输入事件队列,并区分处理"长按返回退出"与普通按键。
5.6 高分存档机制
存档实现非常直接但有效(app.c):
load_game():应用启动分配状态时即调用,尝试以只读方式打开game_asteroids.save,一次性读取整个AsteroidsApp结构体(sizeof(AsteroidsApp))来恢复游戏状态;save_game():若/ext/apps/Games目录不存在则先storage_simply_mkdir()创建,再以FSOM_CREATE_ALWAYS模式写入整个结构体;- 触发时机:本局刷新纪录时(
game_over()及退出时都会调用),既保证数据落盘,又避免了无谓的重复写入。
由于load_game()在asteroids_app_alloc()中于 GUI 初始化前执行,进程启动即完成恢复,因此高分数据在设备重启后依然有效。
六、许可证
本项目采用BSD 许可(LICENSE),版权归原作者 Salvatore Sanfilippo(antirez)所有,允许自由使用、修改与再分发(需保留版权声明与免责条款)。README 亦以 "BSD licensed. Enjoy." 结尾。这也意味着,基于其内置 2D 引擎开发自己的 Flipper Zero 游戏时,代码可以放心复用。
【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考