Hacker News 中文摘要

RSS订阅

Bevy 0.20 发布 -- Bevy 0.20

在 227 名贡献者、817 个拉取请求、社区评审者和慷慨捐赠者的支持下,Bevy 引擎(Bevy)0.20 已在 crates.io 发布。Bevy 是用 Rust 编写的简洁数据驱动游戏引擎,永久免费开源,可按快速入门指南试用,社区插件、游戏和学习资源见 Bevy Assets,升级可参考 0.19 到 0.20 迁移指南。距上个版本数月以来新增大量功能、修复与优化,重点包括支持 macOS 上 Metal 的 Solari 渲染器(Solari)与 DLSS、BSN 场景系统(BSN)语法更易读写,以及场景实体触发的 Ready 事件(Ready)。

正文

感谢 227 位贡献者、817 个拉取请求、社区评审者,以及我们慷慨的捐赠者,我们很高兴在 crates.io 上发布 Bevy 0.20!

如果你还不了解 Bevy,它是一个用 Rust 构建的、令人耳目一新地简单的数据驱动游戏引擎。你可以查看我们的快速入门指南立即体验。它永远免费且开源!你可以在 GitHub 上获取完整的源代码。查看 Bevy Assets 可以获取社区开发的插件、游戏和学习资源集合。

要将现有的 Bevy App 或 Plugin 更新到 Bevy 0.20,请查看我们的0.19 到 0.20 迁移指南。

自几个月前的上次发布以来,我们添加了大量新功能、错误修复和体验优化,以下是一些亮点:

  • Solari 和 DLSS:Solari 是 Bevy 的实时路径追踪渲染器,现在更快、更准确,支持更多 Bevy 渲染功能,并通过 Metal 在 macOS 上运行!
  • BSN 语法改进:BSN 是 Bevy 的新场景系统,此次做了一些语法调整,使其更易于阅读和组合。
  • Ready 事件:BSN 场景实体现在会在其所有子实体生成完毕后触发一个可观察的 Ready 事件。
  • 更多 UI 部件:Bevy Feathers 是 Bevy 面向编辑器的、有主见的 UI 工具包,现在新增了颜色输入、可滚动列表视图、下拉选择和懒加载菜单部件。数字输入部件现在支持滑动/拖动,我们还添加了无头(headless)标签部件。
  • WESL 着色器:Bevy 正式采用 WESL 着色器语言(WGSL 的标准化扩展)。WESL 已经比 Bevy 旧的自定义 WGSL 方言更好,我们正与 WESL 团队合作规划 Bevy 着色器开发的未来。
  • 精灵材质与扩展的 2D 材质:现在可以为精灵创建自定义着色器材质,2D 网格材质也可以像 3D 中那样被扩展。
  • 平移轨道相机:Bevy 现在有了“平移轨道相机”,可以以类似 CAD 的方式导航场景。

Solari 与 DLSS

图 1:zero day

Solari 是 Bevy 的实时路径追踪渲染器,该插件几乎各个方面都有重大改进!

想了解技术细节,可以阅读 JMS55 的博客,或者继续阅读下面的高层概述。

改进的图像质量

得益于 ReSTIR 实现的改进,渲染现在基本无偏,光照更加准确。此外,移动物体不再有滞后的阴影,反射在运动中也不再那么闪烁,尤其是非金属材料。

改进的性能

DLSS-RR 在最近的更新中变得非常好,而对于许多场景,ReSTIR 会消耗可观的性能,却不会显著改善图像质量。因此我们决定将 ReSTIR 设为可选,并默认关闭。如果你在 Bevy 0.19 中使用了 Solari,请检查关闭 ReSTIR 是否影响你的场景,如有需要可重新启用 SolariLighting::restir。关闭 ReSTIR 后,在多光源场景中阴影质量会下降,运动时可能缺失阴影;我们正在探索不使用 ReSTIR 的更廉价光照采样改进方法。此外,Solari 的场景管理代码现在得以保留(类似于之前 Bevy 版本中保留的渲染世界优化),并且整体更加优化,显著降低了 CPU 开销。你也可以查看 SolariLighting 中的新字段,现在有很多旋钮(世界缓存大小、每像素光照采样数、时间累积和路径追踪反弹次数)可以调整,以针对特定场景、项目和硬件优化性能或质量。

