大家好,我是何三,独立开发者
261 位贡献者,1185 个 PR,一个小版本迭代。
这是 Bevy 0.19 交出的成绩单。这个 Rust 游戏引擎在 GitHub 上收获了近 4 万 Star,在开源游戏引擎圈子里,已经是最活跃的那一档了。
但这次更新最炸裂的,不是渲染性能又翻了多少倍,也不是阴影效果有多逼真——而是一套全新的场景系统:BSN(Bevy Scene Notation)。
说得直接点,以前你要在 Bevy 里堆一个 UI 面板加按钮再加几个子组件,代码能写到 50-80 行,中间还得手动处理 AssetServer 传参、Bundle 组合、children 嵌套。现在用 BSN,10 行搞定。
我第一反应是:没搞错吧?

BSN 是啥?一句话说清楚
BSN 的全称是 Bevy Scene Notation——听起来很唬人,说白了就是一套用来描述"场景里有什么"的语法。
你写一个 bsn! 宏,在里面定义你的游戏对象和组件,它自动帮你搞定所有 ECS 注册、依赖注入、子实体生成。
看对比:
以前(旧 Bundle 方式):
fn player(asset_server: &AssetServer) -> impl Bundle {
(
Player { score: 10, ..default() },
children! [
Sprite {
image: asset_server.load("player.png"),
..default()
}
]
)
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(player(&asset_server));
}
现在(BSN 方式):
fn player() -> impl Scene {
bsn! {
Player { score: 10 }
Children [
Sprite { image: "player.png" }
]
}
}
fn setup(mut commands: Commands) {
commands.spawn_scene(player());
}
前者要把 AssetServer 当参数传来传去,后者直接写一个图片路径字符串就行。
看到区别了吗?BSN 内部实现了 Template 机制,它能自动从 "player.png" 这个字符串去加载资源、生成 Handle,完全不需要你手动调用 asset_server.load()。
说实话,这块我也没完全搞懂底层的实现细节,但用起来真的太爽了。
一个游戏场景的代码量从 100 行降到 10 行
让我再说一个更狠的例子。
假设你有一个 UI 按钮,点击后打印日志。旧版 Bevy 的写法之长,让我一直觉得 Bevy 的 UI 代码像在写配置文件。
旧方式——按需传参 + Bundle + 事件监听:
fn spawn_button(commands: &mut Commands, asset_server: &AssetServer) {
commands.spawn((
Button,
Node {
width: Val::Px(100.),
height: Val::Px(50.),
..default()
},
children! [
Text(TextStyle {
font: asset_server.load("fonts/Noto.ttf"),
font_size: 16.,
..default()
})
],
On::<Pointer<Press>>::run(|_| {
info!("button pressed!");
}),
));
}
BSN 方式:
fn button() -> impl Scene {
bsn! {
Button
Node { width: px(100), height: px(50) }
Children [
Text("Click Me")
]
on(|_: On<Pointer<Press>>| info!("button pressed!"))
}
}
一个是手动管理每一条依赖,一个是写声明式标记——这种差别怎么说呢,就好比你以前得自己劈柴生火做饭,现在打开燃气灶就行。
而且 BSN 支持可组合的补丁式场景(Composable Patches)。你可以写一个基础按钮场景,然后在它的基础上覆盖修改:
fn base_button() -> impl Scene {
bsn! { Button Node { width: px(100), height: px(50) } }
}
fn red_button() -> impl Scene {
bsn! {
base_button()
Node { background_color: RED }
}
}
没懂作者为什么这么设计?我猜是为了配合未来即将发布的 Bevy Editor。以后你拖拽式编辑场景,底层导出的就是 BSN 文件,然后代码里可以直接 patch 覆盖——这设计思路,怎么说呢,有远见。
等等,BSN 能做的事还不止这些
这个系统还有一些让我觉得"卧槽这都可以"的功能:
- 实体引用语法:可以用
#Player1这样的名字标记实体,然后在场景内任意引用它,支持定义图结构 - 自动缓存:用
:前缀标记的场景会被缓存,多次实例化只解析一次 - 事件观察器:直接在
bsn!里绑定on()回调,不用单独写系统 - 内联资源:
asset_value(Cuboid::new(1., 1., 1.))直接在场景里定义资源,不用先加到 Assets 再拿 Handle
让我印象最深的是那个缓存机制。你做一个 MMORPG,要刷 1000 个 NPC,每个 NPC 场景里嵌套了武器、装备、AI 行为。以前你得遍历 1000 次全部重新解析,现在只要在场景路径前加个 :,它自动缓存,后续实例化只补丁覆盖差异化部分。
这个压缩率——算了先不说这个,你上手跑一下就知道了。

