- 0.10 到 0.11
- Schedule-First:改进后的 add_systems
- bevy_audio:基于 ECS 的 API 重构
- 允许在 add_plugins 中使用元组和单个插件,弃用 add_plugin
- 改进着色器导入模型
- 扁平化使用 Size 的 UI Style 属性并移除 Size
- 将 ScheduleRunnerSettings 合并到 ScheduleRunnerPlugin
- 添加对自定义 glTF 顶点属性的支持。
- 延迟资产热重载
- 允许使用 Diagnostics 的系统并行运行
- 将日志记录到 stderr 而不是 stdout
- 使 WorldQuery 元类型不可命名
- 提高变更检测的类型安全性和清晰度
- 移除 ChangeTrackers
- 在 assert_is_system 中检查冲突访问
- 移除 ScheduleBuildError 的基础集合错误变体
- 移除 #[system_param(ignore)] 和 #[world_query(ignore)]
- 用安全代码替换一些不安全的系统执行器代码
- 使用 UnsafeWorldCell 提高 SystemParam 代码质量
- 更新 increment_change_tick 以返回强类型 Tick
- 使 State 资源的 state 私有,只能通过 getter 访问
- 仅当 next_state != old_state 时才触发状态转换
- 简化系统管道并使其更灵活
- 简化世界调度方法
- 重命名 UnsafeWorldCell::read_change_tick
- 使用 UnsafeWorldCell 提高多线程执行器的安全性
- 改进命令的封装并添加文档
- 重命名 apply_system_buffers 为 apply_deferred
- 重命名 Command 的 "write" 方法为 "apply"
- 在 QueryState::par_iter 中要求只读查询
- 将引擎的其余部分迁移到 UnsafeWorldCell
- 简化 ComponentIdFor 类型
- 使 QueryParIter::for_each_unchecked 私有
- 弃用 WorldQuery::Fetch 的类型别名
- 为 EntityRef 实现 WorldQuery
- 将 AppTypeRegistry 迁移到 bevy_ecs
- 使场景对实体引用的处理更加健壮
- 重命名 map_entities 和 map_specific_entities
- 要求所有事件都使用 #[derive(Event)]
- 修复 boxed 标签
- 移除 OnUpdate 系统集
- 记录查询错误
- 更新 syn、encase、glam 和 hexasphere
- 重命名键,例如 LAlt 为 AltLeft
- 重命名 Interaction::Clicked 为 Interaction::Pressed
- 在 UntypedReflectDeserializerVisitor 中不要忽略额外的条目
- FromReflect 人体工程学实现
- bevy_reflect:稳定类型路径 v2
- 在 bevy_reflect::Map 特性中添加 get_at_mut
- bevy_reflect:更好的代理
- 从世界构造 Box<dyn Reflect> 以用于 ReflectComponent
- 在预处理着色器中添加 Globals 结构
- 使渲染图槽位在大多数情况下可选
- 从 DynamicUniformBuffer 和 DynamicStorageBuffer 中移除不必要的 values Vec
- 将 (Vec2, Vec2) 更改为 Camera::logical_viewport_rect 中的 Rect
- 使 glsl 和 spirv 支持可选
- 更改默认色调映射方法
- 应用代码库更改,为 StandardMaterial 传输做准备
- 移除 AlphaMode 的 Component 派生
- 重命名 Plane 结构为 HalfSpace
- 修复 Plane UV/纹理翻转
- 添加 RenderTarget::TextureView
- 一致的屏幕空间坐标
- Webgpu 支持
- 在 CI 中获取示例截图
- 计算 GpuMesh 上索引网格的 vertex_count
- 内置天空盒
- 左手系 y 轴向上立方体贴图坐标
- 为 Sprite、TextureAtlasSprite 和 Mesh2d 添加 Aabb 计算
- 添加变形目标
- bevy_scene:添加 SceneFilter
- (去)序列化场景中的资源
- 修复 look_to 变量命名
- 修复孤立实体的变换传播
- 移除 Val::Undefined
- 将 linebreak_behaviour 的拼写更改为 linebreak_behavior
- 在 bevy_ui 中添加 CSS Grid 支持
- MeasureFunc 改进
- 在将 UI 坐标从物理坐标转换为逻辑坐标时除以 UiScale
- NoWrap 文本功能
- 用存储在组件中的标志替换文本系统中的本地文本队列
- 按轴拆分 UI 溢出
- text_system 拆分
- 更新 ahash 和 hashbrown
- 将 bevy_ui 可访问性系统移动到 PostUpdate
迁移指南:0.10 到 0.11
Bevy 严重依赖 Rust 语言和编译器的改进。因此,最低支持 Rust 版本 (MSRV) 是 Rust 的“最新稳定版本”。
Schedule-First:改进后的 add_systems #
我们已经 将添加系统到调度的操作统一到一个 API 下!add_systems
现在接受 ScheduleLabel
作为第一个参数。app.add_system
、app.add_startup_system
、app.add_startup_systems
、system.on_startup()
和 system.in_schedule()
已被弃用,建议使用统一的 app.add_systems
API。
“基础集”已被完全移除,取而代之的是调度。内置的 CoreSet
和 StartupSet
基础集已被顶级调度所取代。(例如:CoreSet::Update
现在是 Update
调度)。
这去掉了大量冗余的 API,完全消除了隐式默认值,并消除了基础集引入的大量混淆。我们相信新的 add_systems
API 的一致性和人体工程学不言而喻
// 0.10
app.add_system(a)
// 0.11
app.add_systems(Update, a)
// 0.10
app.add_systems((a, b).in_schedule(CoreSchedule::Startup))
// 0.11
app.add_systems(Startup, (a, b))
// 0.10
app.add_systems((a, b).in_schedule(CoreSchedule::Startup).in_base_set(StartupSet::PreStartup))
// 0.11
app.add_systems(PreStartup, (a, b))
// 0.10
app.add_startup_systems((a, b))
// 0.11
app.add_systems(Startup, (a, b))
// 0.10
app.add_systems((a, b).on_startup())
// 0.11
app.add_systems(Startup, (a, b))
// 0.10
app.add_systems((c, d, e))
// 0.11 (Update is no longer implied by default)
app.add_systems(Update, (c, d, e))
// 0.10
app.add_systems((f, g).in_schedule(CoreSchedule::FixedUpdate))
// 0.11
app.add_systems(FixedUpdate, (f, g))
// 0.10
app.add_systems(h.in_base_set(CoreSet::PostUpdate))
// 0.11
app.add_systems(PostUpdate, h)
// 0.10
app.add_systems(enter_menu.in_schedule(OnEnter(AppState::Menu)))
// 0.11
app.add_systems(OnEnter(AppState::Menu), enter_menu)
// 0.10
app.add_systems(exit_menu.in_schedule(OnExit(AppState::Menu)))
// 0.11
app.add_systems(OnExit(AppState::Menu), exit_menu)
// 0.10
render_app.add_systems((a, b).in_set(RenderSet::Queue))
// 0.11
render_app.add_systems(Render, (a, b).in_set(RenderSet::Queue))
设置配置现在也接受调度
// 0.10
app.configure_set(A.in_schedule(PostUpdate).after(B))
// 0.11
app.configure_set(PostUpdate, A.after(B))
// 0.10
app.configure_set(A.after(B))
// 0.11 (Update is no longer implied by default)
app.configure_set(Update, A.after(B))
// 0.10
app.configure_sets((A, B).in_schedule(PostUpdate).after(C))
// 0.11
app.configure_sets(PostUpdate, (A, B).after(C))
// 0.10
app.configure_sets((A, B).after(C))
// 0.11 (Update is no longer implied by default)
app.configure_sets(Update, (A, B).after(C))
bevy_audio:基于 ECS 的 API 重构 #
// 0.10
/// Need to store handles somewhere
#[derive(Resource)]
struct MyMusic {
sink: Handle<AudioSink>,
}
fn play_music(
asset_server: Res<AssetServer>,
audio: Res<Audio>,
audio_sinks: Res<Assets<AudioSink>>,
mut commands: Commands,
) {
let weak_handle = audio.play_with_settings(
asset_server.load("music.ogg"),
PlaybackSettings::LOOP.with_volume(0.5),
);
// upgrade to strong handle and store it
commands.insert_resource(MyMusic {
sink: audio_sinks.get_handle(weak_handle),
});
}
fn toggle_pause_music(
audio_sinks: Res<Assets<AudioSink>>,
mymusic: Option<Res<MyMusic>>,
) {
if let Some(mymusic) = &mymusic {
if let Some(sink) = audio_sinks.get(&mymusic.sink) {
sink.toggle();
}
}
}
// 0.11
/// Marker component for our music entity
#[derive(Component)]
struct MyMusic;
fn play_music(
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
commands.spawn((
AudioBundle {
source: asset_server.load("music.ogg"),
settings: PlaybackSettings::LOOP.with_volume(Volume::new_relative(0.5)),
},
MyMusic,
));
}
fn toggle_pause_music(
// `AudioSink` will be inserted by Bevy when the audio starts playing
query_music: Query<&AudioSink, With<MyMusic>>,
) {
if let Ok(sink) = query_music.get_single() {
sink.toggle();
}
}
允许在 add_plugins
中使用元组和单个插件,弃用 add_plugin
#
将 app.add_plugin(plugin)
调用替换为 app.add_plugins(plugin)
。
改进着色器导入模型 #
不使用 #import
指令的着色器应该无需更改即可工作。
最显著的用户界面差异是导入的函数/变量等需要在使用点进行限定,并且没有从导入的导入中将可见的东西“泄漏”到你的着色器作用域中,因此,如果你使用了导入的导入中导入的东西,现在需要直接导入它们并进行限定。
当前直接将 mesh_vertex_output
包含/“扩展”到结构体中的策略不再有效,因此需要根据示例进行修改(例如:color_material.wgsl
或许多其他示例)。网格数据默认情况下假定在绑定组 2 中,如果网格数据绑定到绑定组 1,则需要将着色器定义 MESH_BINDGROUP_1
添加到管道的 shader_defs
中。
// 0.10
struct FragmentInput {
#import bevy_pbr::mesh_vertex_output
}
@fragment
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {}
// 0.11
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
@fragment
fn fragment(in: MeshVertexOutput) -> @location(0) vec4<f32> {}
如果你正在导入类似 mesh_view_bindings
的东西,但仅用于 globals
统一缓冲区,现在可以将其直接导入。
// 0.10
#import bevy_pbr::mesh_view_bindings
// use globals.time after this
// 0.11
#import bevy_pbr::mesh_view_bindings globals
// globals is now in scope, but nothing else is imported
扁平化使用 Size
的 UI Style
属性并移除 Size
#
size
、min_size
、max_size
和 gap
属性已被 width
、height
、min_width
、min_height
、max_width
、max_height
、row_gap
和 column_gap
属性取代。请使用新的属性。
将 ScheduleRunnerSettings 合并到 ScheduleRunnerPlugin #
不要插入 ScheduleRunnerSettings
资源,而是配置 ScheduleRunnerPlugin
// 0.10
.insert_resource(ScheduleRunnerSettings::run_loop(Duration::from_secs(5)))
.add_plugin(ScheduleRunnerPlugin::default())
// 0.11
.add_plugin(ScheduleRunnerPlugin::run_loop(Duration::from_secs(5)))
添加对自定义 glTF 顶点属性的支持。 #
如果你之前使用类似于单元的结构体语法实例化 GltfPlugin
,则必须改为使用 GltfPlugin::default()
,因为该类型不再是类似于单元的类型。
延迟资产热重载 #
// 0.10
.add_plugins(DefaultPlugins.set(AssetPlugin {
watch_for_changes: true,
..default()
}))
// 0.11
.add_plugins(DefaultPlugins.set(AssetPlugin {
// You can now give it a configurable delay. This is a safe default.
watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)),
..default()
}))
允许使用 Diagnostics 的系统并行运行 #
- 使用新的
app.register_diagnostic(Diagnostic::new(DIAGNOSTIC_ID, "diagnostic_name", 10));
注册Diagnostic
。 - 在用于写入新度量的系统中,将
mut diagnostics: ResMut<Diagnostics>
更改为mut diagnostics: Diagnostics
以允许系统并行运行。
- fn system(mut diagnostics: ResMut<Diagnostics>) {}
+ fn system(mut diagnostics: Diagnostics) {}
- 在用于读取度量的系统中,将
diagnostics: Res<Diagnostics>
更改为diagnostics: Res<DiagnosticsStore>
。
- fn system(diagnostics: Res<Diagnostics>) {}
+ fn system(diagnostics: Res<DiagnosticsStore>) {}
将日志记录到 stderr 而不是 stdout #
在类 Unix 系统上,当打印日志(如 info!
、trace!
、error!
等)时,从 stderr
中读取,而不是从 stdout
中读取
- 在命令行上使用
2> output.log
将stderr
保存到文件
使 WorldQuery
元类型不可命名 #
使用 #[derive(WorldQuery)]
创建的类型的 State
和 Fetch
类型现在不可命名。如果需要引用它们,请使用语法 <T as WorldQuery>::State
、<T as WorldQuery>::Fetch
。
提高变更检测的类型安全性和清晰度 #
引擎现在使用 Tick
类型来处理变更滴答,而不是 u32
。任何与引擎内部进行交互的代码都需要更新,包括
- 手动实现
SystemParam
、WorldQuery
、DetectChanges
和DetectChangesMut
特性的代码。 World::change_tick
和read_change_tick
方法。System::set_last_change_tick
和get_last_change_tick
。此外,这些方法已分别重命名为set_last_run
和get_last_run
。SystemChangeTick::change_tick
和last_change_tick
方法。这些方法已分别重命名为this_run
和last_run
。Tick::set_changed
方法,该方法已重命名为set
。
移除 ChangeTrackers #
ChangeTrackers
已被移除。请改用 Ref<T>
查询。
在 assert_is_system
中检查冲突访问 #
函数 assert_is_system
和 assert_is_read_only_system
(位于 bevy_ecs::system
中)现在会在传递的系统具有无效的世界访问权限时引发恐慌。任何在具有无效访问权限的系统上调用此函数的测试现在都会失败。请修复系统的冲突访问权限,或者指定该测试旨在失败
- 对于常规测试(即使用
#[test]
注解的函数),请向函数添加#[should_panic]
属性。 - 对于文档测试,请在代码块的开头添加
should_panic
:```should_panic
移除 ScheduleBuildError
的基础集合错误变体 #
随着基础集的移除,ScheduleBuildError
的相关变体也被移除。如果你之前处理过任何这些变体,可以安全地移除处理它们的代码。
移除 #[system_param(ignore)]
和 #[world_query(ignore)]
#
属性 #[system_param(ignore)]
和 #[world_query(ignore)]
已被移除。如果你之前在 PhantomData
字段中使用过这两个属性,可以简单地移除该属性
#[derive(SystemParam)]
struct MyParam<'w, 's, Marker> {
...
// 0.10
#[system_param(ignore)]
_marker: PhantomData<Marker>,
// 0.11
_marker: PhantomData<Marker>,
}
#[derive(WorldQuery)]
struct MyQuery<Marker> {
...
// 0.10
#[world_query(ignore)]
_marker: PhantomData<Marker>,
// 0.11
_marker: PhantomData<Marker>,
}
如果你之前在实现 Default
的其他类型中使用过该属性,请考虑将该类型包装在 Local<>
中(这只对 SystemParam
有效)
#[derive(SystemParam)]
struct MyParam<'w, 's> {
// 0.10
#[system_param(ignore)]
value: MyDefaultType, // This will be initialized using `Default` each time `MyParam` is created.
// 0.11
value: Local<MyDefaultType>, // This will be initialized using `Default` the first time `MyParam` is created.
}
如果你正在实现这两个特性,并且需要保留旧 ignore
属性的精确行为,请考虑为使用 Default
特性的包装结构手动实现 SystemParam
或 WorldQuery
// 0.10
#[derive(WorldQuery)]
struct MyQuery {
#[world_query(ignore)]
str: String,
}
// 0.11
#[derive(WorldQuery)]
struct MyQuery {
str: DefaultQuery<String>,
}
pub struct DefaultQuery<T: Default>(pub T);
unsafe impl<T: Default> WorldQuery for DefaultQuery<T> {
type Item<'w> = Self;
...
unsafe fn fetch<'w>(...) -> Self::Item<'w> {
Self(T::default())
}
}
用安全代码替换一些不安全的系统执行器代码 #
函数 bevy_utils::SyncUnsafeCell::get_mut
现在返回类型为 &mut SyncUnsafeCell<T>
的值。以前,这返回了一个不可变引用。
使用 UnsafeWorldCell
来提高 SystemParam
的代码质量 #
对于 SystemParam
的手动实现者:函数 get_item
现在接受 UnsafeWorldCell
而不是 &World
。要访问世界数据,请使用
.get_entity()
,它返回一个UnsafeEntityCell
,可用于访问组件数据。get_resource()
及其变体,用于访问资源数据。
更新 increment_change_tick
以返回强类型 Tick
#
函数 UnsafeWorldCell::increment_change_tick
现在是强类型的,返回类型为 Tick
的值,而不是原始 u32
。
将状态设为私有,只能通过 State 资源的获取器访问 #
使用 State::get
而不是直接访问元组字段。
仅在 next_state != old_state
时触发状态转换 #
状态转换现在仅在退出和进入的状态不同时触发。这意味着如果世界当前处于状态 A
,如果排队进行到同一状态 A
的状态转换,则 OnEnter(A)
调度(或 OnExit
)将不再运行。
简化系统管道并使其更灵活 #
IntoPipeSystem
特性已被移除,pipe
方法已移至 IntoSystem
特性。
// 0.10
use bevy_ecs::system::IntoPipeSystem;
schedule.add_systems(first.pipe(second));
// 0.11
use bevy_ecs::system::IntoSystem;
schedule.add_systems(first.pipe(second));
简化世界调度方法 #
方法 World::run_schedule_ref
已弃用,将在下一个版本的 Bevy 中删除。请改用 run_schedule
。
重命名 UnsafeWorldCell::read_change_tick
#
UnsafeWorldCell
方法 read_change_tick
已重命名为 change_tick
。
使用 UnsafeWorldCell
提高多线程执行器的安全性 #
System
特性现在使用 UnsafeWorldCell
而不是 &World
。这种类型为内部可变世界访问提供了一个强大的 API。
- 方法
run_unsafe
使用这种类型来管理跨多个线程的世界变异。 - 方法
update_archetype_component_access
使用这种类型来确保只能使用世界元数据。
let mut system = IntoSystem::into_system(my_system);
system.initialize(&mut world);
// 0.10
system.update_archetype_component_access(&world);
unsafe { system.run_unsafe(&world) }
// 0.11
system.update_archetype_component_access(world.as_unsafe_world_cell_readonly());
unsafe { system.run_unsafe(world.as_unsafe_world_cell()) }
改进命令的封装并添加文档 #
Command
类型 Remove
和 RemoveResource
不再可以手动构造。
// 0.10
commands.add(Remove::<T> {
entity: id,
phantom: PhantomData,
});
// 0.11
commands.add(Remove::<T>::new(id));
// 0.10
commands.add(RemoveResource::<T> { phantom: PhantomData });
// 0.11
commands.add(RemoveResource::<T>::new());
命令类型 GetOrSpawn
已被移除。在 bevy_ecs
之外使用此类型是不可能的。
将 apply_system_buffers 重命名为 apply_deferred #
apply_system_buffers
已重命名为apply_deferred
System
特性上的apply_system_buffers
方法已重命名为apply_deferred
- 函数
is_apply_system_buffers
已被is_apply_deferred
替换 Executor::set_apply_final_buffers
现在是Executor::set_apply_final_deferred
Schedule::apply_system_buffers
现在是Schedule::apply_deferred
将 Command 的 "write" 方法重命名为 "apply" #
Command::write
实现需要改为实现Command::apply
。这仅仅是一个名称更改,无需采取进一步的措施。EntityCommand::write
实现需要改为实现EntityCommand::apply
。这仅仅是一个名称更改,无需采取进一步的措施。
在 QueryState::par_iter
中要求只读查询 #
函数 QueryState::par_iter
现在强制所有世界访问为只读,类似于 QueryState::iter
的工作方式。以前使用此方法修改世界的任何代码都是不安全的。如果您需要修改世界,请改用 par_iter_mut
。
将引擎的其余部分迁移到 UnsafeWorldCell
#
使用 &World
修改任何世界数据现在被认为是不安全的——必须使用类型 UnsafeWorldCell
来实现内部可变性。以下方法现在接受 UnsafeWorldCell
而不是 &World
QueryState
:get_unchecked
、iter_unchecked
、iter_combinations_unchecked
、for_each_unchecked
、get_single_unchecked
、get_single_unchecked_manual
。SystemState
:get_unchecked_manual
let mut world = World::new();
let mut query = world.query::<&mut T>();
// 0.10
let t1 = query.get_unchecked(&world, entity_1);
let t2 = query.get_unchecked(&world, entity_2);
// 0.11
let world_cell = world.as_unsafe_world_cell();
let t1 = query.get_unchecked(world_cell, entity_1);
let t2 = query.get_unchecked(world_cell, entity_2);
方法 QueryState::validate_world
和 SystemState::matches_world
现在接受 WorldId
而不是 &World
// 0.10
query_state.validate_world(&world);
// 0.11
query_state.validate_world(world.id());
方法 QueryState::update_archetypes
和 SystemState::update_archetypes
现在接受 UnsafeWorldCell
而不是 &World
// 0.10
query_state.update_archetypes(&world);
// 0.11
query_state.update_archetypes(world.as_unsafe_world_cell_readonly());
简化 ComponentIdFor
类型 #
类型 ComponentIdFor<T>
现在实现了 SystemParam
而不是 FromWorld
——这意味着它应该直接用作系统的参数,而不是用在 Local
中。
// 0.10
fn my_system(component_id: Local<ComponentIdFor<MyComponent>>) {
let component_id = **component_id;
}
// 0.11
fn my_system(component_id: ComponentIdFor<MyComponent>) {
let component_id = component_id.get();
}
将 QueryParIter::for_each_unchecked
设为私有 #
方法 QueryParIter::for_each_unchecked
已被移除——请改用 for_each
或 for_each_mut
。如果您的用例无法使用这两个方法中的任何一个,那么您的代码可能是不安全的。
如果您有一个您认为是安全的 for_each_unchecked
用例,请打开一个问题。
弃用 WorldQuery::Fetch
的类型别名 #
类型别名 bevy_ecs::query::QueryFetch
和 ROQueryFetch
已被弃用。如果您需要引用 WorldQuery
结构体的提取类型,请直接引用 WorldQuery
上定义的关联类型
// 0.10
type MyFetch<'w> = QueryFetch<'w, MyQuery>;
type MyFetchReadOnly<'w> = ROQueryFetch<'w, MyQuery>;
// 0.11
type MyFetch<'w> = <MyQuery as WorldQuery>::Fetch;
type MyFetchReadOnly<'w> = <<MyQuery as WorldQuery>::ReadOnly as WorldQuery>::Fetch;
为 EntityRef 实现 WorldQuery #
EntityRef::world
已被移除,以使 EntityRef
用作查询结果时安全。如果您是通过 World::entity
或 World::get_entity
获取 EntityRef
的。在调用 World::entity
之前保存对 World
的引用的副本。
// In 0.10
let entity_ref = world.entity(id);
let world_2 = entity_ref.world();
// In 0.11
let world_2 = &world;
let entity_ref = world.entity(id);
将 AppTypeRegistry 移动到 bevy_ecs #
如果您没有使用 prelude::*
来导入 AppTypeRegistry
,则应更新您的导入
// 0.10
use bevy::app::AppTypeRegistry;
// 0.11
use bevy::ecs::reflect::AppTypeRegistry
使场景处理实体引用更健壮 #
MapEntities
实现必须从 &EntityMap
参数更改为 &mut EntityMapper
参数,并且不再可以返回 Result
。最后,它们应该从调用 EntityMap::get
切换为调用 EntityMapper::get_or_reserve
。
重命名 map_entities 和 map_specific_entities #
在 bevy_ecs
中,ReflectMapEntities::map_entities
现在需要一个额外的 entities
参数来指定它应用于哪些实体。要保留旧的行为,请使用新的 ReflectMapEntities::map_all_entities
,但请考虑将实体专门传递进来是否对您的用例更好,以避免错误。
要求所有事件都使用 #[derive(Event)]
#
为事件添加 #[derive(Event)]
宏。用作事件的第三方类型应该包装在新的类型中。
修复带框标签 #
ScheduleLabel
特性已被重构,不再依赖于特性 std::any::Any
、bevy_utils::DynEq
和 bevy_utils::DynHash
。任何手动实现都需要改用新的特性方法。
impl ScheduleLabel for MyType {
// 0.10
fn dyn_clone(&self) -> Box<dyn ScheduleLabel> { ... }
// 0.11
fn dyn_clone(&self) -> Box<dyn ScheduleLabel> { ... }
fn as_dyn_eq(&self) -> &dyn DynEq {
self
}
// No, `mut state: &mut` is not a typo.
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
self.hash(&mut state);
// Hashing the TypeId isn't strictly necessary, but it prevents collisions.
TypeId::of::<Self>().hash(&mut state);
}
}
移除 OnUpdate
系统集 #
用 run_if(in_state(xxx))
替换 OnUpdate
。
记录查询错误 #
QueryEntityError::QueryDoesNotMatch
的显示消息已从 “给定的实体没有请求的组件。” 更改为 “给定的实体的组件与查询不匹配。”。
更新 syn、encase、glam 和 hexasphere #
在为嵌套的捆绑包派生 Bundle
时使用 #[bundle]
属性现在会抛出错误。它从 0.9 版本起就不再需要了,请参阅迁移指南。
#[derive(Bundle)]
struct PlayerBundle {
#[bundle] // Remove this line
sprite_bundle: SpriteBundle,
collider: Collider,
}
重命名 LAlt
等键为 AltLeft
#
通过替换进行迁移
LAlt
→AltLeft
RAlt
→AltRight
LBracket
→BracketLeft
RBracket
→BracketRight
LControl
→ControlLeft
RControl
→ControlRight
LShift
→ShiftLeft
RShift
→ShiftRight
LWin
→SuperLeft
RWin
→SuperRight
重命名 Interaction::Clicked -> Interaction::Pressed #
重命名所有 Interaction::Clicked -> Interaction::Pressed 的实例
不要忽略 UntypedReflectDeserializerVisitor
中的额外条目 #
如果您使用多个条目(即除 "type": { /* fields */ }
之外的条目)反序列化 Box<dyn Reflect>
值,则应将其删除,否则反序列化将失败。
FromReflect
人体工程学实现 #
FromReflect
现在在 Reflect
派生宏中自动派生。同时具有这两种派生的项需要删除 FromReflect
派生项。
// 0.10
#[derive(Reflect, FromReflect)]
struct Foo;
// 0.11
#[derive(Reflect)]
struct Foo;
如果使用 FromReflect
的手动实现和 Reflect
派生,用户将需要选择退出自动实现。
// 0.10
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// 0.11
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
bevy_reflect:稳定的类型路径 v2 #
Asset
、Material
和Material2d
的实现者现在还需要派生TypePath
。Reflect
的手动实现者需要实现新的get_type_path
方法。为了在类型注册表中注册具有泛型参数的类型,即使泛型参数仅用于 `#[reflect(ignore)]` 字段,也必须实现 `TypePath`。
// 0.10 struct MyType {} #[derive(Reflect)] struct MyTypeWithGeneric<A>{ #[reflect(ignore)] _phantom: PhantomData<A> } fn main() { App::new().add_plugins(DefaultPlugins) .register_type::<MyTypeWithGeneric<MyType>>() // in 0.11 this would error .run(); } // 0.11 #[derive(TypePath)] // New. Can also just use #[derive(Reflect)] struct MyType {} #[derive(Reflect)] struct MyTypeWithGeneric<A: TypePath>{ // changed #[reflect(ignore)] _phantom: PhantomData<A> } fn main() { App::new().add_plugins(DefaultPlugins) .register_type::<MyTypeWithGeneric<MyType>>() .run(); }
如果您不拥有某个类型,则可能需要将其包装在 newtype 中,并为 newtype 手动实现 `TypePath`。
// 0.10 use other_crate::RemoteType; #[derive(Reflect, Default)] struct MyTypeWithGeneric<A>{ #[reflect(ignore)] _phantom: PhantomData<A> } fn main() { App::new().add_plugins(DefaultPlugins) .register_type::<MyTypeWithGeneric<RemoteType>>() .run(); } // 0.11 use other_crate::RemoteType; #[derive(Default)] struct MyType(RemoteType); impl TypePath for MyType { fn type_path() -> &'static str { "my_crate::my_module::MyType" } fn short_type_path() -> &'static str { "MyType" } } #[derive(Reflect, Default)] struct MyTypeWithGeneric<A: TypePath> { #[reflect(ignore)] _phantom: PhantomData<A> } fn main() { App::new().add_plugins(DefaultPlugins) .register_type::<MyTypeWithGeneric::<MyType>>() .run(); }
在 `bevy_reflect::Map` 特性中添加 `get_at_mut` #
`Map` 特性的实现者现在需要实现 `get_at_mut`。
bevy_reflect:更好的代理 #
- 动态类型不再接受字符串类型名称。相反,它们需要对 `TypeInfo` 的静态引用。
#[derive(Reflect)]
struct MyTupleStruct(f32, f32);
let mut dyn_tuple_struct = DynamicTupleStruct::default();
dyn_tuple_struct.insert(1.23_f32);
dyn_tuple_struct.insert(3.21_f32);
// 0.10
let type_name = std::any::type_name::<MyTupleStruct>();
dyn_tuple_struct.set_name(type_name);
// 0.11
let type_info = <MyTupleStruct as Typed>::type_info();
dyn_tuple_struct.set_represented_type(Some(type_info));
- `Reflect::get_type_info` 已重命名为 `Reflect::represented_type_info`,现在也返回 `Option<&'static TypeInfo>`(而不是仅 `&'static TypeInfo`)。
// 0.10
let info: &'static TypeInfo = value.get_type_info();
// 0.11
let info: &'static TypeInfo = value.represented_type_info().unwrap();
- `TypeInfo::Dynamic` 和 `DynamicInfo` 已被删除。使用 `Reflect::is_dynamic` 代替。
// 0.10
if matches!(value.get_type_info(), TypeInfo::Dynamic) {
// ...
}
// 0.11
if value.is_dynamic() {
// ...
}
从世界构造 `Box<dyn Reflect>` 用于 `ReflectComponent` #
如果您之前手动创建了 `ReflectComponentFns`,则现在需要添加一个 `from_world` 函数指针。
ReflectComponentFns {
from_world: |world| Box::new(MyComponent::from_world(world)),
// where `from_world: fn(&mut World) -> Box<dyn Reflect>`
// ...
}
向预处理着色器添加 Globals 结构体 #
现在可以在预处理着色器中访问 `Globals` 着色器结构体。如果您之前手动绑定它,您可以删除该代码并直接使用 globals。
使渲染图槽位在大多数情况下可选 #
您现在可以直接从 `RenderGraphContext` 中获取 `view_entity`。
当实现 Node 时
// 0.10
struct FooNode;
impl FooNode {
const IN_VIEW: &'static str = "view";
}
impl Node for FooNode {
fn input(&self) -> Vec<SlotInfo> {
vec![SlotInfo::new(Self::IN_VIEW, SlotType::Entity)]
}
fn run(
&self,
graph: &mut RenderGraphContext,
// ...
) -> Result<(), NodeRunError> {
let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
// ...
Ok(())
}
}
// 0.11
struct FooNode;
impl Node for FooNode {
fn run(
&self,
graph: &mut RenderGraphContext,
// ...
) -> Result<(), NodeRunError> {
let view_entity = graph.view_entity();
// ...
Ok(())
}
}
将节点添加到图时,您不需要为 `view_entity` 指定 `slot_edge`。
// 0.10
let mut graph = RenderGraph::default();
graph.add_node(FooNode::NAME, node);
let input_node_id = draw_2d_graph.set_input(vec![SlotInfo::new(
graph::input::VIEW_ENTITY,
SlotType::Entity,
)]);
graph.add_slot_edge(
input_node_id,
graph::input::VIEW_ENTITY,
FooNode::NAME,
FooNode::IN_VIEW,
);
// add_node_edge ...
// 0.11
let mut graph = RenderGraph::default();
graph.add_node(FooNode::NAME, node);
// add_node_edge ...
从 DynamicUniformBuffer 和 DynamicStorageBuffer 中移除不必要的 values Vec #
由于内部更改导致计算变得非平凡,因此已删除 `len()` 访问器。如果您正在使用它并且没有解决方法,请创建问题。
将 (Vec2, Vec2) 更改为 Camera::logical_viewport_rect 中的 Rect #
// 0.10
fn view_logical_camera_rect(camera_query: Query<&Camera>) {
let camera = camera_query.single();
let Some((min, max)) = camera.logical_viewport_rect() else { return };
dbg!(min, max);
}
// 0.11
fn view_logical_camera_rect(camera_query: Query<&Camera>) {
let camera = camera_query.single();
let Some(Rect { min, max }) = camera.logical_viewport_rect() else { return };
dbg!(min, max);
}
使 glsl 和 spirv 支持可选 #
- 如果您想在 `spirv` 中使用着色器,请启用 `shader_format_spirv` 特性。
- 如果您想在 `glsl` 中使用着色器,请启用 `shader_format_glsl` 特性。
更改默认色调映射方法 #
默认色调映射器已从 ReinhardLuminance 更改为 TonyMcMapface。在您的相机上显式设置 ReinhardLuminance 以恢复之前的外观。
TonyMcMapface 需要 `ktx2`、`tonemapping_luts` 和 `zstd` 特性,这些特性在默认情况下是启用的。如果您禁用了默认特性并注意到场景为粉色,则可以添加 `ktx2`、`tonemapping_luts` 和 `zstd` 特性,或者使用其他色调映射器。
在不需要查找表 (LUT) 的色调映射器中,SomewhatBoringDisplayTransform 最接近 TonyMcMapface。基于 LUT 的色调映射器更可取,因为它们通常更快。
应用代码库更改以准备 `StandardMaterial` 传输 #
- `ViewTarget::main_texture()` 和 `ViewTarget::main_texture_other()` 现在返回 `&Texture` 而不是 `&TextureView`。如果您依赖这些方法,请将您的使用替换为 `ViewTarget::main_texture_view()` 和 `ViewTarget::main_texture_other_view()`;
- `ViewTarget::sampled_main_texture()` 现在返回 `Option<&Texture>` 而不是 `Option<&TextureView>`。如果您依赖此方法,请将您的使用替换为 `ViewTarget::sampled_main_texture_view()`;
- `apply_fog()`、`linear_fog()`、`exponential_fog()`、`exponential_squared_fog()` 和 `atmospheric_fog()` 函数现在接受可配置的 `Fog` 结构体。如果您依赖它们,请通过将全局 `fog` 统一变量作为它们的第一个参数来更新您的使用;
删除 `AlphaMode` 的 `Component` 派生 #
`AlphaMode` 不再是组件。
它在引擎中没有任何地方使用。如果您将其用作自己的目的的组件,则应使用 newtype,如下所示
#[derive(Component, Deref)]
struct MyAlphaMode(AlphaMode);
然后用 `MyAlphaMode` 替换 `AlphaMode` 的使用。
- Query<&AlphaMode, …>,
+ Query<&MyAlphaMode, …>,
将 `Plane` 结构体重命名为 `HalfSpace` #
- 将 `render::primitives::Plane` 的实例更改为 `render::primitives::HalfSpace`
- 将 `render::primitives::Frustum` 中 `planes` 成员的实例更改为 `half_spaces`
修复 `Plane` UV / 纹理翻转 #
翻转您在 `Plane` 形状上使用的纹理。
添加 `RenderTarget::TextureView` #
对 `RenderTarget` 枚举的引用将需要处理附加字段,例如在 `match` 语句中。
一致的屏幕空间坐标 #
`Window::cursor_position` 现在返回相对于左上角的游标位置,而不是相对于左下角。这现在与其他屏幕空间坐标相匹配,例如 `RelativeCursorPosition`、UI 和视口。
`Camera` 上的 `world_to_viewport`、`viewport_to_world` 和 `viewport_to_world_2d` 方法现在返回/接受相对于左上角的视口位置,而不是相对于左下角。
如果您使用 `world_to_viewport` 来定位 UI 节点,则返回的 `y` 值现在应该传递给 `Style` 上的 `top` 字段,而不是 `bottom` 字段。请注意,这可能会移动 UI 节点的位置,因为它现在锚定在顶部。
如果您将 `Window::cursor_position` 传递给 `viewport_to_world` 或 `viewport_to_world_2d`,则无需更改。
Webgpu 支持 #
- `Plugin::setup` 已重命名为 `Plugin::cleanup`
- 已添加 `Plugin::finish`,添加管道的插件应在此函数中执行,而不是在 `Plugin::build` 中执行。
// 0.10
impl Plugin for MyPlugin {
fn build(&self, app: &mut App) {
app.insert_resource::<MyResource>
.add_systems(Update, my_system);
let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Err(_) => return,
};
render_app
.init_resource::<RenderResourceNeedingDevice>()
.init_resource::<OtherRenderResource>();
}
}
// 0.11
impl Plugin for MyPlugin {
fn build(&self, app: &mut App) {
app.insert_resource::<MyResource>
.add_systems(Update, my_system);
let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Err(_) => return,
};
render_app
.init_resource::<OtherRenderResource>();
}
fn finish(&self, app: &mut App) {
let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Err(_) => return,
};
render_app
.init_resource::<RenderResourceNeedingDevice>();
}
}
在 CI 中拍摄示例屏幕截图 #
`TimeUpdateStrategy::ManualDuration` 的含义已更改。它不再将时间设置为 `Instant::now()` 加上给定的持续时间,而是将时间设置为上次更新加上给定的持续时间。
计算 `GpuMesh` 上索引网格的 `vertex_count` #
`vertex_count` 现在直接存储在 `GpuMesh` 上,而不是 `GpuBufferInfo::NonIndexed` 上。
内置天空盒 #
如果需要,翻转 `EnvironmentMapLight` 地图以匹配它们之前渲染的方式(反向)。
左手 Y 轴向上立方体贴图坐标 #
从点光源阴影立方体贴图采样时,使用(预期)光到片段方向向量,但将 z 坐标取反。以前,您会使用片段到光方向向量。
为 `Sprite`、`TextureAtlasSprite` 和 `Mesh2d` 添加 `Aabb` 计算 #
- 2D 实体现在会受到视锥体剔除的影响,请检查您的 2D 相机的 z 坐标和投影 `far`,如果其中一些不再渲染。
- 特别是,具有负 z 值的 2D 实体现在被具有 `default` `Camera2dBundle` 的视锥体剔除所剔除。我们计划在版本 `0.11.1` 中为默认 2D 相机重新添加对负值的支持。
添加变形目标 #
- `MeshPipeline` 现在只有一个 `mesh_layouts` 字段,而不是单独的 `mesh_layout` 和 `skinned_mesh_layout` 字段。您应该在您的实现中处理所有可能的网格绑定组布局。
- 您还应该正确处理新的 `MORPH_TARGETS` 着色器定义和网格管道键。公开了一个新函数来简化此操作:`setup_moprh_and_skinning_defs`
- `MeshBindGroup` 现在是 `MeshBindGroups`,缓存的绑定组现在可以通过 `get` 方法访问。
bevy_scene:添加 `SceneFilter` #
`DynamicScene::from_scene` 和 `DynamicScene::from_world` 不再需要 `AppTypeRegistry` 引用。
// 0.10
let registry = world.resource::<AppTypeRegistry>();
let dynamic_scene = DynamicScene::from_world(&world, registry);
// let dynamic_scene = DynamicScene::from_scene(&scene, registry);
// 0.11
let dynamic_scene = DynamicScene::from_world(&world);
// let dynamic_scene = DynamicScene::from_scene(&scene);
已删除 `DynamicSceneBuilder::from_world_with_type_registry`。现在注册表将自动从给定的世界中获取。
// 0.10
let registry = world.resource::<AppTypeRegistry>();
let builder = DynamicSceneBuilder::from_world_with_type_registry(&world, registry);
// 0.11
let builder = DynamicSceneBuilder::from_world(&world);
在场景中(反)序列化资源 #
场景格式已更改,用户可能无法使用在此版本之前保存的场景,因为资源场景字段丢失了。
修复 look_to 变量命名 #
`Transform::look_to` 方法将 `direction.try_normalize()` 的默认值从 `Vec3::Z` 更改为 `Vec3::NEG_Z`
修复孤儿实体的转换传播 #
- 如果您调用了 `bevy_transform::systems::sync_simple_transforms` 和 `bevy_transform::systems::propagate_transforms`(bevy 没有重新导出这些),您需要考虑额外的 `RemovedComponents<Parent>` 参数。
删除 `Val::Undefined` #
- `Val::Undefined` 已被删除。Bevy UI 使用默认值的行為應保持不變。
- `UiRect` 字段的默认值已更改为 `Val::Px(0.)`。
- `Style` 的 `position` 字段已被删除。它的 `left`、`right`、`top` 和 `bottom` 字段已直接添加到 `Style` 中。
- 对于 `Style` 的 `size`、`margin`、`border` 和 `padding` 字段,`Val::Undefined` 应替换为 `Val::Px(0.)`。
- 对于 `Style` 的 `min_size`、`max_size`、`left`、`right`、`top` 和 `bottom` 字段,`Val::Undefined` 应替换为 `Val::Auto`
将拼写 linebreak_behaviour 更改为 linebreak_behavior #
更新使用 `linebreak_behaviour` 的地方为 `linebreak_behavior` 更新事件 `FileDragAndDrop::HoveredFileCancelled` 的使用位置为 `HoveredFileCanceled` 更新 `Touches.just_cancelled` 的使用位置为 `Touches.just_canceled` 事件 `TouchPhase::Cancelled` 现在称为 `TouchPhase::Canceled`
向 `bevy_ui` 添加 CSS 网格支持 #
- `UiSystem::Flex` 系统集已重命名为 `UiSystem::Layout`。
- 现在无法在常量时间内使用结构体字面量更新语法与 `Style`,因为它的一个字段实现了 `Drop`,这样做会导致“此类型的析构函数无法在常量中求值”错误(参见 此问题)。
// 0.10
pub const ABSOLUTE_STYLE: Style = Style {
position_type: PositionType::Absolute,
..Style::DEFAULT
};
// 0.11
pub const ABSOLUTE_STYLE: Style = {
let mut style = Style::DEFAULT;
style.position_type = PositionType::Absolute;
style
};
`MeasureFunc` 改进 #
`CalculatedSize` 已重命名为 `ContentSize`。
已从 `UiSurface` 中删除 `upsert_leaf` 函数,并替换为 `update_measure`,该函数更新 `MeasureFunc` 而不进行节点插入。
已从 `Measure` 特性中删除 `dyn_clone` 方法。
CalculatedSize
的新功能已被set
方法取代。ImageBundle
和TextBundle
不再实现Clone
。 您可以:- 包装您自己的 bundle 类型,并通过跳过克隆
ContentSize
字段来实现Clone
。 - 使用闭包代替
clone
// 0.10 let circle = ImageBundle { style: image_style, image: materials.circle.clone(), ..Default::default() }; commands.spawn(circle.clone()); commands.spawn(circle.clone()); commands.spawn(circle.clone()); commands.spawn(circle.clone()); // 0.11 let circle = || ImageBundle { style: image_style, image: materials.circle.clone(), ..Default::default() }; commands.spawn(circle()); commands.spawn(circle()); commands.spawn(circle()); commands.spawn(circle());
- 包装您自己的 bundle 类型,并通过跳过克隆
在将 UI 坐标从物理坐标转换为逻辑坐标时除以 UiScale
#
现在,物理 UI 坐标将被 UiScale
和窗口的缩放因子同时除以,以计算 UI 节点的逻辑大小和位置。
这确保了由 Node
和 GlobalTransform
组件保存的 UI 节点大小和位置值,与用于派生它们的样式约束一致,遵循相同的逻辑坐标系,而不受当前 scale_factor
和 UiScale
的影响。
NoWrap
Text
功能 #
bevy_text::text::BreakLineOn
现在有一个新的变体 NoWrap
,用于禁用 Text
的文本换行。 也可以使用 TextBundle
的 with_no_wrap
方法禁用文本换行。
将文本系统中的本地文本队列替换为存储在组件中的标志 #
TextBundle
现在有一个新的字段 text_flag
,类型为 TextFlags
。
按轴拆分 UI Overflow
#
Style
属性 Overflow
现在是一个结构体,具有 x
和 y
字段,允许对每个轴进行溢出控制。
使用这些辅助函数替换 Overflow
的变体。
- 用
Overflow::visible()
替换Overflow::Visible
- 用
Overflow::clip()
替换Overflow::Hidden
text_system
拆分 #
ImageBundle
现在有一个新的字段 image_size
,类型为 UiImageSize
,它包含图像 bundle 纹理的大小,并由 update_image_calculated_size_system
自动更新。
更新 ahash 和 hashbrown #
如果您之前使用过资产的哈希值或使用 Bevy 公开的固定哈希器,则需要更新哈希值。
将 bevy_ui 可访问性系统移动到 PostUpdate
#
bevy_ui
可访问性系统已移至 PostUpdate
,如果您之前是在相对于这些系统安排的,请确保现在在 PostUpdate
中进行。