当前位置: 首页 > news >正文

用JSON定义游戏界面:FlatUI序列化功能完整上手教程

用JSON定义游戏界面:FlatUI序列化功能完整上手教程

【免费下载链接】flatuiEfficient Immediate Mode UI for Games项目地址: https://gitcode.com/gh_mirrors/flatu/flatui

FlatUI 是 Google 开源的高效即时模式(Immediate Mode)游戏 UI 库,主打轻量、快速、零状态管理的界面渲染方案。而它的序列化功能(Serialization)更是让开发者可以用 JSON 直接定义游戏界面,把界面布局与 C++ 代码彻底分离,堪称游戏开发者的"界面配置神器"。这篇教程将带你从零上手 FlatUI 序列化,学会用 JSON 快速搭建游戏菜单、配置控件、绑定事件,并扩展自定义控件,全程无需反复编译即可调整界面。

什么是 FlatUI 序列化功能

传统即时模式 UI 中,界面代码和逻辑代码混在一起,改一个按钮位置都要重新编译。FlatUI 序列化功能改变了这一切:它借助FlatBuffers序列化框架,允许你用一份 JSON 文件描述整个游戏界面(控件、布局、尺寸、事件),运行时再解析加载、渲染显示。

它的核心价值在于:

  • 界面与代码解耦:改 UI 文案、颜色、布局只改 JSON,不动 C++ 代码;
  • 天然支持多人协作:策划、美术可以直接编辑 JSON,程序员专注逻辑;
  • 低开销高性能:FlatBuffers 序列化后的二进制数据无需解析即可直接读取,契合游戏对性能的苛刻要求;
  • 支持动态数据与自定义控件:可注册运行时可变的变量,也可扩展专属控件。

FlatUI 序列化核心原理:JSON 到界面的一次旅行

整个流程可以概括为三步:写 JSON → 用 Schema 解析成二进制 → 运行时反序列化渲染

负责这一切的骨架是 flatui.fbs(FlatBuffers Schema 文件),它定义了界面的"语法规则"。其中FlatUIElement是核心表结构,包含了idtypelayouttextsizemarginoffsethorizontalvertical等字段;而Type枚举则列出了 FlatUI 内置支持的控件类型:

控件类型用途常用字段
Label文本标签text、ysize
TextButton文本按钮text、size、margin
Image图片显示texture、ysize
ImageButton图片按钮texture、size
Edit文本输入框ysize、size_2f
Slider滑动条texture、size_2f、bar_size
CheckBox复选框texture、text
ScrollBar滚动条texture、size、bar_size
Group容器分组layout、horizontal、vertical、offset
SetVirtualResolution设置虚拟分辨率virtual_resolution

关于 Schema 的完整字段定义,可以参考 flatui.fbs 中的注释说明。

快速上手:用 JSON 定义第一个游戏界面

我们直接看 FlatUI 自带的序列化示例 first_menu.json,它定义了一个居中的垂直布局菜单,包含标题、按钮和输入框:

{ elements: [ { type: "flatui_data.Type.SetVirtualResolution", id: "virtual resolution", virtual_resolution: 1000 }, { type: "flatui_data.Type.Group", id: "first menu group", layout: VerticalLeft, horizontal: Center, vertical: Center, elements: [ { type: "flatui_data.Type.Label", id: "first menu label", text: "Welcome to the first menu! :D", ysize: 40 }, { type: "flatui_data.Type.Edit", id: "first menu edit text", ysize: 40, size_2f: { x: 0, y: 0 } } ] } ] }

这段 JSON 传达了几个关键信息:

  • type指明控件类型,如LabelGroupEdit
  • id是控件的唯一标识,后续绑定事件、注册动态数据全靠它;
  • layout / horizontal / vertical控制布局方向与对齐方式,Center表示居中;
  • elements支持无限嵌套,实现树形界面结构,与 C++ 中的StartGroup / EndGroup逻辑一一对应。

在 C++ 中加载并渲染 JSON 界面

