迁移指南

迁移指南:0.9 到 0.10

Bevy 严重依赖于 Rust 语言和编译器的改进。因此,最低支持的 Rust 版本 (MSRV) 是 Rust 的“最新稳定版本”。

将引擎迁移到 Schedule v3(无阶段) #

渲染
ECS
  • 调用 .label(MyLabel) 应替换为 .in_set(MySet)

  • SystemLabel 派生应替换为 SystemSet。您还需要添加 DebugPartialEqEqHash 特征以满足新的特征边界。

  • 阶段已被移除。将这些替换为系统集,然后在需要的地方使用 apply_system_buffers 专属系统添加命令刷新。

  • CoreStageStartupStageRenderStageAssetStage 枚举已被替换为 CoreSetStartupSetRenderSetAssetSet。已保留相同的调度保证。

  • with_run_criteria 已重命名为 run_if。为了清楚起见,运行标准已重命名为运行条件,现在应简单地返回 bool 而不是 schedule::ShouldRun

  • 循环运行标准和状态堆栈已被移除。如果您需要这种级别的对系统控制流的控制,请使用运行调度的专属系统。

  • App::add_state 现在接受 0 个参数:根据 Default 实现设置起始状态。

  • 不要为在阶段中运行的系统创建 SystemSet 容器,而是使用 my_system.in_schedule(OnEnter(State::Variant)) 或其 OnExit 同级。

  • 对于应用程序级对何时运行哪些调度的控制流(例如用于回滚网络),请创建自己的调度并将其插入 CoreSchedule::Outer 标签下方。

  • 固定时间步长现在在调度中进行评估,而不是通过运行标准进行控制。默认情况下,run_fixed_timestep 系统在 CoreSet::FirstCoreSet::PreUpdate 之间运行此调度。

  • AssetStage 引入的命令刷新点已被移除。如果您依赖这些,请手动添加它们回来。

  • 带有 CalculateBounds 标签的 calculate_bounds 系统现在位于 CoreSet::Update 中,而不是在应用命令之前位于 CoreSet::PostUpdate 中。您可能需要将移动系统排序为在此系统之前发生,以避免在剔除行为中出现系统顺序歧义。

  • RenderLabel AppLabel 已重命名为 RenderApp,以提高清晰度

  • 在测试系统或以无头方式运行系统时,只需使用 Schedule::new()World::run_schedule 构造和运行调度,而不是构造阶段

  • 状态已大大简化:不再有“状态堆栈”。要将状态更改排队到下一个状态,请调用 NextState::set

  • 字符串不再可用作 SystemLabelSystemSet。使用类型,或使用系统函数。

阶段 #

阶段有两个关键元素:它们一个接一个地运行,并在最后应用命令。

前者可以使用系统集替换(除非您需要分支或循环调度逻辑,在这种情况下您应该使用调度),而后者可以使用 apply_system_buffers 手动控制。

为了从 Bevy 的内置阶段迁移,我们提供了 CoreSetStartupSetRenderSet 系统集。命令刷新已添加到这些中,但如果您添加了自定义阶段,则可能需要添加自己的命令刷新,如果您依赖于这种行为。

之前

app
    .add_system_to_stage(CoreStage::PostUpdate, my_system)
    .add_startup_system_to_stage(StartupStage::PostStartup, my_startup_system);

之后

app
    .add_system(my_system.in_base_set(CoreSet::PostUpdate))
    .add_startup_system(my_startup_system.in_base_set(StartupSet::PostStartup));

如果您有自己的阶段

// Bevy 0.9
#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)]
pub struct AfterUpdate;

app.add_stage_after(CoreStage::Update, AfterUpdate, SystemStage::parallel());

// Bevy 0.10, no command flush
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
#[system_set(base)]
pub struct AfterUpdate;

app.configure_set(
    AfterUpdate
        .after(CoreSet::UpdateFlush)
        .before(CoreSet::PostUpdate),
);

// Bevy 0.10, with a command flush
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
#[system_set(base)]
pub enum AfterUpdate {
    Parallel,
    CommandFlush
}

app.configure_sets(
    (
        CoreSet::UpdateFlush,
        AfterUpdate::Parallel,
        AfterUpdate::CommandFlush,
        CoreSet::PostUpdate,
    ).chain()
).add_system(apply_system_buffers.in_base_set(AfterUpdate::CommandFlush));

标签类型 #