改进的兼容性

Solari 现在支持相机上 Atmosphere 和 EnvironmentMapLights 的光照,此外还继续支持 DirectionalLight 和自发光网格。我们希望在不久的将来添加对剩余的 PointLight、SpotLight 和 RectLight 类型的支持。Solari 现在也能在 macOS 上运行,但请注意 bevy_solari 目前尚未为 macOS 提供内置降噪器;未来 MetalFX Ray Reconstruction 可能是一种解决方案(欢迎贡献!)。

DLSS 更新

我们的 dlss_wgpu crate 已更新以支持最新版 DLSS,带来 DLSS-RR 4.5,显著提高了 Solari 的降噪质量。如果你在 Bevy 0.19 中使用了 DLSS,请确保下载并设置最新版 DLSS SDK,否则会遇到编译器错误。

BSN 语法改进

BSN 刚出现时有一些特性在实践中造成了摩擦。这个周期我们对 BSN 的语法做了一些改动,以提升其易用性和清晰度。此后语法应该基本固定了。

显式场景语法

所有场景引用现在都需要 @ 前缀:以前可以写 bsn! { scene_variable scene_function() @SceneComponent {scene_expression} },现在必须写成 @scene_variable、@scene_function()、@SceneComponent 和 @{scene_expression}。除了更容易发现场景包含(并统一各种情况的语法)之外,这也让我们能极大地简化组件值的写法!

不再需要 template_value 包装!

现在你可以移除组件值中所有烦人的 template_value 包装:以前是 template_value(component_variable) 和 template_value(component_function()),现在直接写 component_variable 和 component_function() 即可。

枚举“直接可用”

枚举不再需要 VariantDefaults 或 FromTemplate,只要它们实现了 Default 和 Clone。以前需要 #[derive(Component, Default, Clone, VariantDefaults)] 并在 bsn! 中写 Foo::B,现在派生时去掉 VariantDefaults,直接写 bsn! { Foo::B }。如果你之前用的枚举不支持 VariantDefaults,现在也可以去掉 template_value 包装。但移除 VariantDefaults 意味着枚举现在必须指定每个字段:以前可以写 Foo::A { x: 1 }(y 字段用默认值初始化),现在必须手动写成 Foo::A { x: 1, y: 0 }。我们认为这个权衡是值得的,因为它提高了 BSN 与任意 Rust 枚举的兼容性;而且 Rust 本来也不支持“枚举变体默认值”!

链式方法支持

“构建器模式”(以及一般的链式方法)以前需要 template_value 包装,现在可以去掉了:以前是 template_value(Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y)),现在直接写 Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y)。类似 template_value(node.clone()) 的写法现在也只需写 node.clone()。通常,你现在应该能移除 BSN 声明中所有的 template_value 实例!

改进的列表语法