JSON 写好了,接下来用 C++ 把它加载进游戏。完整的可运行示例在 flatuiserializationsample.cpp,核心流程如下:

  1. 加载文件:读取 JSON、自定义控件 Schema 和主 Schema;
  2. 解析生成二进制:用flatbuffers::Parser结合 Schema 把 JSON 编译成 FlatBuffer 二进制数据;
  3. 创建界面:调用CreateFlatUIFromData()传入二进制数据;
  4. 渲染循环:把创建函数传入flatui::Run()每帧执行。
flatbuffers::Parser parser; parser.Parse(schema.c_str(), include_directories); // 解析 Schema parser.Parse(first_menu_json.c_str()); // 解析 JSON auto* data = parser.builder_.GetBufferPointer(); // 拿到二进制数据 Run(assetman, fontman, input, [&]() { flatui::CreateFlatUIFromData(data, &assetman, event_handler); });

CreateFlatUIFromData是序列化 API 的核心入口,其完整签名定义在 flatui_serialization.h,接受三个参数:FlatBuffer 数据、用于纹理渲染的AssetManager(可选)、以及事件处理器FlatUIHandler(可选)。

事件绑定与动态数据:让界面"活"起来

静态界面没有意义,FlatUI 序列化通过事件绑定动态数据让界面与游戏逻辑联动。

事件处理

事件处理器是一个std::function,接收事件、控件 ID 和动态数据三个参数。示例代码中通过 lambda 包装后传入CreateFlatUIFromData

auto event_handler = & { EventHandler(e, id, dynamic_data, menu_id); };

EventHandler内部按控件id分发逻辑,例如监听"change menu button"的kEventWentUp(松开)事件切换菜单,实现两个菜单之间的来回切换。

动态数据注册

输入框里的文字是运行时可变的,需要用RegisterStringData把它和 JSON 中的控件 ID 绑定:

std::string edit_text_box("Edit me!"); flatui::RegisterStringData("first menu edit text", &edit_text_box);

FlatUI 提供了一套完整的注册函数:RegisterIntDataRegisterFloatDataRegisterBoolDataRegisterVec2DataRegisterVec4Data等,对应DynamicData联合体中的各种数据类型,全部声明在 flatui_serialization.h。注意:注册的指针必须比界面的生命周期更长,否则会引发悬垂指针。

自定义控件:扩展 FlatUI 的专属武器

内置控件不够用时,FlatUI 序列化还支持自定义控件。步骤很简单:

  1. 定义枚举:在自定义 Schema(如 custom_widgets.fbs)中声明控件类型;
  2. 实现渲染函数:编写一个符合CustomWidget签名的函数,用element中的数据调用 FlatUI 绘制 API;
  3. 注册控件:调用RegisterCustomWidget(type, widget)把类型与函数绑定。
void ChangeMenuButton(const flatui_data::FlatUIElement* element, fplbase::AssetManager* assetman, flatui::FlatUIHandler event_handler, flatui::DynamicData* dynamic_data) { flatui::StartGroup(flatui::kLayoutVerticalLeft); flatui::ColorBackground(fplbase::LoadVec4(...)); flatui::Event e = flatui::TextButton(element->text()->c_str(), element->size()); flatui::EndGroup(); event_handler(e, element->id()->str(), dynamic_data); } flatui::RegisterCustomWidget(custom_widgets::Type_ChangeMenuButton, ChangeMenuButton);

自定义控件还能通过attributes字段接收 JSON 中传入的任意参数(颜色、尺寸、对齐方式等),灵活性极高,示例中的"Change Menu"按钮就是典型应用。

调试技巧与常见问题

JSON 写错了怎么办?FlatUI 内置了错误输出机制,默认最多打印 10 条错误,可通过SetErrorOutputCount()调整:

flatui::SetErrorOutputCount(flatui::kNoErrorOutputLimit); // 输出所有错误

常见坑位提醒:

  • JSON 格式不合法:示例代码在Parse失败时会直接报错退出,务必检查括号与逗号;
  • texture 找不到:渲染图片控件时,确保AssetManager中已加载对应纹理资源;
  • id 冲突或遗漏:事件绑定和动态数据都依赖id,命名要全局唯一;
  • Schema 版本不一致:JSON 字段必须与flatui.fbs版本匹配,否则解析报错。

