
给 Rust 游戏加暂停菜单egui 接入 Bevy 与 Miniquad 的完整指南【免费下载链接】eguiegui: an easy-to-use immediate mode GUI in Rust that runs on both web and native项目地址: https://gitcode.com/GitHub_Trending/eg/eguiegui 是一个纯 Rust 的即时模式 GUI 库把它的 egui 集成做进游戏引擎核心工作量只有两件事每帧把输入喂给它、把它输出的三角形画出来。这篇 Rust 游戏 GUI 教程以给游戏加一个暂停菜单为任务推进讲清 egui 怎么接进 Bevy 和 Miniquad、为什么能跑通、每帧成本有多高、常见坑怎么修。读完你能拿到一个可运行的接入路径和一份对照排查的坑位清单。3 步跑通第一个暂停菜单 先不管引擎细节目标是游戏按 Esc 后弹出一个带继续游戏按钮的窗口。建一个独立的 UI 状态。egui 是即时模式——每帧把界面重画一遍好处是界面永远反映最新状态所以你不需要创建窗口、持有句柄、销毁窗口这一套只需要在每帧的回调里声明它。把输入喂给 egui让它算出该画什么、该响应什么点击。把 egui 输出的网格交给引擎的渲染器画上去。以 Bevy 为例前两步被bevy_egui插件包掉了你只写第 2 步里的 UI 代码[dependencies] bevy 0.11 bevy_egui 0.22fn pause_menu(mut egui_ctx: ResMutEguiContext) { egui::Window::new(暂停).show(egui_ctx.ctx_mut(), |ui| { if ui.button(继续游戏).clicked() { // 把游戏状态切回 Running } }); }窗口、拖动、失焦、点击判定都是窗口本身处理的你只关心按钮是否被点。这一步跑通后菜单已经能盖在 3D 场景上了——因为 egui 本身不管窗口也不管显卡这两件事都归引擎管。即时模式为什么它和游戏循环合拍保留模式 GUI传统方式先构建一棵持久的控件树靠回调通知状态变化即时模式每帧从零声明一遍界面if ui.button(继续).clicked()这种写法里是否被点是当场算出来的没有任何回调要接。这对游戏是天然契合的你的游戏循环本来就是每帧跑一次UI 逻辑和游戏逻辑在同一个节拍上不存在游戏改了血量、血条还显示旧值的同步问题也不用维护控件的生命周期。代价是每帧都做一次完整布局所以下一节的性能话题绕不开它。官方 README 里 crates/egui/README.md 的 Why immediate mode 一节把这个取舍讲得很透值得一读。选型问答Bevy 和 Miniquad 各走哪条桥egui 的官方集成只负责纯 Rust 环境crates/eframe、crates/egui-winit、crates/egui-wgpu接进第三方引擎靠的是社区桥接库官方 README 在 Integrations 一节也明确把 Bevy 和 Miniquad 归为第三方集成。两条路怎么选问自己三个问题谁管窗口和输入如果你的引擎自己管Bevy 的Input插件、miniquad 的事件回调egui 只需要被转发事件不需要再建一套窗口系统。两者都符合此项打平。你的渲染器是什么Bevy 默认 wgpuMiniquad 给你裸 OpenGL。egui 官方提供 crates/egui_glow 和 crates/egui-wgpu 两套绘制器桥接库各自封装其一——选引擎渲染栈匹配的那条别自己混搭。你想自己控制每帧时序吗Miniquad 风格更底层输入回调、run、paint三步都摆在你手里流程示意fn render() { forward_input_to_egui(); // 1. 转发 miniquad 输入 let out egui_ctx.run(raw, |ctx| pause_menu_ui(ctx)); // 2. 跑 UI egui_miniquad::paint(out); // 3. 提交三角形 }Bevy 路线把这三步藏进插件你只写 UI 代码适合 UI 是附属品的项目Miniquad 路线每步可见适合 UI 与游戏逻辑深度耦合比如自定义光标、逐帧拦截按键的项目。不确定就先走 Bevy跑通后再看要不要降层。每帧成本性能注意什么即时模式的账单是每帧一次完整布局但官方 README 给出的经验值是有参考的典型应用 egui 每帧占 1~2 ms并且只在有交互或动画时重绘界面静止时基本不花 CPU。真正会咬人的是内容规模超大滚动区。滚动列表里塞上万行每帧都要给它们算布局。做法是只布局可见范围附近的内容或把长历史裁掉。纹理碎片。文字和图片走纹理图集crates/epaint/src/texture_atlas.rs频繁上传零散小图会拖慢绘制尽量让图标、贴图复用同一批纹理。字体别在运行时现装。中文等字体在启动阶段一次性装好参考 examples/custom_font/src/main.rs 的set_fonts写法避免游戏中途切场景时卡顿。3D 画面叠 UI 的顺序。游戏先画场景、egui 后画网格顺序反了菜单会被场景盖住反向需求在 UI 里嵌 3D可以看 examples/custom_3d_glow/src/main.rs它演示了用PaintCallback在 egui 区域内画 3D。三个高频坑现象、原因、解法 ⚠️按现象→原因→解法排查输入被抢走或双发现象菜单开着时按方向键角色也在动或按键进了 UI 却进不了游戏。 原因引擎和 egui 各自消费了一遍原始事件没人先问对方要不要。 解法固定一个优先级——本帧事件先交给 eguictx.input里能看到它实际消费了哪些剩下的再发给游戏逻辑暂停时干脆不往游戏层转发。事件结构定义在 crates/egui/src/data/input/对照它写过滤逻辑。高分屏上文字发虚现象同一套 UI普通显示器清晰Retina 屏模糊。 原因egui 用逻辑点计算布局物理像素密度没传对网格被拉伸了。 解法把真实像素密度喂进去入口是 crates/egui/src/context.rs 里的Context::set_pixels_per_point它最终换算为 zoom factor确保引擎报告的缩放系数和视口尺寸一致。中文显示成方块现象英文正常中文全是豆腐块。 原因默认字体crates/epaint_default_fonts/fonts只覆盖拉丁字符和 emoji不含 CJK。 解法自备.ttf/.otf中文字体用Context::set_fonts装进去并调到Proportional字体族首位完整写法在 examples/custom_font。还有一个小坑值得记一下egui 默认拿窗口标题当 ID。两个动态标题的窗口重名时位置、展开状态会互相串。给动态窗口显式指定独立 ID 即可。下一步跑一遍再往下学现在就执行cargo run --release -p egui_demo_app这个演示应用里每个窗口的源码都能在 crates/egui_demo_lib/src/demo 找到对应文件看到什么就去读对应文件比通读文档快得多。想深入原理读 crates/egui/README.md 的 Why immediate mode 与 Integrations 两节想再动手examples/ 目录里hello_world、custom_keypad、multiple_viewports是从简单到进阶的一条完整路径。【免费下载链接】eguiegui: an easy-to-use immediate mode GUI in Rust that runs on both web and native项目地址: https://gitcode.com/GitHub_Trending/eg/egui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考