系统标签已重命名为系统集,并与阶段标签统一。StageLabel 特征应替换为系统集,使用 SystemSet 特征,如以下讨论。

之前

#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)]
enum MyStage {
    BeforeRound,
    AfterRound,
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)]
enum MySystem {
    ComputeForces,
    FindCollisions,
}

之后

#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
enum MySet {
    BeforeRound,
    AfterRound,
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
enum MySystem {
    ComputeForces,
    FindCollisions,
}

系统集(Bevy 0.9) #

在 Bevy 0.9 中,您可以使用 SystemSet 类型和各种方法来同时配置多个系统。此外,这是与各种调度 API(如运行标准)交互的唯一方式。

之前

app.add_system_set(SystemSet::new().with_system(a).with_system(b).with_run_criteria(my_run_criteria));

之后

app.add_systems((a, b).run_if(my_run_condition));

歧义检测 #

ReportExecutionOrderAmbiguities 资源已被移除。相反,这是在每个调度基础上配置的。

app.edit_schedule(CoreSchedule::Main, |schedule| {
    schedule.set_build_settings(ScheduleBuildSettings {
        ambiguity_detection: LogLevel::Warn,
        ..default()
    });
})

固定时间步长 #

FixedTimestep 运行标准已被移除,现在由调度或 on_timer / on_fixed_timer 运行条件处理。

之前

app.add_stage_after(
    CoreStage::Update,
    FixedUpdateStage,
    SystemStage::parallel()
        .with_run_criteria(
            FixedTimestep::step(0.5)
        )
        .with_system(fixed_update),
);

之后

// This will affect the update frequency of fixed time for your entire app
app.insert_resource(FixedTime::new_from_secs(0.5))

    // This schedule is automatically added with DefaultPlugins
    .add_system(fixed_update.in_schedule(CoreSchedule::FixedUpdate));

应用程序现在可能只有一个统一的固定时间步长。CoreSchedule::FixedTimestep 用于在网络、物理和游戏机制期间实现确定性和稳定性。与计时器不同,如果自上次运行以来已超过一个时间段,它将反复运行。

打算用作循环计时器来定期执行工作或轮询。如果您依赖于具有不同时间段的多个 FixedTimestep 运行标准,您应该切换到使用计时器,通过 on_timer(MY_PERIOD)on_fixed_timer(MY_PERIOD) 运行条件。

之前

app.add_system_set(
    SystemSet::new()
        .with_run_criteria(FixedTimestep::step(0.5))
        .with_system(update_pathfinding),
)
.add_system_set(
    SystemSet::new()
        .with_run_criteria(FixedTimestep::step(0.1))
        .with_system(apply_damage_over_time),
);

之后

app
.add_system(update_pathfinding.run_if(on_timer(Duration::from_secs_f32(0.5))))
.add_system(apply_damage_over_time.run_if(on_timer(Duration::from_secs_f32(0.1))));

状态 #

状态已大大简化,不再有状态堆栈。每个状态类型(通常是枚举)都需要 States 特征,通常通过派生宏实现。

例如

#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
enum AppState {
    #[default]
    Menu,
    InGame,
}

App::add_state 不再接受参数:起始状态现在通过您的状态类型的 Default 实现控制。

要访问上面 States 类型的当前状态,请使用 Res<State<AppState>,并通过 .0 访问元组字段。要将状态更改排队,请使用 ResMut<NextState<AppState>> 并调用 .set(AppState::Menu).

状态更改现在通过 apply_state_transitions 专属系统应用,当您调用 App::add_state 时,会在 CoreSet::StateTransitions 中添加此系统的副本。您可以在需要的地方添加更多副本,特定于正在应用的状态。

OnEnterOnExit 系统现在位于调度中,通过 apply_state_transitions 系统在 World 上运行。相比之下,OnUpdate 现在是一个系统集,嵌套在 CoreSet::Update 中。

之前

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum AppState {
    Menu,
    InGame,
}

app.add_state(AppState::Menu)
    .add_system_set(SystemSet::on_enter(AppState::Menu).with_system(setup_menu))
    .add_system_set(SystemSet::on_update(AppState::Menu).with_system(menu))
    .add_system_set(SystemSet::on_exit(AppState::Menu).with_system(cleanup_menu))

之后

#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
enum AppState {
    #[default]
    Menu,
    InGame,
}

app.add_state::<AppState>()
    .add_system(setup_menu.in_schedule(OnEnter(AppState::Menu)))
    .add_system(menu.in_set(OnUpdate(AppState::Menu)))
    .add_system(cleanup_menu.in_schedule(OnExit(AppState::Menu)));

当您需要在 CoreSet::Update 之外运行特定于状态的系统时,您可以使用内置的 in_state 运行条件。

将窗口作为实体 #

窗口

WindowDescriptor 替换为 Window

widthheight 字段更改为 WindowResolution,方法是:

WindowResolution::new(width, height) // Explicitly
// or using From<_> for tuples for convenience
(1920., 1080.).into()

将任何 WindowCommand 代码替换为直接修改 Window 的字段,现在通过像这样生成/销毁具有 Window 组件的实体来创建/关闭窗口

let window = commands.spawn(Window { ... }).id(); // open window
commands.entity(window).despawn(); // close window

要获取窗口,您现在需要使用 Query 而不是 Res

// 0.9
fn count_pixels(windows: Res<Windows>) {
    let Some(primary) = windows.get_primary() else {
        return;
    };
    println!("{}", primary.width() * primary.height());
}

// 0.10
fn count_pixels(primary_query: Query<&Window, With<PrimaryWindow>>) {
    let Ok(primary) = primary_query.get_single() else {
        return;
    };
    println!("{}", primary.width() * primary.height());
}

使 SystemParam 派生宏更灵活 #

ECS

EventWriter 中已移除生命周期 's。任何显式指定此类型生命周期的代码都需要更新。

// 0.9
#[derive(SystemParam)]
struct MessageWriter<'w, 's> {
    events: EventWriter<'w, 's, Message>,
}

// 0.10
#[derive(SystemParam)]
struct MessageWriter<'w> {
    events: EventWriter<'w, Message>,
}