BSN 以前用逗号分隔实体,也可以用可选的 () 包裹实体以明确边界,但这导致了大量语法噪音、行噪音和过度缩进。许多开发者改用另一种难以直观区分实体的写法。现在 BSN 使用 -- 分隔列表中的实体,例如:bsn! { Node Children [ #OkButton @button("Ok") -- #CancelButton @button("Cancel") ] }。这兼顾了各种优点:实体在视觉上清晰可分,且没有过度缩进、行噪音或语法噪音(在“标记格式”领域与其他竞争对手相比的数据非常有竞争力!)。在此上下文中,() 和 , 已被弃用。同时,不鼓励/警告在 bsn_list!(和 bsn!)中使用 [] 和 (),因为这会导致 rustfmt 自动格式化不佳;请改用 bsn_list! {},它是唯一不会被 rustfmt 改动的语法。别担心,我们计划构建一个 BSN 自动格式化工具!

Ready 事件

我们在上个版本中落地了 BSN,即 Bevy 的下一代场景系统。但它缺少一个关键部分:当场景完全“就绪”并生成后(例如所有依赖已加载、完整层级存在且所有初始组件已插入场景),能够轻松运行逻辑的能力。这对于构建内聚、独立、可组合的场景至关重要,也是在其他场景表示(如 glTF)之上正确叠加 Bevy 逻辑所必需的。我们之前最接近的是针对某个组件的 Add 事件,它是“自顶向下”运行的(意味着子实体尚不可用)。我们需要一个“自底向上”的等价物,以支持依赖完整加载并生成后场景的逻辑。解决方案很直接:在场景中某个实体的完整生成逻辑(包括其子孙)运行之后,为该实体触发一个新的 Ready 事件。这样就可以写出如下逻辑:定义一个 Widget 场景组件,在其 scene() 函数中用 bsn! 声明一个 Node,通过 on(|ready: On<Ready>| { ... }) 监听 Ready 事件,此时包括 widget.bsn 内容在内的整个场景都已可用,然后生成它(如 world.spawn(bsn! { @Widget }))。

Feathers 是 Bevy 面向编辑器的、有主见的 UI 工具包,现在有更多部件供你使用:

颜色输入

图 2:颜色输入

Bevy 现在有了一个紧凑的颜色输入选择器,点击时显示颜色选择器弹出部件,包括色轮选择器、RGB 和 HSL 选择器,以及最近使用的颜色网格。

列表视图 / 滚动条

图 3:滚动条列表视图

一个可滚动、可选择的列表视图。

下拉选择

图 4:下拉菜单

点击时显示包含选项列表的下拉菜单的选择字段。

懒加载菜单

图 5:懒加载菜单

打开菜单时生成弹出菜单,关闭时销毁它。这与普通的 Menu 部件不同,后者只是隐藏菜单。

数字输入部件滑动 / 拖动

FeathersNumberInput 部件已扩展,支持普通文本输入和滑动/拖动。它有一个可配置的“硬限制”(任何输入方式下的最小/最大值)和“软限制”(拖动时的最小/最大值),此外还可控制浮点精度和步长。

bevy_ui_widgets 现在有 headless(自带视觉)标签行为:一个 TabList 容器和 Tab 头。选择由“外部”管理,列表上的 SelectedTab 保存选中的标签;交互发出 ValueChange<Option<Entity>> 作为请求,由应用或可选的 tablist_self_update 观察者应用。标签支持键盘快捷键,并集成 Bevy 的焦点、交互和无障碍系统。例如:bsn! { TabList SelectedTab(Some(first_tab)) on(tablist_self_update) Children [ Tab Children [ Text("General") ] -- Tab Children [ Text("Rendering") ] ] }。有关受控和自更新标签列表(两种方向)的示例,请参阅 headless_tabs 示例。

WESL 着色器

Bevy 的着色器现在用 WESL 编写,旧的“Custom Bevy Extended WGSL”语言支持已被移除。WESL 是一种扩展 WGSL 的语言标准,添加了模块、导入、条件编译等重要易用特性。你可以在浏览器中的 WESL Playground 实时查看效果(还能渲染漂亮的 shader toys!)。Bevy 以前用自己的自定义 WGSL 方言处理这些事情,但我们认为采用通用标准对更广泛的着色器生态系统(以及我们自己)更好,这样可以集中资源改进语言、模块生态和 IDE 工具。我们一直与 WESL 团队紧密合作,以适合 Bevy 的方式演进该标准。其中一个关键工具是语言服务器协议支持,即 wgsl-analyzer,安装到你的 IDE 后,可提供语法高亮、跳转到定义、内嵌提示、代码折叠、格式化等功能。

图 6:带有 WESL 语法高亮的 Bevy 雾效着色器

旧版 Bevy WGSL 方言中的自定义着色器需要翻译成 WESL,并将文件从 .wgsl 重命名为 .wesl。不含预处理器指令的纯 WGSL 文件仍可继续使用。

例如,旧版自定义 Bevy 扩展 WGSL 使用 #import bevy_pbr::forward_io::VertexOutput 和 #ifdef VERTEX_COLORS,绑定写作 @binding(#{MATERIAL_BIND_GROUP});而 WESL 改用 import bevy_pbr::render::forward_io::VertexOutput; 和 @if(VERTEX_COLORS),绑定改为 @binding(constants::MATERIAL_BIND_GROUP)。

网格着色器

网格着色器现已集成到 Bevy 的管线缓存中,可供高级用户使用,能用于渲染:使用 meshoptimizer 等工具生成的 meshlets、具有动态细节级别的程序化草地(如这里所示)、体素(如 nvidium)、粒子等等。网格着色器在高层面上用计算着色器取代了传统的顶点着色器,允许直接在 GPU 上生成几何体,并将生成的图元直接传给片段着色器,而无需使用多个管线或中间缓冲区。一个 MeshPipeline 包含一个可选的任务着色器(也称为放大着色器)、一个网格着色器和一个片段着色器。新的 MeshPipelineDescriptor 可用于定义 MeshPipeline,之后可将其用作 RenderPipeline,从而复用 Bevy 的底层渲染 API(如 RenderContext::begin_tracked_render_pass)来调用新的 draw_mesh_tasks API。用法示例:先用 begin_tracked_render_pass 开启渲染通道,设置 set_render_pipeline(mesh_pipeline) 和绑定组,然后调用 draw_mesh_tasks(1, 1, 1) 来调度任务着色器(若无任务着色器则调度网格着色器)。值得注意的是,网格着色器是一种具有平台特定性能考量的高级图形方法,目前只是该特性的初始基础支持;更高层的用户 API 以及与 StandardMaterial 的便捷集成留待未来工作。网格着色器不支持 Web 平台。详情请参阅新的 mesh_shader_intro 示例。

精灵材质

到目前为止,Bevy 的精灵渲染器一直缺少一个重要功能:无法用自定义着色器扩展它!在此版本中,现在可以通过实现 MaterialExtension2d trait、插入 SpriteMaterial 组件并将 SpriteMaterialPlugin 添加到应用来为精灵创建自定义材质。着色器可以使用 bevy_sprite_render::sprite_mesh::functions 导出的函数,包括:sample_final_color(uv, instance_index)(在给定 UV 采样精灵的最终颜色,含色调和 alpha 丢弃)、sample_sprite_texture(uv, instance_index)(采样不带色调和 alpha 丢弃的精灵纹理)和 get_final_color(sprite_color, instance_index)(对精灵颜色应用色调和 alpha 丢弃)。查看 sprite_material 示例即可看到实际效果!

2D 扩展材质

Bevy 现在为 3D 的 ExtendedMaterial 提供了 2D 版本,可通过实现 MaterialExtension2d trait 来扩展现有材质。例如定义一个带有 #[uniform(20)] value: Vec4 的 MyMaterial,实现 MaterialExtension2d 并指定 fragment_shader 为 my_material.wesl;然后可在 ExtendedMaterial2d 结构体中使用该材质:let handle = materials.add(ExtendedMaterial2d { base: ColorMaterial::from_color(Color::WHITE), extension: MyMaterial { value: Vec4::ZERO } });,再生成一个带有 Mesh2d 和 MeshMaterial2d(handle) 的实体。

精灵渲染后端统一

精灵渲染后端已被一个新后端取代,该后端复用了大量为 3D 构建的基础设施。这在许多情况下带来了性能提升,也使未来的维护和改进更容易。

平移轨道相机

我们已将 @aevyrie 开发的优秀 bevy_editor_cam 上游化,作为 bevy_camera_controller crate 中新的 PanOrbitCamera!

用法

添加 MeshPickingPlugin 和 DefaultPanOrbitCameraPlugins:app.add_plugins((MeshPickingPlugin, DefaultPanOrbitCameraPlugins))。然后在任意 3D 相机上添加 PanOrbitCamera 组件:commands.spawn((Camera3d::default(), PanOrbitCamera::default()))。完整功能见 camera/pan_orbit_camera_cad 示例。

使用 chain_weak 的弱系统排序

使用 .chain() 对大组系统排序很方便,但可能过于严格:如果系统集 X 链式排在 Y 之前,X 中的每个系统都必须完成,Y 中的任何系统才能开始,即使相关系统从未接触相同数据。这常常让工作线程在等待系统集末尾少数几个落后者时空闲,这种模式在渲染世界中频繁出现。新的 chain_weak()、before_weak() 和 after_weak() 函数提供了更宽松的替代方案。与常规对应函数一样,它们请求相继元素之间的排序,但只有在数据访问实际冲突的系统之间才保持该顺序;不冲突的系统则无序,可以任意顺序运行,包括并行。例如原先 ExtractCommands、PrepareMeshes 等系统集可用 .chain_weak() 替代 .chain()。当两个弱排序系统在数据访问上实际冲突时,它们之间仍保持正常顺序,先前的仍先运行;链中通过不冲突系统间接冲突的两个系统也保持顺序。但不冲突的系统可以自由重叠以提高并行度!有两种系统被视为始终冲突,因此其顺序始终保留:产生延迟效果(如 Commands)的较早系统(以便较晚系统观察到它们,并照常插入 ApplyDeferred 同步点),以及独占系统(无论如何不能重叠任何系统)。由于调度器只能看到它跟踪的访问,通过只读访问上的内部可变性、全局状态或其他未跟踪方法表达的依赖关系不会被尊重。只有在系统不依赖这种隐藏顺序时才使用 chain_weak,否则应坚持使用 chain。

上下文主题化

Feathers 现在支持“上下文主题化”,即主题变量可以根据父实体而改变。因此,对话框或子面板内的部件可以拥有与常规面板或窗口背景上的部件不同的颜色。该设计遵循 MUI、Radix 或 Chakra 等流行 Web 工具包的做法。新增组件 ThemeContext,可选择部件后代应使用的配色方案;目前可用的方案有 Base、Higher、Highest 和 Floating,对应 Bevy 场景编辑器的设计规划。主题上下文与一种名为 SemanticToken 的新型设计令牌配合使用。颜色的查找过程现在需要两步:先将 ThemeToken 转换为 SemanticToken,然后结合 SemanticToken 和 ThemeContext 查找颜色。除了允许上下文相关的颜色选择外,这也让设计新主题更容易:不必再乏味地为上百个不同主题令牌选择颜色,语义令牌集合要小得多,且令牌与颜色之间的关系更直观。

Val::Em 和 Val::Rem

Bevy UI 现在支持 em 和 rem 作为尺寸单位。em 是当前字体大小(由 EmSize 组件表示,当实体上有 TextFont 时从其派生;沿层级向下传播由你的应用负责),rem 是全局“根”字体大小(由现有的 RemSize 资源表示)。如果你可能想在编写 UI 后改变文本大小(例如作为无障碍功能,或只是为了在不同设备上改善 UI),这尤其有用。例如:bsn! { Node { width: em(10) } Text("Hello") TextFont { font_size: FontSize::Rem(1.5) } }。默认字体大小现在是 rem(1) 而不是 px(20);如果你不更改 RemSize,这不会有影响,但意味着当你更改时文本会默认缩放。

按列变更计数

组件现在可以通过 #[component(summary_tick)] 选择启用“列摘要变更计数”。启用后,除了“每实体变更 tick”外,还会存储一个“列变更 tick”,从而在查询变更时可以廉价地跳过整个实体列,而不必检查每个实体的组件是否变更。这使得变更操作更昂贵(需要同时写列变更 tick 和实体变更 tick),但对于变更查询频繁但实际很少变更的实体,这个权衡很容易值得!我们已经看到变更计数在 GPU 网格提取代码中带来了 132 倍的加速!

FixedNode

FixedNode 是 Bevy UI 的新标记组件。带有 FixedNode 组件的 UI 节点相对于目标相机的视口定位,而不是其父元素。FixedNode 不继承父级的布局、裁剪或变换上下文,行为类似“根节点”。

椭圆边框半径

图 7:椭圆边框半径

Bevy UI 现在可以绘制具有椭圆边框几何的节点。BorderRadius 的字段现在是 CornerRadius,以便为每个轴设置不同半径。例如:let a = BorderRadius::all(CornerRadius::circular(vh(10.))); let b = BorderRadius::all(vh(10.)); // a == b let c = BorderRadius::top_right(CornerRadius::new(px(10.), px(20.)));

调度随机化

在调度(以及你的系统)运行之前,它会根据系统的排序约束(.before()、.after()、.chain())和系统集计算系统运行顺序。但除此之外,调度还必须解决冲突——如果系统 A 和系统 B 都修改组件 C,且 A 和 B 之间没有排序,调度需要选择谁先运行。到目前为止,规则是这是非确定性的。但在实践中,调度“确定性地但任意地”选择这些冲突系统的顺序。简单说,你的系统可能偶然处于正确顺序,但对图做一个不相关的改动可能突然把它变成错误顺序,这个问题很难检测。现在我们引入调度随机化!它会在保持任何显式系统排序约束的同时随机化系统顺序。启用 debug 特性后,ScheduleBuildSettings 会包含一个 shuffle_seed 字段,用户可设置它来随机化调度。例如,用 rand::random() 生成种子并记录(以便发现 bug 时能复现),然后通过 edit_schedule 设置 shuffle_seed: Some(rng_seed)。这可用于“属性测试”,以验证你的系统在不同顺序下是否满足某些属性。但有一些注意事项:目前使用 auto_insert_apply_deferred 时,带命令的系统总是被放在它们能到达的最早同步点之前,这意味着即使系统顺序不正确,它们也可能因为使用的同步点而“偶然”获得正确顺序,我们希望未来修复此问题。此外,多线程执行器会贪婪地执行系统:它寻找第一个未执行且依赖已完成、且没有其他冲突系统正在运行的系统。结果是即使随机顺序是 (A, B, C),如果 A 和 B 冲突,C 也可能在 B 之前运行。这可能正是你想测试的,但可以考虑使用单线程执行器来避免这种情况。该工具与现有的系统顺序歧义检测(静态分析系统图)互补:歧义检测廉价地生成(有时很长的)潜在问题列表,其中并非所有都对应项目中的真实 bug;某些允许顺序下的真实测试失败能给你更可操作的信息,告诉你哪些问题是真实的,以及正确的顺序。此外,歧义检测可能有假阴性,通常是在歧义被错误忽略,或存在不需要写访问权限(从调度器视角)的内部可变性机制时。

捕获 Panic

对于长时间运行的程序,崩溃可能是不可接受的。例如,如果你的图像编辑器某个工具有 bug,最好让该工具失败或产生错误结果,而不是丢失所有未保存的工作。Bevy 的系统、命令和观察者能够返回错误,你可以逐个设置错误处理器,或让 FallbackErrorHandler 处理。但这过去只适用于显式返回的错误:Panic 曾导致整个应用退出。在 Bevy 0.20 中,这些 panic 现在会被转为错误并传给回退错误处理器。默认情况下这会重新 panic,但现在你可以选择记录错误并继续,或做任何你想做的事。

更快的批量销毁

有时你只想一次性销毁大量实体。这相当常见:Bevy 自己的 DespawnOnEnter 和 DespawnOnExit 允许你在切换游戏状态时快速清理实体,整理菜单或在失败后重置游戏。虽然总工作量不大,但都集中在一瞬间:如果这个过程慢,你可能会看到卡顿,或更长的加载画面。如果你使用新的 despawn_all<F: QueryFilter> 命令(或其同族命令)来批处理这项工作,ECS 可以通过降低开销(在相关操作间共享步骤)来加速。基准测试如下(五次运行中位数,AMD Ryzen 9 9950X3D):100 个实体,despawn 为 3.68 µs,despawn_all 为 2.84 µs(加速 1.30×);1,000 个:25.2 µs 对 15.3 µs(1.65×);10,000 个:254.9 µs 对 149.7 µs(1.70×);100,000 个:3.17 ms 对 2.07 ms(1.53×)。如果你使用 DespawnOnEnter 或 DespawnOnExit,无需更改代码即可免费获得此性能提升。

更好的纹理压缩

纹理是大多数 3D 游戏内存占用的重要部分。更小的纹理意味着更小的下载、更快的加载和更大的场景。Bevy 0.20 从两方面解决这个问题:改进的压缩方法,以及资源处理期间的自动 mipmap 生成。Bevy 的 CompressedImageSaver 资源处理器已显著升级,新的压缩后端由 ctt 库提供支持。新的 compressed_image_saver 特性将纹理压缩为 BCn 格式(桌面 GPU)或 ASTC 格式(移动 GPU),输出质量高于以前的 Basis Universal 方案:每字节获得更高画质。压缩器会根据输入纹理的通道数和类型自动选择最佳输出格式——例如单通道纹理用 BC4,HDR 纹理用 BC6H,标准 RGBA 纹理用 BC7。试试新的 compressed_image_saver 示例即可看到实际效果。

自动 mipmap 生成

不再需要手动生成 mipmap(为每个纹理生成的缩小版本,用于远距离查看)!新后端在压缩期间自动生成完整 mip 链。这意味着纹理在远距离查看时锯齿更少,GPU 缓存利用率更好——全部免费,只需让纹理通过资源处理器即可。

其他平台上的图像压缩

要针对移动 GPU,请设置 BEVY_COMPRESSED_IMAGE_SAVER_ASTC 环境变量为你想要的块大小(例如 4x4、6x6、8x8)。块越大文件越小,但质量越低。支持全部 14 种 ASTC 块大小。以前的 Basis Universal 压缩行为已移至 compressed_image_saver_universal 特性。这仍是跨平台分发(包括 WebGPU)的最佳选择,因为 UASTC 可在加载时转码为目标 GPU 支持的任何格式。

Bevy 错误上下文消息

与流行的 anyhow crate 类似,BevyError 现在提供了一种符合人体工学的方式,使用 context 方法为错误附加额外上下文,同时也允许从 Option<T> 创建 Result<T, BevyError>。这样可以更轻松地通过人类可读的消息追溯错误,而无需查看冗长的回溯。例如:let parsed: usize = "I am not a number".parse().context("Failed to parse number")?; 会产生错误消息 Failed to parse number: invalid digit found in string。with_context 可用于通过闭包生成上下文消息。如果多个 context 堆叠,记录错误时你会看到所有消息。例如,若 package.json 缺失,load_package 中 parse_package().context("Failed to parse package.json")? 会产生:Failed to parse package.json,以及 Caused by: Failed to read package.json 和 No such file or directory (os error 2)。

InlineBox 和 InlineImage

图 8:内联图片

让文本环绕元素可以创建更复杂的 UI 元素。新引入的 InlineBox 组件允许在文本布局中预留空间以放置自定义内容。要在文本中穿插图片,请生成一个带有 InlineImage 组件的实体。

下一步?

不管我们添加多少功能,社区总会要求更多。游戏引擎永远没有“完成”的一天。让我们窥探一下 Bevy 正在开发中的其他功能!和往常一样,其中许多是“Bevy 场景编辑器的必备组件”,即使它们不是“编辑器本身”。这样我们可以增量发布有用的部分,并在整合时打磨它们。

  • .bsn 资产格式:语法稳定后,是时候将 BSN 带到文件系统中,创建一种人类可读、支持热重载、为工具(即编辑器)驱动编写而设计的文件格式。
  • 资产即实体:虽然我们的资产处理一直在改进,但它仍是一个独立的数据模型。我们正在努力将资产表示为实体,让它们获得 ECS 的全部表达能力(包括事件观察者和关系),直接支持在 BSN 中定义资产,并降低学习曲线(因为资产像其他 ECS 数据一样访问)。
  • 远程检查器:从外部工具浏览、修改和变动实体,无论是在本机还是其他设备上!
  • 更强大的必需组件:希望能在必需组件中引入资产、根据其他实体/组件变化值或引用资源?我们也是:希望将必需组件与支持 BSN 的 Template trait 集成,并包含各种增强功能。
  • 互斥组件:一个长期被要求的功能:静态确保 Player 永远不会是 Camera,从而创建可依赖的不变量。
  • HDR(高动态范围)显示支持:Bevy:现在支持更多颜色!

评论

社区整体肯定 Bevy 的模块化架构、持续投入和技术进展,但对它是否已成熟到能承载商业项目存在明显分歧。称赞者强调设计优雅、原型和人工智能辅助开发速度惊人,质疑者则指出构建困难、破坏性更新频繁,实际工作中往往在维护引擎迁移而不是做玩法。

肯定模块化架构与团队持续投入

  • 认为 Bevy 在库设计上明显考虑了模块化,团队保持高频开发,贡献者和社区看起来既有主见又懂行;相比 Godot 常先堆功能、再逐渐打磨,Bevy 更早体现设计与体验上的考究,0.20 的 Solari 路径追踪等工作也令人印象深刻。(认可度:较多人) > 参与引擎建设的人往往既有主见又懂行,这让 Bevy 看起来更少出现“先实现功能、多个版本后才打磨”的情况。(@Fraterkes)

指出入门和构建体验仍然劝退

  • 虽然认同其模块化设计思路,但实际尝试时连构建都没跑通,入门门槛偏高,对新手并不友好。(认可度:少数人) > Bevy 听起来在库设计上考虑了模块化,但至今连构建都没成功,入门非常困难。(@bobajeff)

认为破坏性更新与版本迁移拖累交付

  • 点版本之间频繁引入破坏性变更,原本很好的开发体验会被迁移工作打断;结果是维护引擎升级而不是做玩法。有人以好玩心态学习时体验很棒,也理解这些变更是在解决重要问题,但仍判断它太不成熟,不能押上真正的商业产品。(认可度:较多人) > Bevy 的工效学在点版本发布前很好,之后你就得维护引擎迁移,而不是交付玩法。(@soltanov)

认为适合快速原型、模拟器和人工智能辅助开发

  • 结合人工智能代理做资产、美术和大部分编码时,Bevy 的设计让添加新功能和塑造游戏更轻松;有人一周就做出带局域网模式的即时战略游戏,效果可玩甚至接近《星际争霸 2》,也有人用它做城市与经济模拟器并进展顺利。它还被一些做模拟的公司列入招聘技能。(认可度:较多人) > 我用 Bevy 一周做出类似《星际争霸 2》的即时战略游戏,虽不及它在打磨和平衡上的水准,但实际已可比,这让我觉得不可思议。(@jablongo)

批评 BSN 场景格式语法设计糟糕

  • 场景格式 BSN 的符号过多,用 -- 分隔列表元素说明设计已走进死角;连 LR(1) 都不满足,本就该被视为设计错误,应当重新设计为编辑器优先,并把版本控制合并的便利性放在首位。(认可度:少数人) > 场景格式里符号太多,用 -- 分隔列表元素说明它已被设计进死角,连 LR(1) 都不满足,本就该预示它设计错了。(@pcwalton)

有价值的补充

  • pcwalton 提到自己在 0.20 贡献了渲染代码,把渲染在处理器端的开销降到与变更实体数量同阶,但发布说明里未提及这一点。
  • weinzierl 补充说,Jasmine 上周在 Bevy 聚会上做了关于 Solari 路径追踪的入门演讲,相关视频已发布在 YouTube,想深入了解可以看该演讲。