Bevy 0.2

发表于 2020 年 9 月 19 日,作者 Carter Anderson ( 一只戴着猫耳朵、挥舞着触手的剪影人物,即 Octocat:GitHub 的吉祥物和徽标 @cart 一只灰色鸟儿飞行的矢量图;X(前身为 Twitter)的旧徽标 @cart_cart 一个指向右边的三角形,在一个圆角矩形中;YouTube 的徽标 cartdev )

在最初的 Bevy 版本发布一个月后,感谢 **87** 位贡献者、**174** 个拉取请求以及我们慷慨的赞助商,我很高兴地宣布在crates.io上发布 **Bevy 0.2**!

对于那些不了解 Bevy 的人来说,Bevy 是一个用 Rust 构建的,令人耳目一新的简单、数据驱动的游戏引擎。您可以查看快速入门指南来开始。Bevy 永远免费且开源!您可以在 GitHub 上获取完整的源代码

以下是此版本中的一些亮点

异步任务系统 #

作者:@lachlansneff 和 @aclysma

Bevy 在整个引擎中使用多线程:ECS 调度、资产加载、渲染等。在此版本之前,它几乎对所有这些任务都使用Rayon。Rayon 很好,因为它通常与调用 some_list.par_iter().for_each(|x| do_something(x)) 一样简单。然后 Rayon 会自动将 for_each 分解成任务,并在尽可能多的核心上运行它们。如果您想轻松地并行化代码,Rayon 是一个不错的选择,但它也有一个缺点,那就是它非常占用 CPU。

Bevy(以及许多其他使用 rayon 的 Rust 游戏引擎和 ecs 框架)收到了有关它们过度占用 CPU/使用情况与完成的“实际”工作不成比例的反馈。

我们决定通过构建一个自定义的异步友好任务系统来解决这个问题,该系统支持创建特定于上下文的任务池。例如,您可能为计算、IO、网络等拥有单独的池。这也使我们能够根据工作类型和/或优先级灵活地适当地负载平衡工作。CPU 使用率的提高非常显著

总合并 CPU 使用率百分比 - 8 核机器(越小越好) #

threading cpu usage 8 core

总合并 CPU 使用率百分比 - 32 核机器(越小越好) #

threading cpu usage 32 core

初步的 Web 平台支持 #

作者:@smokku

(一部分)Bevy 现在使用 WebAssembly/WASM 在 Web 上运行!具体来说,Bevy 应用程序可以运行 Bevy ECS 调度、响应输入事件、创建空画布(使用 winit),以及其他一些事情。这是一个巨大的第一步,但重要的是要指出,仍然缺少许多部分,例如 2D/3D 渲染、多线程和声音。

这些限制并没有阻止 @mrk-its 构建第一个 WASM Bevy 游戏!

bevy-robbo (可在此处玩) #

bevy-robbo

他们使用 Bevy 进行游戏逻辑,并巧妙地绕过了渲染限制,将 ASCII 艺术游戏状态从此 Bevy 系统传递到此 JavaScript 函数

您可以按照此处的说明尝试一些 Bevy WASM 示例。

并行查询 #

作者:@GrantMoyer

Bevy ECS 查询是检索实体组件系统数据的灵活方法。使用查询的系统已经并行运行,但在更改之前,查询本身无法并行迭代Bevy 0.2 添加了轻松并行迭代查询的能力

fn system(pool: Res<ComputeTaskPool>, mut query: Query<&mut Transform>) {
    query.iter().par_iter(32).for_each(&pool, |mut transform| {
      transform.translate(Vec3::new(1.0, 0.0, 0.0));
    });
}

这提供了一个不错的函数式 API(类似于 Rayon),它运行在新的 bevy_tasks 系统之上。它将查询分解成 32 个“批次”,并将每个批次作为 bevy 任务系统中的不同任务运行。

变换系统重写 #

作者:@MarekLg
// old
fn system(translation: &Translation, rotation: &Rotation, scale: &Scale) {
  println!("{} {} {}", translation.0, rotation.0, scale.0);
}

// new
fn system(transform: &Transform) {
  println!("{} {} {}", transform.translation(), transform.rotation(), transform.scale());
}

Bevy 的旧变换系统使用单独的 TranslationRotationScale 组件作为“真理来源”。用户在其系统中使用这些组件进行修改,然后将它们同步到 LocalTransform 组件,该组件又会考虑到层次结构,同步到全局 Transform 组件。这在以下几个方面是不错的

  • 检索 Translation 等单个组件时,缓存效率略高(因为需要访问的数据更少)
  • 理论上更易于并行化。仅访问 Translation 的系统不会阻塞访问 Rotation 的系统。