用于并行查询迭代的基本自适应批处理 #

ECS

Query(State)::par_for_each(_mut)batch_size 参数已移除。这些调用会自动为您计算批次大小。从所有调用这些函数的调用中删除这些参数。

// 0.9
fn parallel_system(query: Query<&MyComponent>) {
   query.par_for_each(32, |comp| {
        ...
   });
}

// 0.10
fn parallel_system(query: Query<&MyComponent>) {
   query.par_iter().for_each(|comp| {
        ...
   });
}

枚举 Visibility 组件 #

渲染
  • visibility.is_visible 字段的评估现在应该检查 visibility == Visibility::Inherited
  • 设置 visibility.is_visible 字段现在应直接设置值:*visibility = Visibility::Inherited
  • Visibility::VISIBLEVisibility::INVISIBLE 的使用现在应该分别使用 Visibility::InheritedVisibility::Hidden
  • ComputedVisibility::INVISIBLESpatialBundle::VISIBLE_IDENTITY 已分别重命名为 ComputedVisibility::HIDDENSpatialBundle::INHERITED_IDENTITY

bevy_reflect: 预解析路径 #

动画
反射

GetPath 方法已根据以下内容重命名

  • path -> reflect_path
  • path_mut -> reflect_path_mut
  • get_path -> path
  • get_path_mut -> path_mut

移除 App::add_sub_app #

App

App::add_sub_app 已移除,取而代之的是 App::insert_sub_app。使用 SubApp::new 并通过 App::insert_sub_app 插入它

// 0.9
let mut sub_app = App::new()
// Build subapp here
app.add_sub_app(MySubAppLabel, sub_app, extract_fn);

// 0.10
let mut sub_app = App::new()
// Build subapp here
app.insert_sub_app(MySubAppLabel, SubApp::new(sub_app, extract_fn));

使 HandleUntyped::id 私有 #

资源

不要直接访问 HandleUntyped 的 ID,如 handle.id,而应使用新的 getter handle.id()

CorePlugin 分解为 TaskPoolPluginTypeRegistrationPluginFrameCountPlugin #

核心

CorePlugin 已分解为单独的插件。如果不使用 DefaultPluginsMinimalPlugins PluginGroupCorePlugin 的替代方案现在是在应用程序中添加 TaskPoolPluginTypeRegistrationPluginFrameCountPlugin

用于元数据存储的不可变稀疏集 #

ECS

Table::component_capacity() 已移除,因为表不支持在构建后添加/移除列。

拆分组件 Tick #

ECS

