
Flipper Zero 上的 DnD DiceTRPG 掷骰子应用的构建、使用与源码解析【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/FlipperDnD Dice是一款运行在 Flipper Zero 上的桌面掷骰子应用FAP 外置应用内置 Coin、d4、d6、d8、d10、d12、d20、d100 共 8 种骰子类型支持一次投掷多枚骰子、自动求和并带有完整的滚动动画。本文基于 Applications/Official/source-OLDER/kyhwana/dice2/README.md 及配套源码从编译构建、安装部署、实际操作到内部状态机与渲染原理逐层展开读完你既能把它编译进自己的 Flipper Zero也能完全理解这个应用背后的 GUI 编程范式。DnD Dice 主界面截图DnD Dice 投掷结果界面截图功能概览为 TRPG 桌面扮演而生的骰子盒DnD Dice 面向《龙与地下城》等 TRPG 玩家把现实中一整套骰子收纳进了 Flipper Zero 的 128×64 单色屏幕中。按原文档说明应用支持以下骰子类型类型面数名称源码中定义典型用途Coin2Coin抛硬币判定、随机二选一d44d4匕首、法术骰d66d6属性骰、常见伤害骰d88d8长弓、中型伤害骰d1010d10百分比骰的十位d1212d12巨斧等重武器d2020d20攻击检定、豁免、技能检定d100100d100百分比掷骰在 constants.h 中可以看到这 8 种骰子被建模为一个Dice结构体数组每种骰子只记录三个信息type面数、屏幕坐标x/y和显示名称name。除了骰子种类齐全应用还有几个实用设计多枚投掷与自动求和一次最多投掷 10 枚骰子MAX_DICE_COUNT常量结果界面同时展示总和与每一枚的明细动画反馈投掷时骰子有逐帧滚动动画结果数字会从屏幕上部落入一个结果边框内result_frame_pos_y定义了下落关键帧合理的输入约束Coin 与 d100 被设计为单骰类型isOneDice()自动锁定数量为 1避免逻辑上无意义的多次投掷。仓库目录结构在深入编译与源码之前先整体认识一下这个应用的完整工程布局位于Applications/Official/source-OLDER/kyhwana/dice2/dice2/ ├── README.md # 官方说明文档 ├── LICENSE.md # GPL-3.0 开源许可 ├── application.fam # FAP 应用清单编译系统元数据 ├── constants.h # 常量、骰子表、状态机定义 ├── dice_app.c # 应用主逻辑入口、事件循环、渲染 ├── icon.png # 应用列表图标10×10 ├── assets/ # FAP 图标资源骰子各帧、UI 按钮、计数与结果框 └── sources/ # Pixilart 像素画源文件与效果截图其中sources/目录保留了d20.pixil、d6.pixil、result_border.pixil等 Pixilart 像素画工程源文件Pixil 2.6.1 格式含图层与内嵌 base64 位图数据说明应用的全部美术资源都是像素画风格方便开发者直接用 Pixilart 编辑后重新导出。编译构建从源码到 .fap 文件原文档给出了标准的 Flipper 外置应用编译流程。Flipper Zero 的应用以FAPFlipper Application Package形式分发需要借助官方固件仓库的fbtFlipper Build Tool构建系统来交叉编译。完整步骤如下第一步获取固件源码克隆 flipperzero-firmware 官方仓库或使用你日常刷写的第三方固件如 unleashed-firmware。编译产物会因固件分支的 API 版本差异而不同因此选择与你的设备固件匹配的分支最重要。git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git第二步把 dice2 工程链接进固件的用户应用目录固件源码中有一个专用的用户应用目录applications_user凡是要以 FAP 方式单独编译的应用都需要在这里被引用。原文档要求创建名为dice的符号链接指向本仓库dice2 目录cd flipperzero-firmware ln -s /path/to/dice2 applications_user/dice说明符号链接名dice需要与工程内部实际使用的名称区分开——应用真正的appid是DND_Dice_app见下文application.fam解析符号链接名只是让fbt能在用户应用目录中发现该工程的路径。第三步编译在固件仓库根目录执行./fbt fap_dice_dnd_app这里的fap_dice_dnd_app是 fbt 自动生成的 FAP 构建目标命名规则为fap_appid因此对应appidDND_Dice_app。编译系统会调用交叉工具链将 dice_app.c 与constants.h编译为可执行 FAP 包并把assets/中的图标资源一并打包进去。第四步定位产物编译完成后FAP 文件位于固件构建目录build/f7-firmware-D/.extapps/dice_dnd_app.fapf7-firmware-D表示 debug 配置的 F7 芯片固件构建目录release 配置为f7-firmware-R.extapps是 fbt 收集所有外置应用产物的目录。安装部署把 FAP 装进 SD 卡得到dice_dnd_app.fap后原文档推荐两种安装方式手动拷贝将.fap文件复制到 Flipper Zero SD 卡的apps/Games目录这与application.fam中fap_categoryGames的设置一致然后从应用的Games游戏分类中启动qFlipper 桌面客户端通过 qFlipperFlipper 官方 PC 管理工具的文件管理/应用安装功能直接推送自动处理 SD 卡目录结构与依赖检查。安装后设备端会显示DnD Dice [Ka3u6y6a]该名称来自application.fam的name字段并配有icon.png作为列表图标。玩法与按键操作在设备上启动应用后操作逻辑如下对应 dice_app.c 中的按键处理分支按键场景行为◀ / ▶骰子选择界面在 Coin、d4、d6、d8、d10、d12、d20、d100 之间切换伴随骰子滑入的切换动画▲ / ▼骰子选择界面增减投掷数量110Coin 与 d100 锁定为 1OK任意非动画状态投掷骰子进入滚动动画并展示结果BACK结果界面返回骰子选择界面BACK骰子选择界面退出应用结果界面有三个信息层次中央放大显示所有骰子点数总和roll_result下方以4, 1, 3形式列出逐枚明细rolled_dices[]底部则提示当前骰子类型与投掷数量。对于 Coin 和 d100 这类单骰类型结果界面只显示总和而省略明细行由isResultVisible()与isOneDice()共同控制。源码解析状态机驱动的动画应用抛开掷骰子的表象这个应用是一份相当完整的Flipper Zero GUI 编程范例其核心可以拆解为状态机、事件循环、掷骰算法和渲染管线四部分。1. 六态状态机应用在 constants.h 中定义了 6 个应用状态typedef enum { SelectState, // 骰子选择主界面 SwipeLeftState, // 左滑切换动画选中下一个骰子 SwipeRightState, // 右滑切换动画选中上一个骰子 AnimState, // 投掷滚动动画 AnimResultState, // 结果数字下落动画 ResultState // 结果展示 } AppState;整个应用的交互可以看作这个状态机的转移图SelectState在左右按键下进入滑动动画状态滑动到位坐标命中DICE_X回到SelectStateOK 按键触发roll()进入AnimState动画播完进入AnimResultState数字落到位置后再转入ResultStateBACK 则从结果态回到选择态或直接退出。constants.h中isDiceNameVisible()、isDiceButtonsVisible()、isDiceSettingsDisabled()、isAnimState()等一系列谓词函数都是围绕状态机来裁剪 UI 元素的显隐例如动画过程中隐藏 ROLL 按钮、结果展示阶段隐藏左右切换箭头。2. 事件驱动的消息循环入口函数dice_dnd_app()dice_app.c遵循 Flipper SDK 的标准应用骨架分配容量为 8 的FuriMessageQueue事件队列消息类型为AppEvent区分EventTypeTick定时器事件与EventTypeKey按键事件注册ViewPort的绘制回调draw_callback与输入回调input_callback二者都通过ValueMutex互斥锁保护共享的State避免渲染线程与输入线程竞争创建一个周期为furi_kernel_get_tick_frequency() * 0.2约 200ms的FuriTimer定时器回调不断向队列投递EventTypeTick——动画的逐帧推进正是依赖这个 5Hz 的节拍主循环furi_message_queue_get()以 100ms 超时轮询队列分别处理 Tick驱动update()与按键事件退出时依次释放定时器、消息队列、互斥锁并移除 ViewPort资源清理完整。3. 掷骰算法roll()函数dice_app.c的随机逻辑只有一行核心代码state-rolled_dices[i] (rand() % dice_types[state-dice_index].type) 1;即对每个骰子用rand() % 面数 1生成 1N 的均匀分布点数累加到roll_result得到总和超出投掷数量的槽位置 0。随后根据当前骰子类型切换硬币动画帧coin_set_end并把状态推进到AnimState。对于硬币dice_index 0投掷结果只有 1 或 2 两种因此coin_set_start()/coin_set_end()会根据结果把动画首尾帧替换为正面heads或反面tails的帧序列。4. 分层渲染管线draw_callback采用先 UI、再内容的分层绘制策略dice_app.cdraw_ui()负责绘制底部按钮ROLL / EXIT / BACK、左右切换箭头、数量调节图标与数字、骰子类型名称在结果态调用draw_results()用canvas_draw_str_aligned居中绘制总和与明细并把结果框I_ui_result_border沿result_frame_pos_y[] {-30, -20, -10, 0}逐帧下落在其他状态调用draw_dice()从dice_frames[]中按(dice_index-1) * MAX_DICE_FRAMES anim_frame取当前动画帧绘制并利用x 128 || x -35的越界裁剪跳过屏幕外的骰子。动画帧的资源组织也值得注意dice_frames[]按每种骰子 4 帧的顺序平铺存储d4 4 帧 → d6 4 帧 → … → d100 4 帧索引计算即上述公式硬币则特殊处理为 9 帧MAX_COIN_FRAMES并在AnimState的第 3 帧切换首帧以表现翻转。构建元数据解析application.fam 里的门道FAP 应用的构建信息全部声明在 application.fam 中理解这些字段对改造成自有应用很有价值字段值含义appidDND_Dice_app全局唯一应用 ID参与 fbt 目标名fap_dice_dnd_app的生成nameDnD Dice [Ka3u6y6a]设备端显示的应用名apptypeFlipperAppType.EXTERNAL外置应用以独立 FAP 包分发区别于内置固件应用entry_pointdice_dnd_app入口函数符号即dice_app.c中的int32_t dice_dnd_app(void* p)cdefines[APP_DICE]编译期宏定义可在源码中条件编译requires[gui]声明依赖 GUI 子系统fbt 据此做依赖校验stack_size1 * 1024应用线程栈大小1KBorder90应用在菜单中的排序权重fap_iconicon.png应用列表图标fap_categoryGames安装分类目录对应 SD 卡apps/Gamesfap_icon_assetsassets打包进 FAP 的图标资源目录值得注意stack_size仅为 1KB这对于一个纯渲染、无持久化状态的小型 GUI 应用已经足够——它与furi_kernel_get_tick_frequency() * 0.2的定时器共同体现了 Flipper 生态资源极度精简的编程取向。自定义与扩展建议由于全部美术源文件.pixil都保留在sources/目录且常量集中在constants.h你可以非常低成本地个性化这个应用增加骰子面数在dice_types[]中追加条目如 d30同步扩充dice_frames[]的帧序列并修改DICE_TYPES修改动画节奏调整MAX_COIN_FRAMES/MAX_DICE_FRAMES、SWIPE_DIST当前 11px与定时器周期0.2秒替换美术资源用 Pixilart 打开sources/*.pixil重新绘制导出 PNG 后替换assets/中的同名文件并重新执行./fbt fap_dice_dnd_app。小结DnD Dice 虽小却完整覆盖了 Flipper Zero 外置应用开发的全部链路application.fam声明元数据 → fbt 交叉编译 → 符号链接接入applications_user→.fap产物 → 拷贝至 SD 卡apps/Games启动。而它内部六状态状态机、200ms 定时器驱动的逐帧动画、ViewPortValueMutex的并发渲染模型更是学习 Flipper GUI 编程不可多得的精简范例。无论你是想直接编译一个骰子应用装进设备还是以此为模板开发自己的 FAP本文结合 dice_app.c、constants.h 与 application.fam 的逐层拆解都可以作为你的起点。【免费下载链接】FlipperPlayground (and dump) of stuff I make or modify for the Flipper Zero项目地址: https://gitcode.com/GitHub_Trending/fl/Flipper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考