但是,这种方法也有一些非常严重的缺点

  • “单个组件”是真理来源,因此当用户系统运行时,LocalTransform 已过期。如果需要最新的“完整变换”,则必须通过访问所有三个组件来手动构建它。
  • 非常难以理解。用户需要考虑 5 个组件,它们以不同的方式相互交互。
  • 将变换设置为特定的矩阵值(例如:Mat4::look_at())非常麻烦,并且除非用户显式禁用组件同步,否则该值会被立即覆盖。

鉴于这些问题,我们决定将单个统一的局部到父级的 Transform 组件作为真理来源,并计算出 GlobalTransform 组件以用于世界空间变换。我们认为这个 API 将更易于使用和理解。Unity 也正在考虑对其 ECS 进行类似的变换重写,并且在Amethyst 论坛主题中对此主题进行了大量讨论。

操纵杆/游戏手柄输入 #

作者:@simpuid

由于使用了gilrs 库,Bevy 输入插件现在对大多数控制器提供了跨平台支持!

fn button_system(gamepads: Res<Vec<Gamepad>>, button_input: Res<Input<GamepadButton>>) {
    for gamepad in gamepads.iter() {
        if button_input.just_pressed(GamepadButton(*gamepad, GamepadButtonType::RightTrigger)) {
            println!("Pressed right trigger!");
        }
    }
}

Bevy ECS 性能改进 #

作者:@cart

世代实体 ID #

我们将实体 ID 从随机 UUID 更改为递增的世代索引。随机 UUID 很好,因为它们可以在任何地方创建,在游戏运行期间是唯一的,并且可以安全地持久保存到文件或跨网络重用。我真的很希望我们能让它们发挥作用,但它们最终比其他方法慢太多。随机性会带来可衡量的成本,并且必须使用哈希表查找实体位置。

通过迁移到世代索引(我们使用 hecs 实现),我们可以直接使用实体 ID 作为数组索引,这使得实体位置查找非常快。

只读查询 #

我为不会修改任何内容的查询实现了“只读”特性。这使我们能够保证查询不会修改任何内容。

从 World API 中删除锁定 #

这让我们获得了非常不错的速度提升。由于结合了新的“只读查询”并将 World 修改 API 更改为可变的 World 借用,我们可以安全地做到这一点。

这尚未在系统中的 Queries 中启用,因为一个系统可能有多个 Queries,这些 Queries 可以以一种不使可变访问唯一的方式同时访问。我认为这是一个可以解决的问题,但它需要更多工作。幸运的是,“for-each”系统没有任何碰撞风险,因此我们现在在其中使用了无锁查询。

直接组件查找(以纳秒计,越小越好) #

由于这些优化,直接组件查找比以前快得多

get_component graph

请注意,此基准测试使用了 world.get::<T>(entity)query.get::<T>(entity) 应该具有类似于 hecs 结果的结果,因为它仍然使用锁。最终我希望我们也能从系统查询中删除锁。

变更日志 #

新增 #

更改 #

修复了 #

内部改进 #

Bevy CI 的许多改进:#325#349#357#373#423.

贡献者 #

非常感谢 **87 位贡献者** 使这次发布(以及相关的文档)成为可能!

  • 0x22fe
  • 8bit-pudding
  • aarongeorge
  • ablakey
  • aclysma
  • adekau
  • aevyrie
  • AmionSky
  • andreheringer
  • AngelOnFira
  • ashneverdawn
  • BafDyce
  • BimDav
  • bitshifter
  • Bobox214
  • Boiethios
  • caelunshun
  • cart
  • CleanCut
  • dallenng
  • DGriffin91
  • Dispersia
  • DJMcNab
  • eliaspekkala
  • EllenNyan
  • eXodiquas
  • figsoda
  • Fishrock123
  • FSMaxB
  • GabLotus
  • GrantMoyer
  • guimcaballero
  • Halfwhit
  • hannobraun
  • IceSentry
  • ifletsomeclaire
  • Incipium
  • io12
  • jakerr
  • jamadazi
  • joejoepie
  • JohnDoneth
  • julhe
  • kaflu
  • karroffel
  • lachlansneff
  • lberrymage
  • logannc
  • Lowentwickler
  • MarekLg
  • MatteoGgl
  • memoryruins
  • mfrancis107
  • MGlolenstine
  • MichaelHills
  • MilanVasko
  • Moxinilian
  • mrk-its
  • mtsr
  • multun
  • naithar
  • ncallaway
  • ndarilek
  • OptimisticPeach
  • PrototypeNM1
  • reidbhuntley
  • RobDavenport
  • saicu
  • simpuid
  • SmiteWindows
  • smokku
  • StarArawn
  • stefee
  • tarkah
  • TehPers
  • Telzhaak
  • TheNeikos
  • thirdsgames
  • TomBebb
  • tristanpemble
  • verzuz
  • VitalyAnkh
  • w1th0utnam3
  • Waridley
  • wyhaya
  • Xavientois
  • zicklag