与更改检测 Tick 交互的各种底层 API 不再返回 &UnsafeCell<ComponentTicks>,而是返回 TickCells,其中包含两个单独的 &UnsafeCell<Tick>

// 0.9
column.get_ticks(row).deref().changed

// 0.10
column.get_ticks(row).changed.deref()

记录和锁定 bevy_ecs::archetype 中的类型 #

ECS

ArchetypeIdArchetypeGenerationArchetypeComponentId 现在都是不透明的 ID,无法转换为数值。如果这无法满足您的用例,请提交问题,或查看 bevy_ecs 过度公开 以获取更多信息。

ArchetypeArchetypes 现在无法在 bevy_ecs 之外构造。使用 World::archetypes 获取对这些类型中任一类型的只读引用。

锁定对实体的访问 #

ECS

EntitiesDefault 实现已移除。您可以通过 World::entitiesWorld::entities_mut 获取对 WorldEntities 的引用。

Entities::alloc_at_without_replacementAllocAtWithoutReplacement 已设置为私有,因为在 bevy_ecs 之外正确使用它比较困难。如果您仍然需要使用此 API,请提交问题或查看 bevy_ecs 过度公开 以获取更多信息。

EventReader::clear 中使用借用而不是消耗 #

ECS

EventReader::clear 现在接受可变引用,而不是消耗事件读取器。这意味着 clear 现在需要对读取器变量进行显式可变访问,而之前在某些情况下可以省略。

// Old (0.9)
fn clear_events(reader: EventReader<SomeEvent>) {
  reader.clear();
}

// New (0.10)
fn clear_events(mut reader: EventReader<SomeEvent>) {
  reader.clear();
}

新类型 ArchetypeRow 和 TableRow #

ECS

Archetype 索引和 Table 行已作为 ArchetypeRowTableRow 进行新类型化。

完善未类型化的 API #

ECS

MutUntyped::into_inner 现在会将事物标记为已更改。

使用 TableId 和 TableRow 扩展 EntityLocation #

ECS

World 现在只能容纳最多 232 - 1 个原型和表。如果您的用例需要更多,请提交问题并解释您的用例。

移除 ExclusiveSystemParam::apply #

ECS

已移除特征方法 ExclusiveSystemParamState::apply。如果您有一个具有必须应用的缓冲区的独占系统,则应在独占系统的主体中应用它们。

移除 SystemParamState 特征,并移除类似 ResState 的类型 #

ECS

已移除特征 SystemParamStateSystemParamFetch,并且它们的函数已转移到 SystemParam

特征 ReadOnlySystemParamFetch 已替换为 ReadOnlySystemParam

// 0.9
impl SystemParam for MyParam<'_, '_> {
    type State = MyParamState;
}
unsafe impl SystemParamState for MyParamState {
    fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { ... }
}
unsafe impl<'w, 's> SystemParamFetch<'w, 's> for MyParamState {
    type Item = MyParam<'w, 's>;
    fn get_param(&mut self, ...) -> Self::Item;
}
unsafe impl ReadOnlySystemParamFetch for MyParamState { }

// 0.10
unsafe impl SystemParam for MyParam<'_, '_> {
    type State = MyParamState;
    type Item<'w, 's> = MyParam<'w, 's>;
    fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State { ... }
    fn get_param<'w, 's>(state: &mut Self::State, ...) -> Self::Item<'w, 's>;
}
unsafe impl ReadOnlySystemParam for MyParam<'_, '_> { }

在非源线程中丢弃 NonSend 时恐慌。 #

ECS

普通资源和 NonSend 资源不再共享相同的支持存储。如果 R: Resource,则 NonSend<R>Res<R> 将互相返回不同的实例。如果您同时使用 Res<T>NonSend<T>(或它们的可变变体)来获取相同的资源,强烈建议使用 Res<T>

记录 PtrPtrMutOwningPtr 的对齐要求 #

ECS

bevy_ptr 类型上的 new byte_addbyte_offset 方法的安全不变式已更改。所有调用者都应重新审核以确保其健全性。

添加 resource_id,并将 init_resourceinit_non_send_resource 更改为返回 ComponentId #

ECS
  • 添加 Components::resource_id
  • World::init_resource 更改为返回生成的 ComponentId
  • World::init_non_send_resource 更改为返回生成的 ComponentId

Events<Entity> 替换 RemovedComponents<T> 支持 #