总结:什么时候该用 FlatUI 序列化

如果你正在开发游戏,且满足以下任一场景,强烈建议尝试 FlatUI 序列化功能:

  • 需要频繁调整界面布局,希望免编译热改 UI;
  • 团队中有策划或美术参与界面配置
  • 需要动态生成菜单、弹窗等结构化界面;
  • 追求极低开销的序列化方案(FlatBuffers 天然零拷贝)。

上手方式也很简单:将仓库https://gitcode.com/gh_mirrors/flatu/flatui克隆到本地,直接运行sample/serialization目录下的示例工程,对照 first_menu.json、second_menu.json 和 flatuiserializationsample.cpp 边改边看,很快就能掌握用 JSON 定义游戏界面的全部技巧!

【免费下载链接】flatuiEfficient Immediate Mode UI for Games项目地址: https://gitcode.com/gh_mirrors/flatu/flatui

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.cnnetsun.cn/news/4085210.html

相关文章:

  • 开发效率提升300%:这套SpringBoot3+Vue3脚手架让你的项目快速启动
  • BilibiliDown使用指南:收藏夹300条内容一键落地的离线视频备份方案
  • Python进阶 - sys模块 退出程序与异常信息获取
  • 用 relly 学 Rust 系统编程:零拷贝与安全内存操作实战
  • lainTSX 是什么:在浏览器中游玩《Serial Experiments Lain》PSX 游戏的完整指南
  • 认识 LightningJS:第三方JavaScript嵌入方案如何同时做到安全、快速与异步?
  • stdarch测试体系全览:C/Rust随机对拍、反汇编断言与20+架构的CI矩阵
  • 【单片机毕业设计】基于 STM32 或 51 单片机的多传感融合智能学习照明设备设计 基于 STM32 或 51 单片机的带时钟定时功能智能护眼装置设计与实现(021303)
  • Milvus 迁移到 RAG:先守住索引和评测口径
  • 告别录屏几小时,m3u8-downloader 让 M3U8 视频下载一条命令搞定
  • DistroAV(OBS-NDI)插件“Runtime缺失“全场景自救指南:从零上手到进阶调优的完整路线图
  • ManyDepth位姿估计网络解析:PoseCNN如何为多帧深度估计提供关键几何信息
  • 打造 7×24 家庭无线音乐中心:Shairport4w 开机自启与托盘运行实战
  • Blender里一键导出GIF动画,再也不为这事发愁
  • 【Bug已解决】Mustache list sections silently drop falsy items (`0`, `False`, `““`)
  • 有手就行!零基础用AI做数据分析,普通打工人也能玩出高级感
  • osu-droid难度算法实现剖析:Aim、Speed与Reading技能模型深度解析
  • 世毫九信息几何物理学框架下黎曼ζ函数非平凡零点的拓扑不动点本质
  • assert_instr测试机制深度解析:stdarch如何确保内建函数与机器指令一一对应
  • SideWaffle vs 其他VS模板扩展:为什么它是Web开发者的终极选择?
  • DDrawCompat 上手全攻略:让老 DirectX 游戏在现代 Windows 上重获新生
  • GitHub 成就解锁新手指南:零代码审查也能拿到的 Yolo 徽章
  • RTOS延时机制解析:从osDelay到阻塞延时的本质区别与应用
  • lainTSX 收集要素攻略:集齐 Polytan 熊全部 6 个部件的完整路线
  • 告别手忙脚乱:FF14钓鱼计时器“渔人的直感“咬钩识别与幻海流预警实战手册
  • 3步上手免登录微博图片批量下载:weiboPicDownloader从入门到进阶完整指南
  • OBS的NDI插件一装就报Runtime错误?DistroAV安装与排障一篇讲透
  • 炉石传说插件 HsMod 全攻略:8 大实用增强功能与最快上手方法
  • 单片机毕设选题推荐:基于 STM32/51 单片机的三轴姿态感知人体安全监测预警系统设计 基于 STM32/51 单片机的老年人远程跌倒短信报警硬件系统设计(021203)
  • 内联汇编与Naked函数:B语言编译器bext-lang/b的底层控制进阶教程