Bevy 0.19 UI Feature 拆分与渲染陷阱

问题现象

在 Bevy 0.19 中,如果 Cargo.tomldev-dependencies 里只启用 "bevy_ui" 而遗漏 "bevy_ui_render",UI 布局系统会正常工作(Node 实体存在、布局计算正确),但屏幕上完全不渲染任何 UI 元素——包括文本、背景色、边框。

更隐蔽的是,如果此时还使用 FontSource::SystemUi 而未启用 system_font_discovery feature,文本测量会返回 NoSuchFont 错误,导致文本尺寸为 0,进一步掩盖问题。

根因

Bevy 0.19 将 UI 系统拆分为更细粒度的 feature:

Feature职责遗漏后果
bevy_ui布局系统(Node、Flex、Grid、事件)无法使用 UI 组件
bevy_ui_render渲染提取管线(将 UI 节点绘制到屏幕)UI 有布局但不显示
system_font_discovery系统字体数据库(Parley backend)FontSource::SystemUi 无法解析

关键发现路径

  1. Sprite 显示,UI 不显示 → 2D 渲染管线正常,问题在 UI 提取
  2. 红色矩形显示,文本不显示bevy_ui_render 已加载,但文本测量失败
  3. 改用 TextFont::from_font_size()(内置字体)后文本显示 → 确认 SystemUi 需要 system_font_discovery

修复方案

Cargo.toml

[dev-dependencies]
bevy = { version = "0.19.0-rc.1", default-features = false, features = [
    # ... 其他 features ...
    "bevy_ui",
    "bevy_ui_render",  # ← 必须显式启用
    # ...
] }

代码层

// 使用内置默认字体(不需要 system_font_discovery)
let text_font = TextFont::from_font_size(40.);
 
// 错误:SystemUi 需要 system_font_discovery feature
// let text_font = TextFont {
//     font: FontSource::SystemUi,
//     ..default()
// };

诊断流程

遇到 UI 不显示时,按此顺序排查:

  1. 确认 bevy_ui_render feature 已启用

    • 检查 Cargo.toml
    • 无此 feature = 什么都不显示
  2. 确认 bevy_textdefault_font feature 已启用

    • 或使用 asset_server.load("fonts/...") 加载自定义字体
  3. 如果使用系统字体,确认 system_font_discovery 已启用

    • 否则 FontSource::SystemUi / FontSource::SansSerif 等会静默失败
  4. 检查相机

    • Bevy 0.19 官方 example 使用 commands.spawn(Camera2d);
    • 不需要 IsDefaultUiCamera(它会自动 fallback 到 primary window 相机)
  5. 检查布局

    • Display::Grid 需要显式定义 grid_template_columns/rows
    • PositionType::Absolute 的容器需要显式 width/height

版本对比

版本UI 渲染 feature内置字体 feature系统字体
0.18bevy_ui 隐式包含渲染default_font(默认启用)未分离
0.19bevy_ui + bevy_ui_render 分离default_font(仍默认)system_font_discovery

实战教训

bevy_http_client example 修复案例

  • 原始代码Display::Grid + Node::default() 嵌套 + bevy_ui only
  • 现象:画面空白,没有任何 UI
  • 修复步骤
    1. Cargo.toml 添加 "bevy_ui_render"
    2. Display::GridDisplay::Flex
    3. 移除 Node::default() 嵌套(Text 直接作为 flex 子项)
    4. 改用 TextFont::from_font_size() 使用内置字体
    5. 移除多余的 IsDefaultUiCamera

通用检查清单

  • Cargo.toml"bevy_ui_render" 已显式列出
  • 如果使用自定义 feature set,"bevy_text""default_font" 已启用
  • 如果使用系统字体,"system_font_discovery" 已启用
  • 相机使用 Camera2d(无需 IsDefaultUiCamera
  • 布局容器有显式尺寸(width/heightaspect_ratio

相关页面