ECS
  • removed: RemovedComponents<T> 添加 mut,因为我们现在正在内部修改事件读取器。
  • 遍历已移除的组件现在需要 &mut removed_componentsremoved_components.iter(),而不是 &removed_components

移除事件迭代器上的损坏 DoubleEndedIterator 实现 #

ECS

ManualEventIteratorManualEventIteratorWithId 不再是 DoubleEndedIterator,因为实现不正确,并且使用它的任何代码都可能已损坏。

Tick::is_older_than 重命名为 Tick::is_newer_than #

ECS

Tick::is_older_than 的用法替换为 Tick::is_newer_than

清理名为标签的系统集 #

ECS

PrepareAssetLabel 现在称为 PrepareAssetSet

简化 SystemParamFunction 特征的泛型 #

ECS

对于 SystemParamFunction 特征,类型参数 InOutParam 已转换为关联类型。

// 0.9
fn my_generic_system<T, In, Out, Param, Marker>(system_function: T)
where
    T: SystemParamFunction<In, Out, Param, Marker>,
    Param: SystemParam,
{ ... }

// 0.10
fn my_generic_system<T, Marker>(system_function: T)
where
    T: SystemParamFunction<Marker>,
{ ... }

对于 ExclusiveSystemParamFunction 特征,类型参数 Param 已转换为关联类型。此外,还添加了 InOut 关联类型,因为独占系统现在支持系统管道。

// 0.9
fn my_exclusive_system<T, Param, Marker>(system_function: T)
where
    T: ExclusiveSystemParamFunction<Param, Marker>,
    T: Param: ExclusiveSystemParam,
{ ... }

// 0.10
fn my_exclusive_system<T, Marker>(system_function: T)
where
    T: ExclusiveSystemParamFunction<Marker>,
{ ... }

弃用 ChangeTrackers<T>,改用 Ref<T> #

ECS

ChangeTrackers<T> 已弃用,将在下一个版本中移除。任何使用都应替换为 Ref<T>

// 0.9
fn my_system(q: Query<(&MyComponent, ChangeTrackers<MyComponent>)>) {
    for (value, trackers) in &q {
        if trackers.is_changed() {
            // Do something with `value`.
        }
    }
}

// 0.10
fn my_system(q: Query<Ref<MyComponent>>) {
    for value in &q {
        if value.is_changed() {
            // Do something with `value`.
        }
    }
}

EntityMut:将 remove_intersection 重命名为 remove,将 remove 重命名为 take #

ECS
// 0.9
fn clear_children(parent: Entity, world: &mut World) {
    if let Some(children) = world.entity_mut(parent).remove::<Children>() {
        for &child in &children.0 {
            world.entity_mut(child).remove_intersection::<Parent>();
        }
    }
}

// 0.10
fn clear_children(parent: Entity, world: &mut World) {
    if let Some(children) = world.entity_mut(parent).take::<Children>() {
        for &child in &children.0 {
            world.entity_mut(child).remove::<Parent>();
        }
    }
}

bevy_ecs: 没有 World 的 ReflectComponentFns #

ECS
反射

在调用已更改的 ReflectComponent 方法之前调用 World::entity,用户很可能已经拥有 EntityRefEntityMut,而这些方法正在被冗余地查询。

允许使用 EntityRef 遍历整个 World #

ECS
场景

World::iter_entities 现在返回 EntityRef 的迭代器,而不是 Entity 的迭代器。要获取实际的 ID,请使用返回的 EntityRefEntityRef::id

移除 WorldChildBuilderBuildWorldChildren 实现 #

层次结构

已从 WorldChildBuilder 中移除层次结构编辑方法,如 with_childrenpush_children。您可以通过 EntityMut 而不是通过 WorldChildBuilder 编辑层次结构。

重命名动态特征 #

元数据

dynamic 特征已重命名为 dynamic_linking

bevy_reflect: 在 List 中添加 insertremove 方法 #

反射

List 的手动实现者需要实现新的方法 insertremove,并考虑是否使用 pushpop 的新的默认实现。

bevy_reflect: 解耦 ListArray 特征 #

反射

List 特征不再依赖于 ArrayList 的实现者可以移除 Array 实现,并将它的方法移动到 List 实现中(只需要进行几处调整)。

