大家好,我是何三,独立开发者

261 位贡献者,1185 个 PR,一个小版本迭代。

这是 Bevy 0.19 交出的成绩单。这个 Rust 游戏引擎在 GitHub 上收获了近 4 万 Star,在开源游戏引擎圈子里,已经是最活跃的那一档了。

但这次更新最炸裂的,不是渲染性能又翻了多少倍,也不是阴影效果有多逼真——而是一套全新的场景系统:BSN(Bevy Scene Notation)

说得直接点,以前你要在 Bevy 里堆一个 UI 面板加按钮再加几个子组件,代码能写到 50-80 行,中间还得手动处理 AssetServer 传参、Bundle 组合、children 嵌套。现在用 BSN,10 行搞定。

我第一反应是:没搞错吧?

代码对比:旧 Bundle 方式 vs BSN

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 场景系统六大核心特性

不只是 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 生态里选游戏引擎,基本就两个选择:BevyFyrox

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" 免费下载使用