不只是 BSN:0.19 版本还有哪些硬货
BSN 是最大亮点,但不是唯一亮点。这个版本的其他更新也值得一提:
Contact Shadows(接触阴影) 以前 Bevy 的阴影,怎么说呢,能用但说不上好看。0.19 引入了 Contact Shadows,在物体接触边缘生成精细的暗部细节,不需要开光线追踪,帧率几乎没影响。和没开之前放到一起对比,观感差距就像是"手机摄像头 vs 单反"。
Text Input(文本输入)
Bevy UI 终于有了原生的文本输入组件 EditableText。之前做 UI 的用户想要个输入框,得自己写第三方插件,或者绑定系统级输入。这次终于官方支持了。
Rectangular Area Lights(矩形面光源) 做室内场景或者产品展示的福音。普通点光源的光照太"假",面光源出来的效果更接近真实世界的软光。对于想用 Bevy 做建筑可视化的人来说,这个功能真的吹爆。
Post-Processing 效果 内置了暗角(Vignette)和镜头畸变(Lens Distortion)这两种后处理特效。以前你得自己写 shader,现在直接开箱即用。
Renderer 性能优化 大量渲染工作从 CPU 转移到了 GPU,GPU Driven 管线的趋势越来越明显。大场景下的帧率提升非常可观。
同类工具怎么选?
如果你在 Rust 生态里选游戏引擎,基本就两个选择:Bevy 和 Fyrox。
Fyrox 的优势是有可视化编辑器,你对着一堆 YAML 配置文件头疼的话,Fyrox 可能更适合你。但 Bevy 的社区活跃度和生态广度远超 Fyrox——近 4 万 Star,3500+ Fork,Crates.io 上的依赖量级不在一个数量级。
如果你在跨引擎比较——Bevy vs Godot vs Unity: - Unity:C# 生态,商业化,现在还在闹收费争议 - Godot:原生场景系统非常成熟,GDScript + 可视化编辑器 - Bevy:纯 Rust,ECS 架构,天生高性能,但没有编辑器(Editor 正在开发中)
选哪个取决于你想做什么。如果你只是想快速搭个 2D 小游戏,Godot 上手更快。但如果你想用 Rust 写一个高性能、多线程、数据驱动的 3D 游戏,Bevy 是目前唯一的选择——而且 0.19 的 BSN 让代码量直接腰斩再腰斩。
项目地址:https://github.com/bevyengine/bevy
写在最后
Bevy 0.19 的 BSN 场景系统,让我看到了 ECS 架构在"开发体验"上的进化方向。
以前大家都在吹 ECS 的性能优势——多核并行、缓存友好、数据驱动。但性能再好,如果代码写起来比传统 OOP 麻烦三倍,还是劝退的。BSN 的出现,把 ECS 的开发体验拉到了和声明式 UI 一样舒适的水平。
有 261 个人花了 1185 个 PR 才搓出这个大版本,不容易。但我可以负责任地说:Bevy 0.19,值得你花一个下午重写你的游戏场景逻辑。
本文使用 MGO 编辑并发布
关注"何三笔记",回复"mgo" 免费下载使用