// 0.9
impl Array for Foo {
  fn get(&self, index: usize) -> Option<&dyn Reflect> {/* ... */}
  fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {/* ... */}
  fn len(&self) -> usize {/* ... */}
  fn is_empty(&self) -> bool {/* ... */}
  fn iter(&self) -> ArrayIter {/* ... */}
  fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {/* ... */}
  fn clone_dynamic(&self) -> DynamicArray {/* ... */}
}

impl List for Foo {
  fn insert(&mut self, index: usize, element: Box<dyn Reflect>) {/* ... */}
  fn remove(&mut self, index: usize) -> Box<dyn Reflect> {/* ... */}
  fn push(&mut self, value: Box<dyn Reflect>) {/* ... */}
  fn pop(&mut self) -> Option<Box<dyn Reflect>> {/* ... */}
  fn clone_dynamic(&self) -> DynamicList {/* ... */}
}

// 0.10
impl List for Foo {
  fn get(&self, index: usize) -> Option<&dyn Reflect> {/* ... */}
  fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {/* ... */}
  fn insert(&mut self, index: usize, element: Box<dyn Reflect>) {/* ... */}
  fn remove(&mut self, index: usize) -> Box<dyn Reflect> {/* ... */}
  fn push(&mut self, value: Box<dyn Reflect>) {/* ... */}
  fn pop(&mut self) -> Option<Box<dyn Reflect>> {/* ... */}
  fn len(&self) -> usize {/* ... */}
  fn is_empty(&self) -> bool {/* ... */}
  fn iter(&self) -> ListIter {/* ... */}
  fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {/* ... */}
  fn clone_dynamic(&self) -> DynamicList {/* ... */}
}

需要进行的其他一些小调整包括

  • List::iter 使用 ListIter,而不是 ArrayIter(来自 Array::iter 的返回类型)
  • List 的实现者的 Reflect::reflect_hash 中将 array_hash 替换为 list_hash

bevy_reflect:从大多数 glam 类型中删除 ReflectSerializeReflectDeserialize 注册 #

反射
场景

此 PR 从大多数 glam 类型中删除了 ReflectSerializeReflectDeserialize 注册。这意味着任何依赖于这些 glam 类型存在的类型数据的代码都需要停止这样做。

这也意味着一些序列化后的 glam 类型需要更新。例如,以下是 Affine3A

// 0.9
(
  "glam::f32::affine3a::Affine3A": (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0),

// 0.10
  "glam::f32::affine3a::Affine3A": (
    matrix3: (
      x_axis: (
        x: 1.0,
        y: 0.0,
        z: 0.0,
      ),
      y_axis: (
        x: 0.0,
        y: 1.0,
        z: 0.0,
      ),
      z_axis: (
        x: 0.0,
        y: 0.0,
        z: 1.0,
      ),
    ),
    translation: (
      x: 0.0,
      y: 0.0,
      z: 0.0,
    ),
  )
)

在 ScalingMode::AutoMin 旁边添加 AutoMax #

渲染

ScalingMode::Auto 重命名为 ScalingMode::AutoMin

From<Icosphere> 更改为 TryFrom<Icosphere> #

渲染
// 0.9
shape::Icosphere {
    radius: 0.5,
    subdivisions: 5,
}
.into()

// 0.10
shape::Icosphere {
    radius: 0.5,
    subdivisions: 5,
}
.try_into()
.unwrap()

在 add_slot_edge、add_node_edge 中添加 try_* #

渲染

add_node_edgeadd_slot_edge 中删除 .unwrap()。对于处理了错误的用例,请改用 try_add_node_edgetry_add_slot_edge

input_node 中删除 .unwrap()。对于处理了选项的用例,请改用 get_input_node

着色器定义现在可以有值 #

渲染
  • shader_defs.push("NAME".into()); 替换 shader_defs.push(String::from("NAME"));
  • 如果您使用的是着色器定义 NO_STORAGE_BUFFERS_SUPPORT,请检查 Bevy 默认着色器AVAILABLE_STORAGE_BUFFER_BINDINGS 的使用方式。

从 wgpu 获取像素大小 #

渲染

PixelInfo 已被删除。PixelInfo::components 等同于 texture_format.describe().componentsPixelInfo::type_size 可以从 texture_format.describe().block_size/ texture_format.describe().components 获取。但请注意,这可能会对某些纹理类型(如 Rg11b10Float)产生不正确的结果。

在渲染世界中运行清除跟踪器 #

渲染

App 中对 clear_trackers 的调用已从调度移至 App::update(用于主世界),并且已在同一函数中为 sub_apps 添加了对 clear_trackers 的调用。这是因为需要更强的保证。如果在世界中没有调用 clear_trackers,则会导致 RemovedComponents 中发生内存泄漏。如果您以前使用 clear_trackers 对系统进行排序,那么现在无法这样做。

将相机“优先级”重命名为“顺序” #

渲染

Camera 的使用中将 priority 重命名为 order

减少 TrackedRenderPass 中的分支 #

渲染

TrackedRenderPass 现在需要一个 RenderDevice 来构建。为了简化操作,请改用 RenderContext.begin_tracked_render_pass

// 0.9
TrackedRenderPass::new(render_context.command_encoder.begin_render_pass(
  &RenderPassDescriptor {
    ...
  },
));

// 0.10
render_context.begin_tracked_render_pass(RenderPassDescriptor {
  ...
});

使 PipelineCache 在内部可变。 #

渲染

大多数 resource_mut::<PipelineCache>ResMut<PipelineCache> 的使用可以更改为 resource::<PipelineCache>Res<PipelineCache>,只要它们不使用任何需要可变性的方法——唯一需要它的公共方法是 process_queue

将 Msaa 更改为枚举 #

渲染
// 0.9
let multi = Msaa { samples: 4 }
// 0.10
let multi = Msaa::Sample4

// 0.9
multi.samples
// 0.10
multi.samples()

支持在 RenderContext 中录制多个 CommandBuffer #

渲染

RenderContext 的字段现在是私有的。请改用 RenderContext 上的访问器,并使用 RenderContext::new 构建它。

改进 OrthographicCamera 的一致性和可用性 #

渲染
  • window_origin 更改为 viewport_origin;用 Vec2::new(0.5, 0.5) 替换 WindowOrigin::Center,用 Vec2::new(0.0, 0.0) 替换 WindowOrigin::BottomLeft

  • 对于阴影投影等,用 area: Rect::new(left, bottom, right, top) 替换 leftrightbottomtop

  • 对于相机投影,从 OrthographicProjection 实例化中删除 l/r/b/t 值,因为它们在任何 ScalingMode 中都无效

  • ScalingMode::None 更改为 ScalingMode::Fixed

    • 用以下内容替换 l/r/b/t 的手动更改:
      • ScalingMode::Fixed 中的参数来指定大小
      • viewport_origin 来指定偏移量
  • ScalingMode::WindowSize 更改为 ScalingMode::WindowSize(1.0)

&mut PipelineCache 更改为 &PipelineCache #

渲染

SpecializedComputePipelines::specialize 现在接受一个 &PipelineCache 而不是 &mut PipelineCache

引入 detailed_trace 宏,在 TrackedRenderPass 中使用 #

渲染

一些详细的 bevy 跟踪事件现在需要使用 cargo 功能 detailed_trace(除了启用 TRACE 级别的日志记录)才能查看。如果您希望查看这些日志,请使用 bevy 功能 detailed_trace 编译您的代码。目前,唯一受影响的日志是与 TrackedRenderPass 函数相关的渲染器日志。

在 shape::Plane 中添加细分 #

渲染

shape::Plane 现在接受一个额外的 subdivisions 参数,因此用户应该提供它,或者使用新的 shape::Plane::from_size()

更改标准材质默认值并更新文档 #

渲染

StandardMaterial 的默认值现在已更改为具有中等粗糙度的全电介质材质。如果您想使用旧的默认值,可以设置 perceptual_roughness = 0.089metallic = 0.01(不过 metallic 通常应仅设置为 0.0 或 1.0)。

在 #7784 之后删除无用代码 #

渲染

删除了 SetShadowViewBindGroupqueue_shadow_view_bind_group()LightMeta::shadow_view_bind_group,改用预备传递视图绑定组。

直接将关节提取到 SkinnedMeshJoints 中 #

渲染
动画

ExtractedJoints 已被删除。请改用 SkinnedMeshJoints 读取绑定骨骼。

将 glTF 颜色解释为线性而不是 sRGB #

渲染
资源

不需要任何 API 更改,但您的 gltf 网格可能看起来不同。

将发射颜色作为线性而不是 sRGB 发送到统一变量 #

  • 如果您以前使用 Color::rgb() 手动指定了发射值,并且想要保留旧的视觉效果,那么现在必须改用 Color::rgb_linear()
  • 如果您以前使用 Color::rgb_linear() 手动指定了发射值,并且想要保留旧的视觉效果,则需要对您的通道手动应用一次伽马计算才能获得实际的线性 RGB 值。
    • 对于大于 0.0031308 的通道值,请使用 (1.055 * value.powf(1.0 / 2.4)) - 0.055
    • 对于小于或等于 0.0031308 的通道值,请使用 value * 12.92
  • 否则,结果现在应该与其他工具/引擎更加一致。

update_frame_count 系统应放置在 CorePlugin 中 #

渲染
核心
时间

FrameCount 资源以前仅在使用 bevy_render 功能时更新。如果您没有使用此功能,但仍然想要 FrameCount,它现在将被正确更新。

流水线渲染 #

渲染
任务

App runner 和 SubApp extract 函数现在需要是 Send

这样做是为了启用流水线渲染。如果这破坏了您的用例,请报告,因为这些新边界可能能够放松。

删除 ImageMode #

渲染
UI

ImageMode 从未生效,如果您正在使用它,请创建一个问题。

将 'ExtractedUiNodebackground_color重命名为color` #

渲染
UI

ExtractedUiNodebackground_color 字段现在名为 color

删除 GlobalTransform::translation_mut 方法 #

变换
层次结构

GlobalTransform::translation_mut 已被删除,没有替代方案,如果您依赖于此,请更新 Transform。如果给定的实体有子实体或父实体,您可能需要删除它的父实体以使它的变换独立(在这种情况下,新的 Commands::set_parent_in_placeCommands::remove_parent_in_place 可能有用)。

Bevy 可能会在将来添加一种基于实体的变换传播切换方法。

翻转 UI 图像 #

UI
  • UiImage 现在是一个结构体,因此请使用 UiImage::new(handler) 而不是 UiImage(handler)
  • UiImage 不再实现 DerefDerefMut,因此请改用 &image.texture&mut image.texture

删除 TextError::ExceedMaxTextAtlases(usize) 变体 #

UI

TextError::ExceedMaxTextAtlases(usize) 从未抛出,因此如果您匹配此变体,可以简单地删除它。

将默认 FocusPolicy 更改为 Pass #

UI

FocusPolicy 的默认值已从 FocusPolicy::Block 更改为 FocusPolicy::Pass

从 TextAlignment 中删除 VerticalAlign #

UI

Textalignment 字段现在只影响文本的内部对齐方式。

TextAlignment 更改为 TextAlignment,它现在是一个枚举。替换

  • TextAlignment::TOP_LEFTTextAlignment::CENTER_LEFTTextAlignment::BOTTOM_LEFTTextAlignment::Left
  • TextAlignment::TOP_CENTERTextAlignment::CENTER_LEFTTextAlignment::BOTTOM_CENTERTextAlignment::Center
  • TextAlignment::TOP_RIGHTTextAlignment::CENTER_RIGHTTextAlignment::BOTTOM_RIGHTTextAlignment::Right

Text2dBundle 的更改

Text2dBundle 有一个新的字段 text_anchor,它接受一个 Anchor 组件,该组件控制它相对于其变换的位置。

Text2dSize 已被删除。请改用 TextLayoutInfo

删除 QueuedText #

UI

QueuedText 从未面向用户。如果您依赖于它,请创建一个问题。

更改 Size 的默认 widthheightVal::Auto #

UI

Size 的默认 widthheight 值已从 Val::Undefined 更改为 Val::Auto。这不太可能导致现有代码出现问题。

修复使用错误默认值的 Size 辅助函数,并改进 UI 示例 #

UI

Size::width 构造函数现在将 height 设置为 Val::Auto,而不是 Val::UndefinedSize::height 构造函数现在将 width 设置为 Val::Auto,而不是 Val::Undefined

CalculatedSizesize 字段不应为 Size #

UI

CalculatedSizesize 字段已更改为 Vec2

将 winit 更新到 0.28 #

窗口
// 0.9
app.new()
    .add_plugins(DefaultPlugins.set(WindowPlugin {
        primary_window: Some(Window {
            always_on_top: true,
            ..default()
        }),
        ..default()
    }));

// 0.10
app.new()
    .add_plugins(DefaultPlugins.set(WindowPlugin {
        primary_window: Some(Window {
            window_level: bevy::window::WindowLevel::AlwaysOnTop,
            ..default()
        }),
        ..default()
    }));