- 0.13 到 0.14
- 动画
- 应用程序
- 资产
- 删除 UpdateAssets 和 AssetEvents 调度程序
- 在特征中使用 async fn 而不是 BoxedFuture
- 在 ProcessResult 中添加 Ignore 变体
- 删除 Handle<T> 的 Into<AssetId<T>>
- 在 Reader 中添加 AsyncSeek 特征以能够在资产加载器内进行查找
- 在 LoadState::Failed 中添加错误信息
- 将 AssetMetaCheck 设为 AssetPlugin 的一个字段
- 使 LoadContext 使用构建器模式
- 使用 RenderAssetUsages 在加载期间配置 gLTF 网格和材质
- 将 RenderMaterials 和类似内容合并到 RenderAssets 中,为目标类型实现 RenderAsset
- 音频
- 颜色
- 开发工具
- 诊断
- ECS
- 使用观察者泛化 ECS 反应性
- 立即在 System::run 中应用延迟系统参数
- 将 Command 和 CommandQueue 移到 bevy::ecs::world
- 使 Component::Storage 成为一个常量
- 不在 QueryState 中存储 Access<ArchetypeComponentId>
- 删除 WorldCell
- 为 QueryState::matched_tables 和 QueryState::matches_archtypes 返回迭代器而不是切片
- 从默认功能中删除系统步进
- 优化事件更新和虚拟时间
- 使 SystemParam::new_archetype 和 QueryState::new_archetype 不安全
- 更好的 SystemId 和 Entity 转换
- 使 NextState 成为一个枚举
- 将状态与核心 ECS 分开
- 限制 WorldQuery::get_state() 只能接受组件
- 将状态转换名称统一为退出和进入
- 使 apply_state_transition 私有
- 用 ReflectResource 上的 FromReflect 替换 FromWorld 要求
- 使 ReflectComponentFns 和 ReflectBundleFns 方法与 EntityMut 一起使用
- 在 ReflectBundle::insert() 中需要 TypeRegistry
- 将多线程功能重命名为 multi_threaded
- 将 intern 和 label 模块从 bevy::utils 移到 bevy::ecs
- Gizmos
- 输入
- 数学
- 将有限和无限 3D 平面分开
- 将方向类型移出 bevy::math::primitives
- 将 Direction2d/3d 重命名为 Dir2/3
- 使基点样条线包括端点
- 将 Point 替换为 VectorSpace
- Triangle2d 的 UV 映射更改
- 为 3D 包围盒和射线投射使用 Vec3A
- 将 glam 更新到 0.27
- Common MeshBuilder 特征
- 在 TorusMeshBuilder 中添加角度范围
- 在 PlaneMeshBuilder 中添加细分
- 使 Transform::rotate_axis 和 Transform::rotate_local_axis 使用 Dir3
- 在 GlobalTransform 中的局部轴方法中使用 Dir3
- 修复 FloatOrd 的 Ord 和 PartialOrd 不同
- 将 FloatOrd 移到 bevy::math
- 反射
- 渲染
- 使 BackgroundColor 和 BorderColor 的默认行为更直观
- 将 Camera3dBundle::dither 重命名为 deband_dither
- 将 affine_to_square() 重命名为 affine3_to_square()
- 将 AlphaMode 移到 bevy::render
- 在处理纹理尺寸时使用 UVec2
- 修复 CameraProjectionPlugin 在某些情况下未实现 Plugin
- 将 random1D() 替换为 rand_f() 着色器函数
- 内部化网格顶点缓冲区布局
- 使 GpuArrayBufferIndex::index 为 u32
- 允许通过 MaterialPlugin 禁用阴影
- 删除 SpritePipeline::COLORED
- 排序并分箱渲染阶段项、资源和非网格
- GPU 视锥剔除
- 删除 DeterministicRenderingConfig
- 优化 queue_material_meshes 并删除一些位操作
- 默认情况下禁用 RAY_QUERY 和 RAY_TRACING_ACCELERATION_STRUCTURE
- 将上一帧的 inverse_view 上传到 GPU
- 在 GPU 可用时生成 MeshUniforms。
- 在 StandardMaterial 中添加纹理坐标翻转
- 重命名 ShadowFilteringMethod 的 Castano13 和 Jimenez14 变体
- 分别存储 VisibleEntities 列表
- 使 Text 需要 SpriteSource
- 公开 desired_maximum_frame_latency
- 合并 VisibilitySystems frusta 变体
- 扩展颜色分级
- 将 BufferVec 重命名为 RawBufferVec
- 实现清漆
- 拆分 Node2d::MainPass
- 删除 RenderLayers 的限制
- 修复绽放所需的极高发射颜色
- 更惯用的 TextureAtlasBuilder
- 规范化矩阵命名
- 在集群上下文中将“点光源”重命名为“可集群对象”
- 使 Mesh::merge() 获取 Mesh 的引用
- 在 CameraOutputMode 中存储 ClearColorConfig 而不是 LoadOp<Color>
- wgpu 0.20
- 弃用 SpriteSheetBundle 和 AtlasImageBundle
- 将 BackgroundColor 与 UiImage 解耦
- 从 extract_default_ui_camera_view() 系统中删除通用相机
- 将 need_new_surfaces() 系统重命名为 need_surface_configuration()
- 要求窗口化后端在 WindowWrapper 中存储窗口
- 任务
- UI
- 实用程序
- 窗口化
- 无区域
迁移指南:0.13 到 0.14
动画 #
AnimationClip
现在使用 UUID,NoOpTypeIdHash
现在称为 NoOpHash
#
AnimationClip
现在使用 UUID 而不是基于 Name
组件的层次路径来引用骨骼。这有几个后果
- 一个新的组件
AnimationTarget
应该放置在你希望动画的每个骨骼上,以指定它的 UUID 和关联的AnimationPlayer
。glTF 加载器会根据需要自动创建这些组件,因此 glTF 模型的大多数用法都不需要更改。 - 在树中移动骨骼或重命名骨骼不再阻止
AnimationPlayer
影响它。 - 动态更改
AnimationPlayer
组件可能需要手动更新AnimationTarget
组件。
具有 AnimationPlayer
组件的实体现在可能拥有也具有 AnimationPlayer
组件的后代。但是,它们可能不会动画相同的骨骼。
此外,NoOpTypeIdHash
和 NoOpTypeIdHasher
已重命名为 NoOpHash
和 NoOpHasher
。
实现 AnimationGraph
以混合动画 #
AnimationPlayer
现在不能再单独播放动画:它们需要与 Handle<AnimationGraph>
配对。使用 AnimationPlayer
播放动画的代码需要先创建一个 AnimationGraph
资产,添加你想要播放的片段的节点(或片段),然后将该节点的索引提供给 AnimationPlayer
的 play
方法。
// 0.13
fn setup(mut commands: Commands, mut animations: ResMut<Assets<AnimationClip>>) {
let mut animation = AnimationClip::default();
// ...
let mut player = AnimationPlayer::default();
player.play(animations.add(animation));
commands.spawn((
player,
// ...
));
}
// 0.14
fn setup(
mut commands: Commands,
mut animations: ResMut<Assets<AnimationClip>>,
// You now need access to the `AnimationGraph` asset.
mut graphs: ResMut<Assets<AnimationGraph>>,
) {
let mut animation = AnimationClip::default();
// ...
// Create a new `AnimationGraph` and add the animation handle to it.
let (graph, animation_index) = AnimationGraph::from_clip(animations.add(animation));
let mut player = AnimationPlayer::default();
// Play the animation index, not the handle.
player.play(animation_index);
commands.spawn((
player,
// Add the new `AnimationGraph` to the assets, and spawn the entity with its handle.
graphs.add(graph),
// ...
));
}
此外,AnimationPlayer::play_with_transition()
方法已被删除,并被 AnimationTransitions
组件替换。如果你之前使用的是 AnimationPlayer::play_with_transition()
,请将你要播放的所有动画添加到 AnimationGraph
并创建一个 AnimationTransitions
组件来管理它们之间的混合。
有关此更改的更多信息,你可能感兴趣的是 RFC 51.
将颜色乘以 f32
将不再忽略 alpha 通道 #
- PR #12575
- 动画
- 颜色
- 数学
- 渲染
之前可以通过 f32
将 Color
乘以或除以,现在已删除。现在必须操作特定的颜色空间,例如 LinearRgba
。此外,这些操作过去会跳过 alpha 通道,但现在不会了。
// 0.13
let color = Color::RgbaLinear {
red: 1.0,
green: 1.0,
blue: 1.0,
alpha: 1.0,
} * 0.5;
// Alpha is preserved, ignoring the multiplier.
assert_eq!(color.a(), 1.0);
// 0.14
let color = LinearRgba {
red: 1.0,
green: 1.0,
blue: 1.0,
alpha: 1.0,
} * 0.5;
// Alpha is included in multiplication.
assert_eq!(color.alpha, 0.5);
如果你需要 alpha 通道保持不变,请考虑创建自己的辅助方法
fn legacy_div_f32(color: &mut LinearRgba, scale: f32) {
color.red /= scale;
color.green /= scale;
color.blue /= scale;
}
let mut color = LinearRgba {
red: 1.0,
green: 1.0,
blue: 1.0,
alpha: 1.0,
};
legacy_div_f32(&mut color, 2.0);
如果你不介意 alpha 发生变化,但需要它保持在 0.0 到 1.0 的范围内,请考虑将其钳位
let mut color = LinearRgba {
red: 1.0,
green: 1.0,
blue: 1.0,
alpha: 1.0,
} * 10.0;
// Force alpha to be within [0.0, 1.0].
color.alpha = color.alpha.clamp(0.0, 1.0);
请注意,在某些情况下,例如渲染精灵,alpha 会自动钳位,因此你不需要手动执行。
应用程序 #
OnEnter
状态调度程序现在在 Startup 调度程序之前运行 #
- PR #11426
- 应用程序
- ECS
在 Bevy 0.13 中,通过 [app.init_state
] 初始化的状态的 [OnEnter
] 调度程序将在 Startup
调度程序中的任何系统之后运行。这是因为 [apply_state_transitions
] 仅在 [StateTransition
] 调度程序期间运行。
这是一个微妙的错误:游戏可能处于特定状态,而没有首先进入该状态。现在,[OnEnter
] 状态转换逻辑会立即处理。有关此决定的更多上下文,请参阅 bevy#13968。
要进行迁移,请选择以下选项之一
- 将你的启动系统移到一个状态,作为你等待的状态的一个变体(例如
AppState::Setup
),然后在设置完成后从该状态过渡出来。 - 将你的启动系统移到一个状态,并将另一个状态设置为一个 子状态,该子状态依赖于启动状态的完成(例如
SetupState::SetupComplete
)。
// 0.13
#[derive(States, Default)]
enum AppState {
#[default]
InMenu,
InGame,
}
app
.init_state::<AppState>()
.add_systems(Startup, initial_setup)
.add_systems(OnEnter(AppState::InMenu), relies_on_initial_setup);
// 0.14 (Solution 1)
#[derive(States, Default)]
enum AppState {
// Make this the default instead of `InMenu`.
#[default]
Setup
InMenu,
InGame,
}
fn transition_to_in_menu(mut app_state: ResMut<NextState<AppState>>) {
app_state.set(AppState::InMenu);
}
app
.init_state::<AppState>()
.add_systems(OnEnter(AppState::Setup), initial_setup)
.add_system(Update, transition_to_in_menu.run_if(in_state(AppState::Setup)))
.add_systems(OnEnter(AppState::InMenu), relies_on_initial_setup);
// 0.14 (Solution 2)
#[derive(States, Default)]
enum SetupState {
#[default]
SettingUp,
SetupComplete,
}
#[derive(SubStates, Default)]
#[source(SetupState = SetupState::SetupComplete)]
enum AppState {
#[default]
InMenu,
InGame,
}
fn finish_setup(mut app_state: ResMut<NextState<SetupState>>) {
app_state.set(SetupState::SetupComplete);
}
app
.init_state::<SetupState>()
// Note that we don't call `init_state()` for substates!
.add_sub_state::<AppState>()
.add_systems(OnEnter(AppState::InitialSetup), initial_setup)
.add_system(Update, finish_setup.run_if(in_state(AppState::Setup)))
.add_systems(OnEnter(AppState::InMenu), relies_on_initial_setup);
将 SubApp
与 App
分开 #
- PR #9202
- 应用程序
SubApp
已从 App
中分离出来,因此与这些类型交互时涉及一些较大的更改。
构造 SubApp
#
SubApp
不再包含 App
,因此您不再能够将 App
转换为 SubApp
。此外,提取函数现在必须在构造函数之外设置。
// 0.13
#[derive(AppLabel, Clone, Copy, Hash, PartialEq, Eq, Debug)]
struct MySubApp;
let mut app = App::new();
let mut sub_app = App::empty();
sub_app.add_systems(Main, ...);
sub_app.insert_resource(...);
app.insert_sub_app(MySubApp, SubApp::new(sub_app, |main_world, sub_app| {
// Extraction function.
}));
// 0.14
#[derive(AppLabel, Clone, Copy, Hash, PartialEq, Eq, Debug)]
struct MySubApp;
let mut app = App::new();
// Use `SubApp::new()` instead of `App::new()`.
let mut sub_app = SubApp::new();
// Instead of setting the extraction function when you create the `SubApp`, you must set it
// afterwards. If you do not set an extraction function, it will do nothing.
sub_app.set_extract(|main_world, sub_world| {
// Extraction function.
});
// You can still add systems and resources like normal.
sub_app.add_systems(Main, ...);
sub_app.insert_resource(...);
app.insert_sub_app(MySubApp, sub_app);
App
的变化 #
App
不再是 Send
,但 SubApp
仍然是。
由于 App
和 SubApp
的分离,一些其他方法也发生了变化。
首先,App::world
作为属性不再可以直接访问。请改用 App::world
和 App::world_mut
获取器。
#[derive(Component)]
struct MyComponent;
// 0.13
let mut app = App::new();
println!("{:?}", app.world.id());
app.world.spawn(MyComponent);
// 0.14
let mut app = App::new();
println!("{:?}", app.world().id()); // Notice the added paranthesese.
app.world_mut().spawn(MyComponent);
其次,子应用程序的所有获取器现在返回 SubApp
而不是 App
。这包括 App::sub_app
、App::sub_app_mut
、App::get_sub_app
和 App::get_sub_app_mut
。
#[derive(AppLabel, Clone, Copy, Hash, PartialEq, Eq, Debug)]
struct MySubApp;
let mut app = App::new();
app.insert_sub_app(MySubApp, SubApp::new());
assert_eq!(app.sub_app(MySubApp).type_id(), TypeId::of::<SubApp>());
最后,App::runner
和 App::main_schedule_label
现在是私有的。您不再能够获取运行器闭包,但您可以使用 SubApp::update_schedule
获取主调度标签。
let app = App::new();
let label = app.main().update_schedule;
App
上的第三方特性 #
如果您在 App
上实现了扩展特性,请考虑也将其在 SubApp
上实现。
trait SpawnBundle {
/// Spawns a new `Bundle` into the `World`.
fn spawn_bundle<T: Bundle>(&mut self, bundle: T) -> &mut Self;
}
impl SpawnBundle for App {
fn spawn_bundle<T: Bundle>(&mut self, bundle: T) -> &mut Self {
self.world_mut().spawn(bundle);
self
}
}
/// `SubApp` has a very similar API to `App`, so the code will usually look the same.
impl SpawnBundle for SubApp {
fn spawn_bundle<T: Bundle>(&mut self, bundle: T) -> &mut Self {
self.world_mut().spawn(bundle);
self
}
}
使 AppExit
更具体地说明退出原因 #
- PR #13022
- 应用程序
AppExit
事件现在是一个枚举类型,表示代码是否成功退出。如果您要构造它,您现在必须指定 Success
或 Error
。
// 0.13
fn send_exit(mut writer: EventWriter<AppExit>) {
writer.send(AppExit);
}
// 0.14
fn send_exit(mut writer: EventWriter<AppExit>) {
writer.send(AppExit::Success);
// Or...
writer.send(AppExit::Error(NonZeroU8::new(1).unwrap()));
}
如果您在系统中订阅了此事件,请考虑使用 match
来判断它是成功还是错误。
// 0.13
fn handle_exit(mut reader: EventReader<AppExit>) {
for app_exit in reader.read() {
// Something interesting here...
}
}
// 0.14
fn handle_exit(mut reader: EventReader<AppExit>) {
for app_exit in reader.read() {
match *app_exit {
AppExit::Success => {
// Something interesting here...
},
AppExit::Error(exit_code) => panic!("App exiting with an error! (Code: {exit_code})"),
}
}
}
此外,App::run()
现在返回 AppExit
而不是单位类型 ()
。由于 AppExit
实现了 Termination
,您现在可以从主函数中返回它。
// 0.13
fn main() {
App::new().run()
}
// 0.14
fn main() -> AppExit {
App::new().run()
}
// 0.14 (alternative)
fn main() {
// If you want to ignore `AppExit`, you can add a semicolon instead. :)
App::new().run();
}
最后,如果您配置了自定义 App
运行器函数,它现在必须返回 AppExit
。
let mut app = App::new();
app.set_runner(|_app| {
// ...
// Return success by default, though you may also return an error code.
AppExit::Success
});
弃用动态插件 #
- PR #13080
- 应用程序
动态插件现在已弃用。如果可能,请从您的代码中删除所有使用它们的地方。
// 0.13
// This would be compiled into a separate dynamic library.
#[derive(DynamicPlugin)]
pub struct MyPlugin;
impl Plugin for MyPlugin {
// ...
}
// This would be compiled into the main binary.
App::new()
.load_plugin("path/to/plugin")
.run()
// 0.14
// This would now be compiled into the main binary as well.
pub struct MyPlugin;
impl Plugin for MyPlugin {
// ...
}
App::new()
.add_plugins(MyPlugin)
.run()
如果您无法做到这一点,您可以通过使用 #[allow(deprecated)]
注解所有使用来暂时静默弃用警告。请注意,当前的动态插件系统将在下一个主要 Bevy 版本中删除,因此您最终将不得不迁移。您可能对这些更安全、相关的链接感兴趣
- Bevy Assets - 脚本: Bevy 的脚本和修改库
- Bevy Assets - 开发工具: 热重载和其他开发功能
stabby
: 稳定的 Rust ABI
如果您确实无法没有动态插件,您可以从 Bevy 复制代码并将其添加到您的项目中。
将状态初始化方法移至 bevy::state
#
- PR #13637
- 应用程序
- ECS
State
已移至 bevy::state
。随之而来的是,App::init_state
已从普通方法移至扩展特性。如果您没有使用前置声明,现在可能需要导入 AppExtStates
才能使用此方法。(此特性位于 bevy_state
特性标志后面,您可能需要启用它。)
// 0.13
App::new()
.init_state::<MyState>()
.run()
// 0.14
use bevy::state::app::AppExtStates as _;
App::new()
.init_state::<MyState>()
.run()
资产 #
删除 UpdateAssets
和 AssetEvents
调度程序 #
UpdateAssets
调度程序已被删除。如果您将系统添加到此调度程序中,请将其移至 PreUpdate
上运行。(您可能需要使用 system.before(...)
和 system.after(...)
来配置排序。)
// 0.13
App::new()
.add_plugins(DefaultPlugins)
.add_systems(UpdateAssets, my_system)
.run()
// 0.14
App::new()
.add_plugins(DefaultPlugins)
.add_systems(PreUpdate, my_system)
.run()
此外,AssetEvents
已从 ScheduleLabel
更改为 First
调度程序中的 SystemSet
。
// 0.13
App::new()
.add_plugins(DefaultPlugins)
.add_systems(AssetEvents, my_system)
.run()
// 0.14
App::new()
.add_plugins(DefaultPlugins)
.add_systems(First, my_system.in_set(AssetEvents))
.run()
在特性中使用 async fn
而不是 BoxedFuture
#
在 Rust 1.75 中,async fn
已为特性稳定。一些特性已从返回 BoxedFuture
切换为 async fn
,具体来说是
AssetReader
AssetWriter
AssetLoader
AssetSaver
Process
请更新您的特性实现。
// 0.13
impl AssetLoader for MyAssetLoader {
// ...
fn load<'a>(
&'a self,
reader: &'a mut Reader,
_settings: &'a (),
_load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<Self::Asset, Self::Error>> {
// Note that you had to pin the future.
Box::pin(async move {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;
Ok(bytes)
})
}
}
// 0.14
impl AssetLoader for MyAssetLoader {
// ...
async fn load<'a>(
&'a self,
reader: &'a mut Reader<'_>,
_settings: &'a (),
_load_context: &'a mut LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
// No more need to pin the future, just write it!
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;
Ok(bytes)
}
}
由于这些特性现在使用 async
,因此它们不再是对象安全的。如果您需要接收或存储 &dyn Trait
,请改用 &dyn ErasedTrait
变体。例如
// 0.13
struct MyReader(Box<dyn AssetReader>);
// 0.14
struct MyReader(Box<dyn ErasedAssetReader>);
在 ProcessResult
中添加 Ignore
变体 #
ProcessResult
枚举类型用于资产加载,它有一个新的 Ignore
变体。您可能需要更新您的 match
语句。
删除 Handle<T>
的 Into<AssetId<T>>
#
使用 Into
从 Handle
转换为 AssetId
已被删除,因为它是一个易于出错的地方,可能会在 Handle
是强引用时删除资产。如果您需要 AssetId
,请改用 Handle::id()
。
// 0.13
let id: AssetId<T> = handle.into();
// 0.14
let id = handle.id();
在 Reader
中添加 AsyncSeek
特性以能够在资产加载器中进行查找 #
资产加载器的 Reader
类型别名现在需要新的 AsyncSeek
特性。请为必须是 Reader
的任何结构实现 AsyncSeek
,或者在不支持查找的情况下使用其他方法。
如果您遇到了问题,请在 bevy#12880 上告诉我们,帮助我们在 0.15 版本中改进设计!
在 LoadState::Failed
中添加错误信息 #
Rust 以其错误处理而自豪,Bevy 一直在稳步赶上。以前,在使用 AssetServer::load_state
(及其变体)检查资产是否已加载时,返回的错误信息只是空的 LoadState::Failed
。这对调试来说没什么用!
现在,完整的 AssetLoadError
包含在 Failed
中,以便准确地告诉您出了什么问题。您可能需要更新您的 match
和 if let
语句以处理此新值。
// 0.13
match asset_server.load_state(asset_id) {
// ...
LoadState::Failed => eprintln!("Could not load asset!"),
}
// 0.14
match asset_server.load_state(asset_id) {
// ...
LoadState::Failed(error) => eprintln!("Could not load asset! Error: {}", error),
}
此外,LoadState
中的 Copy
、PartialOrd
和 Ord
实现已被删除。您可以显式调用 .clone()
而不是复制枚举类型,您也可以手动重新实现 Ord
作为帮助器方法(如果需要)。
将 AssetMetaCheck
设为 AssetPlugin
的字段 #
AssetMetaCheck
用于配置 AssetPlugin
如何读取 .meta
文件。它以前是一个资源,但现在已更改为 AssetPlugin
中的字段。如果您使用 DefaultPlugins
,您可以使用 .set
来配置此字段。
// 0.13
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(AssetMetaCheck::Never)
.run()
// 0.14
App::new()
.add_plugins(DefaultPlugins.set(AssetPlugin {
meta_check: AssetMetaCheck::Never,
..default()
}))
.run()
使 LoadContext
使用构建器模式 #
LoadContext
用于 AssetLoader
,它已更新,因此其所有 load_*
方法都已合并到一个构建器结构体中。
// 0.13
load_context.load_direct(path);
// 0.14
load_context.loader().direct().untyped().load(path);
// 0.13
load_context.load_direct_with_reader(reader, path);
// 0.14
load_context.loader().direct().with_reader(reader).untyped().load(path);
// 0.13
load_context.load_untyped(path);
// 0.14
load_context.loader().untyped().load(path);
// 0.13
load_context.load_with_settings(path, settings);
// 0.14
load_context.loader().with_settings(settings).load(path);
使用 RenderAssetUsages
在加载过程中配置 gLTF 网格和材质 #
- PR #12302
- 资产
- 渲染
现在可以使用 GltfLoaderSettings
配置是否应在主世界、渲染世界或两者中加载网格和材质。load_meshes
字段已从 bool
更改为 RenderAssetUsages
位标志,并且添加了一个新的 load_materials
字段。
您可能需要更新所有 gLTF .meta
文件。
// 0.13
load_meshes: true
// 0.14
load_meshes: ("MAIN_WORLD | RENDER_WORLD")
如果您在加载 gLTF 文件时使用 AssetServer::load_with_settings
,您还需要更新
// 0.13
asset_server.load_with_settings("model.gltf", |s: &mut GltfLoaderSettings| {
s.load_meshes = true;
});
// 0.14
asset_server.load_with_settings("model.gltf", |s: &mut GltfLoaderSettings| {
s.load_meshes = RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD;
});
将 RenderMaterials
及类似类型合并到 RenderAssets
中,为目标类型实现 RenderAsset
#
- PR #12827
- 资产
- 渲染
RenderMaterials
、RenderMaterials2d
和 RenderUiMaterials
已被 RenderAssets
资源替换。如果您需要使用 AssetId
访问 PreparedMaterial<T>
,请改用 RenderAssets::get
。
此外,RenderAsset
特性现在应该为目标类型而不是源类型实现。如果您需要访问源类型,请使用 RenderAsset::SourceAsset
关联类型。
// 0.13
impl RenderAsset for Image {
type PreparedAsset = GpuImage;
// ...
}
// 0.14
impl RenderAsset for GpuImage {
type SourceAsset = Image;
// ...
}
音频 #
在取消生成音频实体时修复对子项的剩余引用 #
您可以使用 PlaybackMode
枚举类型配置生成的音频的行为。它的一个变体 PlaybackMode::Despawn
会在音频播放完毕时取消生成实体。
以前有一个错误,导致它只会取消生成实体,而不会取消生成其子项。此错误已修复,现在在音频播放完毕时会调用 despawn_recursive()
。
如果您依赖此行为,请考虑使用 PlaybackMode::Remove
只从实体中删除音频组件,或者使用 AudioSink::empty()
来检查是否有任何音频已播放完毕,并手动 despawn()
它。
颜色 #
彻底修改 Color
#
- PR #12163
- 颜色
- Gizmos
- 渲染
- 文本
- UI
Bevy 的颜色支持已经过重大修改,并随之而来的是新的 bevy::color
模块。系好安全带,很多东西都变了!
颜色空间表示 #
Bevy 的主要 Color
枚举类型用于在许多不同的颜色空间(例如 RGB、HSL 等)中表示颜色。以前,这些颜色空间都作为变体内联表示。
enum Color {
Rgba {
red: f32,
green: f32,
blue: f32,
alpha: f32,
},
Hsla {
hue: f32,
saturation: f32,
lightness: f32,
alpha: f32,
},
// ...
}
此方法已更改,现在每个颜色空间都有其自己的专用结构体。
struct Srgba {
red: f32,
green: f32,
blue: f32,
alpha: f32,
}
struct Hsla {
hue: f32,
saturation: f32,
lightness: f32,
alpha: f32,
}
enum Color {
Srgba(Srgba),
Hsla(Hsla),
// ...
}
这样可以更轻松地组织和管理不同的颜色空间,并且还添加了许多新的颜色空间!为了处理此更改,您可能需要更新您的 match
语句。
// 0.13
match color {
Color::Rgba { red, green, blue, alpha } => {
// Something cool here!
},
_ => {},
}
// 0.14
match color {
Color::Srgba(Srgba { red, green, blue, alpha }) => {
// Something cool here!
},
// If you explicitly match every possible color space, you may need to handle more variants.
// Color::Xyza(Xyza { x, y, z, alpha }) => {
// // Something else even cooler here!
// },
_ => {}
}
此外,您现在必须在颜色空间之间转换时使用 From
和 Into
实现,而不是像以前那样使用帮助器方法,例如 as_rgba
和 as_hsla
。
// 0.13
let color = Color::rgb(1.0, 0.0, 1.0).as_hsla();
// 0.14
let color: Hsla = Srgba::rgb(1.0, 0.0, 1.0).into();
Color
方法 #
所有与 RGB 相关的都已重命名为 sRGB。这包括 Color::Rgba
变为 Color::Srgba
,以及 Color::rgb
和 Color::rgb_u8
变为 Color::srgb
和 Color::srgb_u8
。
由于会导致静默的、相对昂贵的转换,因此已删除了访问 Color
的特定通道的方法。这包括 Color::r
、Color::set_r
、Color::with_r
,以及 g
、b
h
、s
和 l
的所有等效方法。将您的 Color
转换为所需的颜色空间,在那里执行您的操作,然后转换回来。
// 0.13
let mut color = Color::rgb(0.0, 0.0, 0.0);
color.set_b(1.0);
// 0.14
let color = Color::srgb(0.0, 0.0, 0.0);
let srgba = Srgba {
blue: 1.0,
..Srgba::from(color),
};
let color = Color::from(srgba);
Color::hex
已移至 Srgba::hex
。调用 .into()
或手动构造 Color::Srgba
变体进行转换。
Color::rgb_linear
和 Color::rgba_linear
已重命名为 Color::linear_rgb
和 Color::linear_rgba
以符合 LinearRgba
结构体的命名方案。
Color::as_linear_rgba_f32
和 Color::as_linear_rgba_u32
已被删除。请改用 LinearRgba::to_f32_array
和 LinearRgba::to_u32
,并在必要时进行转换。
已删除了将 LCH 或 HSL 颜色转换为浮点数数组或 Vec
类型的其他几个颜色转换方法。请在外部重新实现这些方法,或者如果发现它们特别有用,请打开一个 PR 重新添加它们。
Color
上的向量场算术运算(加、减、乘以 f32 和除以 f32)已被移除。请将您的颜色转换为 LinearRgba
空间并在那里显式执行运算。这在处理自发光或 HDR 颜色时尤其重要,它们的色彩通道值通常超出普通 0 到 1 范围。
Alpha #
Alpha,也称为透明度,过去用字母 a
来表示。现在在结构体和方法中用其全称来表示。
Color::set_a
、Color::with_a
和Color::a
现在分别为Color::set_alpha
、Color::with_alpha
和Color::alpha
。这些是新Alpha
特征的一部分。- 此外,
Color::is_fully_transparent
现在也属于Alpha
特征。
CSS 常量 #
各种 CSS 颜色常量不再直接存储在 Color
中。而是定义在 Srgba
颜色空间中,并通过 bevy::color::palettes
访问。在它们上调用 .into()
将它们转换为 Color
以便快速调试使用。
// 0.13
let color = Color::BLUE;
// 0.14
use bevy::color::palettes::css::BLUE;
let color = BLUE;
请注意,palettes::css
不一定与之前定义的常量一一对应,因为一些名称和颜色已经更改以符合 CSS 规范。如果您需要与之前相同的颜色,请查看下面的表格或使用来自 旧常量 的颜色值。
0.13 | 0.14 |
---|---|
CYAN | AQUA |
DARK_GRAY | Srgba::gray(0.25) |
DARK_GREEN | Srgba::rgb(0.0, 0.5, 0.0) |
GREEN | LIME |
LIME_GREEN | LIMEGREEN |
PINK | DEEP_PINK |
切换到 LinearRgba
#
WireframeMaterial
、ExtractedUiNode
、ExtractedDirectionalLight
、ExtractedPointLight
、ExtractedSpotLight
和 ExtractedSprite
现在存储 LinearRgba
而不是多态的 Color
。此外,Color
不再实现 AsBindGroup
。您应该存储 LinearRgba
以避免转换成本。
将 WGSL 数学常量和颜色运算从 bevy_pbr
移动到 bevy_render
#
用于着色器的数学常量和颜色转换函数已从 bevy_pbr::utils
移动到 bevy_render::maths
和 bevy_render::color_operations
。如果您在自己的着色器中依赖这些,请更新您的导入语句。
// 0.13
#import bevy_pbr::utils::{PI, rgb_to_hsv}
// 0.14
#import bevy_render::{maths::PI, color_operations::rgb_to_hsv}
移除旧的颜色空间工具 #
- PR #12105
- 颜色
- 渲染
SrgbColorSpace
特征、HslRepresentation
结构体和 LchRepresentation
结构体已被移除,取而代之的是特定颜色空间结构体。
对于 SrgbColorSpace
,请使用 Srgba::gamma_function()
和 Srgba::gamma_function_inverse()
。如果您使用过 SrgbColorSpace
的 u8
实现,请先将其转换为 f32
。
// 14 is random, this could be any number.
let nonlinear: u8 = 14;
// Apply gamma function, converting `u8` to `f32`.
let linear: f32 = Srgba::gamma_function(nonlinear as f32 / 255.0);
// Convert back to a `u8`.
let linear: u8 = (linear * 255.0) as u8;
请注意,这种转换可能很昂贵,尤其是在 Update
调度期间调用时。请考虑直接使用 f32
。
HslRepresentation
和 LchRepresentation
可以用 Srgba
、Hsla
和 Lcha
之间的 From
实现来代替。
// 0.13
let srgb = HslRepresentation::hsl_to_nonlinear_srgb(330.0, 0.7, 0.8);
let lch = LchRepresentation::nonlinear_srgb_to_lch([0.94, 0.66, 0.8]);
// 0.14
let srgba: Srgba = Hsla::new(330.0, 0.7, 0.8, 1.0).into();
let lcha: Lcha = Srgba::new(0.94, 0.66, 0.8, 1.0).into();
在 ColorAttachment
中使用 LinearRgba
#
- PR #12116
- 颜色
- 渲染
ColorAttachment::new()
现在为 clear_color
接受 Option<LinearRgba>
而不是 Option<Color>
。您可以使用 From<Color>
实现来转换您的颜色。
let clear_color: Option<LinearRgba> = Some(color.into());
开发工具 #
移除 close_on_esc
#
- PR #12859
- 开发工具
close_on_esc
系统已被移除,因为它过于主观且缺乏定制性。如果您使用过此系统,您可以复制其内容如下。
pub fn close_on_esc(
mut commands: Commands,
focused_windows: Query<(Entity, &Window)>,
input: Res<ButtonInput<KeyCode>>,
) {
for (window, focus) in focused_windows.iter() {
if !focus.focused {
continue;
}
if input.just_pressed(KeyCode::Escape) {
commands.entity(window).despawn();
}
}
}
您可能对使用操作系统提供的内置快捷键感兴趣,例如 Alt+F4 和 Command+Q。
诊断 #
使 sysinfo
诊断插件可选 #
bevy::diagnostic
依赖于 sysinfo
来使用 SystemInformationDiagnosticsPlugin
跟踪 CPU 和内存使用情况,但是编译和轮询系统信息可能非常慢。sysinfo
现在位于 sysinfo_plugin
特征标志之后,该标志默认情况下在 bevy
中启用,但在 bevy_diagnostic
中则不启用。
如果您直接依赖于 bevy_diagnostic
,请在 Cargo.toml
中切换标志。
[dependencies]
bevy_diagnostic = { version = "0.14", features = ["sysinfo_plugin"] }
如果您为 bevy
设置了 default-features = false
,请在 Cargo.toml
中执行相同的操作。
[dependencies]
bevy = { version = "0.14", default-features = false, features = ["sysinfo_plugin"] }
改进 tracing
层定制 #
Bevy 使用 tracing
通过 LogPlugin
处理日志记录和跨度。这可以使用 update_subscriber
字段进行定制,但它非常严格。这已经过修改,用更灵活的 custom_layer
替换了 update_subscriber
字段,它返回一个 Layer
。
// 0.13
fn update_subscriber(_app: &mut App, subscriber: BoxedSubscriber) -> BoxedSubscriber {
Box::new(subscriber.with(CustomLayer))
}
App::new()
.add_plugins(LogPlugin {
update_subscriber: Some(update_subscriber),
..default()
})
.run();
// 0.14
use bevy::log::tracing_subscriber;
fn custom_layer(_app: &mut App) -> Option<BoxedLayer> {
// You can provide a single layer:
return Some(CustomLayer.boxed());
// Or you can provide multiple layers, since `Vec<Layer>` also implements `Layer`:
Some(Box::new(vec![
tracing_subscriber::fmt::layer()
.with_file(true)
.boxed(),
CustomLayer.boxed(),
]))
}
App::new()
.add_plugins(LogPlugin {
custom_layer,
..default()
})
.run();
BoxedSubscriber
类型别名也被移除,它被 BoxedLayer
类型别名替换。
ECS #
使用观察者泛化 ECS 反应性 #
- PR #10839
- ECS
在 0.14 中,引入了 ECS 观察者:立即响应世界中事件的机制。作为此更改的一部分,Event
特征被扩展以要求 Component
。#[derive(Event)]
现在自动为带注释的类型实现 Component
,这可能会破坏也 #[derive(Component)]
的类型。
// 0.13
#[derive(Event, Component)]
struct MyEvent;
// 0.14
// `Component` is still implemented by the `Event` derive.
#[derive(Event)]
struct MyEvent;
有关更多信息,请参阅有关钩子和观察者的 发行说明。
在 System::run
中立即应用延迟的系统参数 #
- PR #11823
- ECS
System::run
的默认实现现在将始终立即运行 System::apply_deferred
。如果您在此情况下手动调用 System::apply_deferred
,您可能需要将其移除。请注意,System::run_unsafe
仍然 *不会* 调用 apply_deferred
,因为它无法保证它是安全的。
// 0.13
system.run(world);
// Sometime later:
system.apply_deferred(world);
// 0.14
system.run(world);
// `apply_deferred` no longer needs to be called!
将 Command
和 CommandQueue
移动到 bevy::ecs::world
#
- PR #12234
- ECS
Command
和 CommandQueue
已从 bevy::ecs::system
移动到 bevy::ecs::world
。如果您直接导入它们,您需要更新您的导入语句。
// 0.13
use bevy::ecs::system::{Command, CommandQueue};
// 0.14
use bevy::ecs::world::{Command, CommandQueue};
使 Component::Storage
成为一个常量 #
- PR #12311
- ECS
Component::Storage
关联类型已被关联常量 STORAGE_TYPE
替换,从而使 ComponentStorage
特征不再必要。如果您手动实现 Component
而不是使用 derive 宏,请更新您的定义。
// 0.13
impl Component for MyComponent {
type Storage = TableStorage;
}
// 0.14
impl Component for MyComponent {
const STORAGE_TYPE: StorageType = StorageType::Table;
// ...
}
之前 | 之后 |
---|---|
TableStorage | StorageType::Table |
SparseStorage | StorageType::SparseSet |
Component
现在也不再是对象安全的。如果您使用过 dyn Component
,请考虑 提交一个问题 来描述您的用例。
不要在 QueryState
中存储 Access<ArchetypeComponentId>
#
- PR #12474
- ECS
QueryState
不再存储 Access<ArchetypeComponentId>
,您现在必须将其作为参数传递给使用它的每个方法。为了解决此更改
QueryState::archetype_component_access
已被移除。您可以通过访问周围的SystemState
来解决此问题。QueryState::new_archetype
和QueryState::update_archetype_component_access
现在需要&mut Access<ArchetypeComponentId>
作为参数。
移除 WorldCell
#
- PR #12551
- ECS
WorldCell
由于其不完整性、容易产生运行时恐慌以及存在多种良好替代方案而被移除。如果您使用它来获取多个不同的资源值,请考虑改用 SystemState
,使用 SystemState::get()
方法。
如果 SystemState
不适合您的用例并且可以容忍 unsafe
,您可以使用 UnsafeWorldCell
。它更高效、功能更强大,但缺乏运行时检查。
为 QueryState::matched_tables
和 QueryState::matches_archtypes
返回迭代器而不是切片 #
- PR #12476
- ECS
QueryState::matched_tables
和 QueryState::matched_archetypes
现在返回迭代器而不是切片。如果可能,请使用来自 Iterator
特征的组合器。在最坏的情况下,您可以调用 Iterator::collect()
转换为 Vec
,然后可以将其转换为切片。
从默认特征中移除系统步进 #
- PR #12847
- ECS
系统步进功能现在默认情况下处于禁用状态。它通常不应该包含在发布的游戏中,并且会增加一小部分但可衡量的性能开销。要启用它,请将 bevy_debug_stepping
功能添加到您的 Cargo.toml
中。
[dependencies]
bevy = { version = "0.14", features = ["bevy_debug_stepping"] }
使用 Stepping
的代码仍然可以在该功能被禁用时编译,但在应用程序调用 Stepping::enable()
时会在运行时打印一条错误消息。
优化事件更新和虚拟时间 #
- PR #12936
- ECS
Events::update()
已被优化为对注册的事件数量为 O(1)
。在此过程中,一些系统和运行条件也发生了变化。
使用 EventRegistry
而不是 Events
资源将事件注册到 World
中。
// 0.13
world.insert_resource(Events::<MyEvent>::default());
// 0.14
EventRegistry::register_event::<MyEvent>(&mut world);
一些系统和运行条件也发生了变化。
event_update_system
不再使用泛型,并且现在具有不同的参数。signal_event_update_system
现在具有不同的参数。reset_event_update_signal_system
已被移除。event_update_condition
现在具有不同的参数。
虽然与事件无关,但 virtual_time_system
也发生了变化。它已从一个系统转换为一个常规函数,并且现在接受 &T
和 &mut T
而不是 Res<T>
和 ResMut<T>
。
使 SystemParam::new_archetype
和 QueryState::new_archetype
不安全 #
- PR #13044
- ECS
QueryState::new_archetype
和 SystemParam::new_archetype
现在是不安全的函数,因为它们不能确保提供的 Archetype
来自与状态初始化所在的同一个 World
。您需要将任何用法包装在 unsafe
块中,并且可能需要编写额外的断言以验证正确的用法。
更好的 SystemId
和 Entity
转换 #
- PR #13090
- ECS
如果您需要访问一次性系统的 SystemId
的底层 Entity
,请使用新的 SystemId::entity()
方法。
// 0.13
let system_id = world.register_system(my_system);
let entity = Entity::from(system_id);
// 0.14
let system_id = world.register_system(my_system);
let entity = system_id.entity();
使 NextState
成为一个枚举 #
- PR #11426
- ECS
NextState
已从单元结构体转换为枚举。如果您直接访问内部 Option
,无论是通过 NextState::0
还是匹配,您将需要更新您的代码以处理此更改。
// 0.13
let state = next_state.0.unwrap();
// 0.14
let NextState::Pending(state) = next_state else { panic!("No pending next state!") };
0.13 | 0.14 |
---|---|
NextState(Some(S)) | NextState::Pending(S) |
NextState(None) | NextState::Unchanged |
将状态与核心 ECS 分开 #
- PR #13216
- ECS
状态已移至一个独立的 crate,该 crate 受 bevy_state
特性控制。使用状态但未使用 Bevy 的 default-features
的项目需要将此特性添加到其 Cargo.toml
中。
直接使用 bevy_ecs
并使用状态的项目需要添加 bevy_state
**crate** 作为依赖项。
直接使用 bevy_app
并使用状态的项目需要添加 bevy_state
**特性**。
如果您不使用 DefaultPlugins
,您将需要手动将 StatesPlugin
添加到您的应用程序中。
用户应更新引用旧位置的导入。
// 0.13
use bevy::ecs::schedule::{NextState, OnEnter, OnExit, OnTransition, State, States};
use bevy::ecs::schedule::common_conditions::in_state;
// 0.14
use bevy::state::state::{NextState, OnEnter, OnExit, OnTransition, State, States}
use bevy::state::condition::in_state;
将 WorldQuery::get_state()
限制为仅接受 Components
#
- PR #13343
- ECS
WorldQuery
和 QueryState
的一些方法是不安全的,因为它们传递了一个 &World
。现在它们被限制为只接受 &Components
。受影响的方法是
WorldQuery::get_state()
QueryState::transmute()
QueryState::transmute_filtered()
QueryState::join()
QueryState::join_filtered()
要从 World
中访问 Components
,请调用 World::components()
。
如果您手动实现了 WorldQuery
,则需要更新 get_state()
以仅使用 Components
提供的信息。
将状态转换名称统一为 exited
和 entered
#
- PR #13594
- ECS
StateTransitionEvent
的 before
和 after
字段已重命名为 exited
和 entered
以保持一致性。如果您访问这些字段或构造 StateTransitionEvent
,则需要更新您的使用方式。
使 apply_state_transition
变为私有 #
- PR #13626
- ECS
apply_state_transition
系统不再公开。迁移依赖它的系统的最简单方法是创建一个自定义调度。
// 0.13
App::new()
.add_plugins(DefaultPlugins)
.add_systems(StateTransition, my_system.after(apply_state_transition))
.run()
// 0.14
#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone)]
struct AfterStateTransition;
let mut app = App::new();
app.add_plugins(DefaultPlugins)
.add_systems(AfterStateTransition, my_system);
// Create a new schedule and add it to the app.
let after_state_transition = Schedule::new(AfterStateTransition);
app.add_schedule(after_state_transition);
// Modify the schedule order to make this run after `StateTransition`.
app.world_mut()
.resource_mut::<MainScheduleOrder>()
.insert_after(StateTransition, AfterStateTransition);
app.run()
用 ReflectResource
上的 FromReflect
替换 FromWorld
要求 #
- PR #12136
- ECS
- 反射
#[reflect(Resource)]
现在要求为您的资源实现 FromReflect
特性。如果您使用 #[derive(Reflect)]
,则默认情况下会执行此操作,但是您选择退出此行为的结构体将需要编写自己的实现。FromReflect
已被添加来替换 FromWorld
要求,尽管 FromReflect
是可失败的。您可能希望将 #[reflect(FromWorld)]
添加到您的资源中以维护一个不可失败的变体。
最后,如果您使用 ReflectResource
结构体,则需要将 &TypeRegistry
传递给其 insert
、apply_or_insert
和 copy
方法。
使 ReflectComponentFns
和 ReflectBundleFns
方法与 EntityMut
协同工作 #
- PR #12895
- ECS
- 反射
ReflectComponentFns
和 ReflectBundleFns
已更新为与 EntityMut
协同工作,与更严格的 EntityWorldMut
相比。您将需要更新您对 ReflectComponentFns::apply
、ReflectComponentFns::reflect_mut
和 ReflectBundleFns::apply
的使用。
如果您只使用 ReflectComponent
和 ReflectBundle
,则不需要更改代码,因为 EntityWorldMut
实现了 Into<EntityMut>
。
在 ReflectBundle::insert()
中要求 TypeRegistry
#
- PR #12499
- ECS
- 反射
ReflectBundle::insert
现在需要一个额外的 &TypeRegistry
参数。
将 multi-threaded
特性重命名为 multi_threaded
#
- PR #12997
- ECS
- 任务
multi-threaded
特性已为 bevy
、bevy_asset
、bevy_ecs
、bevy_render
、bevy_tasks
和 bevy_internal
重命名为 multi_threaded
。如果您手动指定 Bevy 特性,请更新您的 Cargo.toml
。
将 intern
和 label
模块从 bevy::utils
移至 bevy::ecs
#
- PR #12772
- ECS
- 实用程序
bevy::utils::label
和 bevy::utils::intern
模块已移至 bevy::ecs
,以及 bevy::utils::define_label
宏,作为缩减 bevy::utils
的一项积极努力的一部分。您将需要更新您的导入语句以使用新的路径。
Gizmos #
Gizmo 线连接 #
- PR #12252
- Gizmos
已为 gizmos 添加了线连接,允许在直线之间创建圆角或尖角。如果您手动创建了自己的 GizmoConfig
,则需要使用 line_joins
字段指定线连接的类型。
GizmoLineJoint
的 Default
实现为 None
,但您可能对 Miter
(尖角)或 Round
(圆角)感兴趣。
Gizmo 线样式 #
- PR #12394
- Gizmos
现在可以使用 GizmoConfig::line_style
配置 gizmos 的线样式(例如实线或点线)。如果您手动创建一个 GizmoConfig
,则需要指定此字段。
将 segments()
方法重命名为 resolution()
#
- PR #13438
- Gizmos
所有名为 segments()
的 gizmo 方法已重命名为 resolution()
,以与 bevy::render
保持一致。
使 gizmos 以引用方式获取基元 #
- PR #13534
- Gizmos
Gizmos::primitive_2d()
和 Gizmos::primitive_3d()
现在以引用方式获取基元,这样非 Copy
基元就不需要在每次绘制时进行克隆。
// 0.13
fn draw(mut gizmos: Gizmos) {
let polygon = Polygon {
vertices: [
// ...
],
};
// Since `Polygon` is not `Copy`, you would need to clone it if you use it more than once.
gizmos.primitive_2d(polygon.clone(), Vec2::ZERO, 0.0, Color::WHITE);
gizmos.primitive_2d(polygon, Vec2::ONE, 0.0, Color::BLACK);
}
// 0.14
fn draw(mut gizmos: Gizmos) {
let polygon = Polygon {
vertices: [
// ...
],
};
// No need to clone the polygon anymore!
gizmos.primitive_2d(&polygon, Vec2::ZERO, 0.0, Color::WHITE);
gizmos.primitive_2d(&polygon, Vec2::ONE, 0.0, Color::BLACK);
}
更多 gizmos 生成器 #
- PR #13261
- Gizmos
Gizmos::primitive_2d(CIRLCE)
、Gizmos::primitive_2d(ELLIPSE)
、Gizmos::primitive_2d(ANNULUS)
和 Gizmos::primitive_3d(SPHERE)
现在返回其相应的生成器,而不是单元类型 ()
。此外,SphereBuilder::circle_segments()
已重命名为 resolution()
。
上下文清除 gizmos #
- PR #10973
- Gizmos
App::insert_gizmo_group()
函数现在名为 App::insert_gizmo_config()
。
输入 #
将触控板输入重命名为手势 #
在最近的 winit
更新中,触控板事件现在可以在移动设备上触发。为了解决这个问题,与触控板相关的项目已重命名为手势
bevy::input::touchpad
已重命名为bevy::input::gestures
。TouchpadMagnify
已重命名为PinchGesture
。TouchpadRotate
已重命名为RotationGesture
。
弃用 ReceivedCharacter
#
- PR #12868
- 输入
- 窗口化
ReceivedCharacter
现在已弃用,因为 winit
重构了其键盘系统,请改为使用 KeyboardInput
。
// 0.13
fn listen_characters(events: EventReader<ReceivedCharacter>) {
for event in events.read() {
info!("{}", event.char);
}
}
// 0.14
fn listen_characters(events: EventReader<KeyboardInput>) {
for event in events.read() {
// Only check for characters when the key is pressed.
if !event.state.is_pressed() {
continue;
}
// Note that some keys such as `Space` and `Tab` won't be detected as a character.
// Instead, check for them as separate enum variants.
match &event.logical_key {
Key::Character(character) => {
info!("{} pressed.", character);
},
Key::Space => {
info!("Space pressed.");
},
_ => {},
}
}
}
添加 WinitEvent::KeyboardFocusLost
#
- PR #13678
- 输入
- 窗口化
WinitEvent
有一个新的枚举变体:WinitEvent::KeyboardFocusLost
。这是在修复失去 Bevy 窗口焦点时(例如使用 Alt + Tab)按键会卡住问题时添加的。请更新所有 match
语句。
数学 #
将有限和无限 3d 平面分开 #
- PR #12426
- 数学
- 渲染
Plane3d
基元现在是一个有限平面,具有 half_size
字段。如果您想要一个无限平面,请使用新的 InfinitePlane3d
。
// 0.13
let plane = Plane3d::new(Vec3::Y);
// 0.14
let plane = Plane3d {
normal: Dir3::Y,
half_size: Vec2::new(10., 10.),
};
let plane = InfinitePlane3d::new(Vec3::Y);
将方向类型从 bevy::math::primitives
中移出 #
Direction2d
、Direction3d
和 InvalidDirectionError
类型已从 bevy::math::primitives
移至 bevy::math
。
// 0.13
use bevy::math::primitives::{Direction2d, Direction3d, InvalidDirectionError};
// 0.14
use bevy::math::{Direction2d, Direction3d, InvalidDirectionError};
将 Direction2d/3d
重命名为 Dir2/3
#
Direction2d
和 Direction3d
类型已重命名为 Dir2
和 Dir3
。它们已缩短,使其更容易键入,并使其与 glam
的较短命名方案(例如 Vec2
、Mat4
)保持一致。
使基点样条曲线包含端点 #
CubicCardinalSpline
中存在一个错误,该错误导致曲线仅穿过内部控制点,而不是起点和终点处的点。(有关深入分析,请参阅 此问题。)此问题已修复,因此曲线穿过所有控制点,但它可能会破坏您依赖的行为。
如果您依赖 CubicCardinalSpline
的旧行为,则需要截断您使用的任何参数化,以便访问与您之前使用的曲线相同的曲线。这可以通过从参数化区间的每个端点裁剪一个单位距离段来完成。例如,如果您的代码如下所示
fn interpolate(t: f32) -> Vec2 {
let points = [
vec2(-1.0, -20.0),
vec2(3.0, 2.0),
vec2(5.0, 3.0),
vec2(9.0, 8.0),
];
let my_curve = CubicCardinalSpline::new(0.3, points).to_curve();
my_curve.position(t)
}
然后为了获得类似的行为,t
需要向上移动 1 个单位(因为 CubicCardinalSpline::to_curve
的输出在区间 [0,1] 中引入了一个新段),将旧段从 [0,1] 移动到 [1,2]
fn interpolate(t: f32) -> Vec2 {
let points = [
vec2(-1.0, -20.0),
vec2(3.0, 2.0),
vec2(5.0, 3.0),
vec2(9.0, 8.0),
];
let my_curve = CubicCardinalSpline::new(0.3, points).to_curve();
// Add 1 here to restore original behavior.
my_curve.position(t + 1)
}
(请注意,这不会为 t
的值提供相同的输出,这些值位于区间 [0,1] 之外。)
另一方面,任何只为了让曲线穿过正确点(即不需要完全相同的输出)而指定额外端点切线的用户,都可以简单地省略只用于控制目的的端点。
用 VectorSpace
替换 Point
#
Point
特性已被 VectorSpace
替换。这些特性非常相似,但有一些细微的改变
VectorSpace
实现现在必须提供ZERO
常量。VectorSpace
现在需要Div<f32, Output = Self>
和Neg
特性边界。VectorSpace
不再需要Add<f32, Output = Self>
、Sum
和PartialEq
特性边界。
对于大多数情况,您可以用 VectorSpace
替换所有 Point
使用情况,但如果您依赖上述列表中的任何内容,则可能需要进行进一步的更改。
Triangle2d
的 UV 映射更改 #
通过此 PR,Triangle2d
的 UV 映射已更改:主要区别在于 UV 不再依赖于三角形的绝对坐标,而是遵循三角形本身在其定义中的平移。如果您依赖于 Triangle2d
的旧 UV 坐标,那么您将需要更新受影响的区域以使用新的 UV 坐标,这些 UV 坐标可以简要描述如下
- 第一个坐标平行于三角形的前两个顶点之间的线。
- 第二个坐标与此正交,指向第三个点的方向。
一般来说,这意味着前两个点的坐标将为[_, 0.]
,而第三个点的坐标将为[_, 1.]
,其具体值取决于第三个点相对于前两个点的 位置。对于锐角三角形,前两个顶点始终具有 UV 坐标[0., 0.]
和[1., 0.]
。对于钝角三角形,第三个点将具有坐标[0., 1.]
或[1., 1.]
,其中另一个点的坐标会发生变化,以保持比例。
例如
- 默认的
Triangle2d
的 UV 坐标为[0., 0.]
、[0., 1.]
和[0.5, 1.]
。 - 顶点为
vec2(0., 0.)
、vec2(1., 0.)
和vec2(2., 1.)
的三角形具有 UV 坐标[0., 0.]
、[0.5, 0.]
和[1., 1.]
。 - 顶点为
vec2(0., 0.)
、vec2(1., 0.)
和vec2(-2., 1.)
的三角形具有 UV 坐标[2./3., 0.]
、[1., 0.]
和[0., 1.]
。
使用 Vec3A
用于 3D 包围盒和射线检测 #
Aabb3d
、BoundingSphere
和RayCast3d
现在在内部使用Vec3A
而不是Vec3
。Vec3A
是Vec3
的 SIMD 加速形式,因此它应该在不明显改变行为的情况下提高性能。
如果你手动构建任何受影响的结构,则需要将其转换为Vec3A
。
// 0.13
let x = Vec3::new(5.0, -2.0);
let aabb = Aabb3d {
min: Vec3::ZERO,
max: x,
};
// 0.14
let x = Vec3::new(5.0, -2.0);
let aabb = Aabb3d {
// Both variants are very similar, so you can usually replace `Vec3` with `Vec3A`.
min: Vec3A::ZERO,
// In cases where you cannot, use the `From` and `Into` traits.
max: x.into(),
};
将 glam
更新到 0.27 #
glam
已从 0.25 更新到 0.27。请查看变更日志了解 0.26 和 0.27,以便更新你的代码。
最大的破坏性变化是,向量类型现在以self - self.trunc()
而不是self - self.floor()
的形式评估fract()
方法。如果你需要旧行为,请使用fract_gl()
方法。
公共 MeshBuilder
特性 #
- PR #13411
- 数学
- 渲染
所有形状网格构建器(ConeMeshBuilder
、PlaneMeshBuilder
等)都具有一个方法build()
,用于将它们转换为Mesh
。此方法已成为公共特性MeshBuilder
。如果你使用build()
但未使用预置,则需要导入此特性。
向 TorusMeshBuilder
添加角度范围 #
- PR #13605
- 数学
- 渲染
TorusMeshBuilder
不再是Copy
,因为它包含用于角度范围的RangeInclusive
(x..=y
)。在以前隐式复制它的任何情况下,都需要手动调用clone()
。
向 PlaneMeshBuilder
添加细分 #
- PR #13580
- 数学
- 渲染
在 0.13 中,Plane
类型已被弃用,取而代之的是Plane2d
和Plane3d
。新的平面类型没有提供用于细分的方法,现已进行修订。
如果你使用了Plane::subdivisions
属性,现在需要将Plane3d
转换为PlaneMeshBuilder
。
// 0.13
let plane = Plane {
subdivisions: 10,
..default()
};
// 0.14
let plane = Plane3d::default().mesh().subdivisions(10);
使 Transform::rotate_axis
和 Transform::rotate_local_axis
使用 Dir3
#
- PR #12986
- 数学
- 变换
Transform::rotate_axis()
和Transform::rotate_local_axis()
现在需要Dir3
而不是Vec3
,因为轴预计是标准化的。通常,你可以使用Vec3
调用Dir3::new()
,它会自动将其标准化,但你必须处理Result
,以防向量无效。
请注意,大多数常量(如Vec3::X
)都具有相应的Dir3
变体,如Dir3::X
。
在 GlobalTransform
中使用 Dir3
用于局部轴方法 #
- PR #13264
- 数学
- 变换
GlobalTransform
组件的定向轴方法(right()
、left()
、up()
、down()
、back()
、forward()
)已从返回Vec3
更新为返回Dir3
。Dir3
实现Deref<Target = Vec>
,但如果你需要可变访问,则可以调用Vec3::from()
。
修复 FloatOrd
的 Ord
和 PartialOrd
不同 #
- PR #12711
- 数学
- 实用程序
FloatOrd
的PartialOrd
实现以前在行为上与其Ord
实现不同,但现在已修复,因此两者现在都匹配。PartialOrd
的当前实现永远不会返回None
,因为它现在回退到Ord
实现。如果你依赖于这种不匹配的行为,请考虑对内部的f32
使用PartialOrd
实现。
将 FloatOrd
移动到 bevy::math
#
- PR #12732
- 数学
- 实用程序
FloatOrd
已被移动到bevy::math
模块中。请更新你的导入语句
// 0.13
use bevy::utils::FloatOrd;
// 0.14
use bevy::math::FloatOrd;
反射 #
手动注册缺失类型 #
许多外部类型不再由 Bevy 的默认插件注册到类型注册表中。通常,只有其他 Bevy 类型使用的类型(由于新的递归注册)才会默认注册。如果你以前在std
或glam
中使用过类型进行反射功能,则可能需要手动注册它们。
App::new().register_type::<DMat3>();
更改 ReflectSerialize
特性边界 #
ReflectSerialize
现在需要TypePath
和FromReflect
特性边界,而不是Reflect
。如果你以前选择退出它们,则需要实现这些特性。例如,如果你使用了#[reflect(type_path = false)]
或#[reflect(from_reflect = false)]
,则需要删除它们。
类型的递归注册 #
- PR #5781
- 反射
现在可以递归注册类型,但在这样做时,所有(未忽略的)反射字段都需要实现GetTypeRegistration
。当Reflect
被派生时,会自动完成此操作,但手动实现还需要实现GetTypeRegistration
。
#[derive(Reflect)]
struct Foo<T: FromReflect> {
data: MyCustomType<T>
}
// 0.13
impl<T: FromReflect> Reflect for MyCustomType<T> {
// ...
}
// 0.14
impl<T: FromReflect + GetTypeRegistration> Reflect for MyCustomType<T> {
// ...
}
impl<T: FromReflect + GetTypeRegistration> GetTypeRegistration for MyCustomType<T> {
// ...
}
将 UntypedReflectDeserializer
重命名为 ReflectDeserializer
#
UntypedReflectDeserializer
已被重命名为ReflectDeserializer
。任何用法都需要相应地更新
// 0.13
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// 0.14
let reflect_deserializer = ReflectDeserializer::new(®istry);
将 Result
作为枚举实现 Reflect
#
Result
的Reflect
实现已更改为使其成为ReflectKind::Enum
而不是ReflectKind::Value
。这提高了它与Option
的一致性,并允许检查其内容。
现在,Result<T, E>
不再需要T
和E
都实现Clone
,而是需要它们实现FromReflect
。此外,<Result<T, E> as Reflect>::reflect_*
现在返回Enum
变体,而不是Value
。
使用 &TypeRegistry
序列化场景,并将 serialize_ron()
重命名为 serialize()
#
- PR #12715
- 反射
- 场景
SceneSerializer
和所有相关的序列化帮助程序现在使用&TypeRegistry
而不是&TypeRegistryArc
。你可以通过TypeRegistryArc::read()
从后者访问前者。
此外,DynamicScene::serialize_ron()
已被重命名为serialize()
。这样做是为了强调此函数不是专门用于序列化到 RON,而是用于官方的 Bevy 场景格式(.scn
/ .scn.ron
)。如果需要,这为将来更改格式留下了空间。
// 0.13
let world = World::new();
let scene = DynamicScene::from_world(&world);
let type_registry_arc: &TypeRegistryArc = &**world.resource::<AppTypeRegistry>();
let serialized_scene = scene.serialize_ron(type_registry_arc).unwrap();
// 0.14
let world = World::new();
let scene = DynamicScene::from_world(&world);
let type_registry_arc: &TypeRegistryArc = &**world.resource::<AppTypeRegistry>();
// We now need to retrieve the inner `TypeRegistry`.
let type_registry = type_registry_arc.read();
// `serialize_ron` has been renamed to `serialize`, and now takes a reference to `TypeRegistry`.
let serialized_scene = scene.serialize(&type_registry).unwrap();
渲染 #
使 BackgroundColor
和 BorderColor
的默认行为更直观 #
- PR #14017
- 渲染
- UI
BackgroundColor
不再为ImageBundle
或ButtonBundle
中的图像着色。设置UiImage::color
来为图像着色。此外,UiImage
的新默认纹理现在是一个透明的白色正方形。使用UiImage::solid_color
可以快速绘制调试图像。最后,BackgroundColor
和BorderColor
的默认值现在是透明的。将颜色手动设置为白色以恢复到以前的行为。
将 Camera3dBundle::dither
重命名为 deband_dither
#
Camera3dBundle::dither
已被重命名为deband_dither
,以使其与Camera2dBundle
保持一致。如果你构造或访问此字段,则需要更新你的使用方式。
将 affine_to_square()
重命名为 affine3_to_square()
#
affine_to_square()
**着色器** 函数已重命名为affine3_to_square
,以便为affine2_to_square
留出空间。请更新你的导入语句和使用方式。(请注意,这不是 Rust,而是 WGSL。)
// 0.13
#import bevy_render::maths::affine_to_square
// 0.14
#import bevy_render::maths::affine3_to_square
将 AlphaMode
移动到 bevy::render
#
AlphaMode
已从bevy::pbr
移动到bevy::render
。如果你直接导入它们,则需要更新你的导入语句。
// 0.13
use bevy::pbr::AlphaMode;
// 0.14
use bevy::render::alpha::AlphaMode;
在处理纹理尺寸时使用 UVec2
#
GpuImage
、TextureAtlasLayout
、TextureAtlasBuilder
、DynamicAtlasTextureBuilder
和FontAtlas
已更改为使用整数而不是浮点数存储其尺寸,以提高与底层纹理数据的 一致性。Vec2
和Rect
的实例已替换为UVec2
和URect
。
迁移此过程很棘手,因为从f32
到u32
的转换是有损的。如果你使用的是常量,你可以简单地重写代码。如果你使用的是用户输入,则可以选择简单地丢弃小数部分(1.4 as u32
)或先四舍五入(1.83.round() as u32
)。
修复 CameraProjectionPlugin
在某些情况下未实现 Plugin
#
CameraProjectionPlugin<T>
存在一个错误,如果T
未实现Component
和GetTypeRegistration
,它有时不会实现Plugin
。现在通过要求T: CameraProjection + Component + GetTypeRegistration
解决了此问题。
将 random1D()
替换为 rand_f()
着色器函数 #
bevy_pbr::utils::random1D()
**着色器** 函数已被类似的bevy_pbr::utils::rand_f()
替换。请注意,如果你将返回的f32
转换为其他数据类型,你可能对返回u32
的rand_u()
和返回vec2<f32>
的rand_vec2f()
感兴趣。
内部网格顶点缓冲区布局 #
现在将重复的 MeshVertexBufferLayout
合并为单个对象 MeshVertexBufferLayoutRef
,其中包含指向布局的原子引用计数 (Arc
) 指针。通过对这些布局进行驻留,可以缓存 PartialEq
的结果,从而加快渲染速度。使用 MeshVertexBufferLayout
的代码可能需要更新为使用 MeshVertexBufferLayoutRef
。
将 GpuArrayBufferIndex::index
设为 u32 #
GpuArrayBufferIndex::index
现在是 u32
而不是 NonMaxU32
,因为不再需要限制数字。请更新任何使用 u32
的用法。
允许通过 MaterialPlugin
禁用阴影 #
MaterialPlugin
现在有一个 shadows_enabled
属性。如果您手动构建了此插件,则可能需要设置它。默认情况下它为 true,但您可以通过将其设置为 false 来完全禁用阴影。
删除 SpritePipeline::COLORED
#
SpritePipelineKey
的 COLORED
标志已被删除,因为它不再使用。这样做,HDR
、TONEMAP_IN_SHADER
和 DEBAND_DITHER
的原始值已更改。如果您正在手动将 u32
转换为 SpritePipelineKey
,则可能需要更新它。
对渲染阶段项目、资源和非网格进行排序和分箱 #
PhaseItem
的使用已分为 BinnedPhaseItem
和 SortedPhaseItem
。如果您有自定义 PhaseItem
,则需要选择其中一种新类型。值得注意的是,某些阶段 *必须* 排序(例如 Transparent 和 Transmissive),而其他阶段可以分箱。有效地排序是“Bevy 之前的做法”,而分箱是新的,这种变化的目的是尽可能避免排序,从而提高性能。
如果您正在寻找快速迁移,请考虑选择 SortedPhaseItem
,它需要最少的代码更改。
如果您正在寻找更高的性能(并且您的阶段不需要排序),您可能想要选择 BinnedPhaseItem
。值得注意的是,箱子是根据 BinKey
填充的,同一个箱子中的所有内容都可能进行批处理。
如果您只是消费这些类型,那么对像 &mut RenderPhase<Transparent2d>
这样的类型的 Query
将成为 Resource
,例如
mut transparent_render_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>
ViewSortedRenderPhases
和 ViewBinnedRenderPhases
用于与您尝试访问的阶段项目(排序或分箱)一致。
SortedPhaseItems
的示例 SortedPhaseItems
s
- Transmissive3d
- Transparent2d
- Transparent3d
- TransparentUi
BinnedPhaseItem
的示例包括 BinnedPhaseItem
s
- Opaque3d
- Opaque3dPrepass
- Opaque3dDeferred
- AlphaMask3d
- AlphaMask3dPrepass
- AlphaMask3dDeferred
- Shadow
如果您没有网格(例如用于 GPU 驱动的粒子或过程生成),并且想要使用新的分箱行为,则 BinnedRenderPhase
包含一个 non_mesh_items
集合,该集合与 BinnedRenderPhaseType
相对应。当 添加 项目到 BinnedRenderPhase
时,将使用此类型。
您可能还希望查看新的 custom_phase_item 示例,其中详细介绍了一些新的 API。
GPU 视锥剔除 #
对于 PhaseItem
,dynamic_offset: Option<NonMaxU32>
字段现在是 extra_index: PhaseItemExtraIndex
,它包装了一个 u32
。不要使用 None
,而要使用 PhaseItemExtraIndex::NONE
。
此更改影响 AlphaMask3d
、AlphaMask3dDeferred
、AlphaMask3dPrepass
、Opaque2d
、Opaque3dDeferred
、Opaque3dPrepass
、Shadow
、Transmissive3d
、Transparent2d
、Transparent3d
和 TransparentUi
。
删除 DeterministicRenderingConfig
#
DeterministicRenderingConfig
已被删除,因为它的唯一属性 stable_sort_z_fighting
不再需要。现在不透明项目被分箱而不是排序,因此 Z 轴抖动已基本消除。
优化 queue_material_meshes
并删除一些位操作 #
GpuMesh
上的 primitive_topology
字段现在是一个 getter 方法:GpuMesh::primitive_topology()
。
出于性能原因,MeshPipelineKey
已被拆分为 BaseMeshPipelineKey
(位于 bevy::render
中)和 MeshPipelineKey
(位于 bevy::pbr
中)。这两个可以与按位或运算符组合起来生成最终的 MeshPipelineKey
。
let base_pipeline_key = BaseMeshPipelineKey::all();
let pbr_pipeline_key = MeshPipelineKey::all();
let pipeline_key: u64 = base_pipeline_key.bits() | pbr_pipeline_key.bits();
默认情况下禁用 RAY_QUERY
和 RAY_TRACING_ACCELERATION_STRUCTURE
#
RAY_QUERY
和 RAY_TRACING_ACCELERATION_STRUCTURE
wgpu
特性现在默认情况下被禁用,因为一些用户在初始化时出现程序崩溃。(此问题的 wgpu
问题可以在 此处 找到。)
如果您使用这些功能,则需要通过 WgpuSettings::features
重新启用它们。
let mut settings = WgpuSettings::default();
// Enable `RAY_QUERY` and `RAY_TRACING_ACCELERATION_STRUCTURE`, along with the defaults.
settings.features |= WgpuFeatures::RAY_QUERY | WgpuFeatures::RAY_TRACING_ACCELERATION_STRUCTURE;
App::new()
.add_plugins(DefaultPlugins.set(RenderPlugin {
render_creation: settings.into(),
..default()
}))
.run()
请注意,WgpuSettings::default()
会自动为 Bevy 配置良好的默认标志,而 WgpuFeatures::default()
等效于 WgpuFeatures::empty()
。
将前一帧的 inverse_view
上传到 GPU #
PreviousViewProjection
已重命名为 PreviousViewData
,PreviousViewProjectionUniformOffset
已重命名为 PreviousViewUniformOffset
。此外,还重命名了几个系统
update_previous_view_projections
到update_previous_view_data
extract_camera_previous_view_projection
到extract_camera_previous_view_data
prepare_previous_view_projection_uniforms
到prepare_previous_view_uniforms
在 GPU 上生成 MeshUniform
(如果可用)。 #
自定义渲染阶段现在需要多个系统,而不仅仅是 batch_and_prepare_render_phase
。以前创建自定义渲染阶段的代码现在应该根据需要添加 BinnedRenderPhasePlugin
或 SortedRenderPhasePlugin
,而不是直接添加 batch_and_prepare_render_phase
。
将纹理坐标翻转添加到 StandardMaterial
#
Quad
在 0.13 中已弃用,但它的替代品 Rectangle
没有为 Quad::flip
提供明确的替代方案。这已经得到修正:现在您可以对任何 StandardMaterial
调用 flip()
。
请注意,Quad::flip
专门是 *水平* 翻转,但 StandardMaterial::flip()
支持 *垂直* 和 *水平* 翻转。
重命名 ShadowFilteringMethod
的 Castano13
和 Jimenez14
变体 #
ShadowFilteringMethod::Castano13
和 ShadowFilteringMethod::Jimenez14
已分别重命名为 Gaussian
和 Temporal
,以便为将来扩展留出空间,但相应的作者仍在文档中被提及。
分别存储 VisibleEntities
列表 #
check_visibility()
和 VisibleEntities
现在分别存储四种类型的可渲染实体 - 2D 网格、3D 网格、灯光和 UI 元素。如果您的自定义渲染代码检查 VisibleEntities
,则现在需要使用 WithMesh2d
、WithMesh
、WithLight
和 WithNode
类型分别指定它感兴趣的实体类型。如果您的应用程序引入了新的可渲染实体类型,则需要向主世界计划中添加一个具有适当查询过滤器的 check_visibility
系统实例,以适应您的新组件或组件。例如
struct MyCustomRenderable;
App::new()
.add_plugins(DefaultPlugins)
.add_systems(
PostUpdate,
check_visibility::<With<MyCustomRenderable>>
.in_set(VisibilitySystems::CheckVisibility)
)
.run();
使 Text
需要 SpriteSource
#
Text
现在需要一个 SpriteSource
标记组件才能渲染。此组件已添加到 Text2dBundle
中,如果未使用 ..default()
,则可能需要指定它。
公开 desired_maximum_frame_latency
#
desired_maximum_frame_latency
字段已添加到 Window
和 ExtractedWindow
中。它是一个 Option<NonZero<u32>>
,它暗示了 GPU 上允许的最大排队帧数。更高的值可能会导致更流畅的帧,并避免因 CPU-GPU 数据上传而导致的冻结,但这一切都以更高的输入延迟为代价。将 desired_maximum_frame_latency
设置为 None
将使其回退到默认值,当前为 2。
合并 VisibilitySystems
的视锥变体 #
VisibilitySystems
的 UpdateOrthographicFrusta
、UpdatePerspectiveFrusta
和 UpdateProjectionFrusta
变体已被删除,取而代之的是新的 VisibilitySystems::UpdateFrusta
变体。
扩展颜色分级 #
ColorGrading
组件已扩展以支持单独配置阴影、中间调和高光部分。如果您以前配置了 gamma
或 pre_saturation
字段,则现在必须为所有部分设置它们。
// 0.13
let color_grading = ColorGrading {
gamma: 2.0,
pre_saturation: 0.8,
..default()
};
// 0.14
let mut color_grading = ColorGrading::default();
for section in color_grading.all_sections_mut() {
section.gamma = 2.0;
// `pre_saturation` has been renamed to `saturation`.
section.saturation = 0.8;
}
此外,post_saturation
和 exposure
字段已被专门移动到新的 global
字段,它是一个 ColorGradingGlobal
,支持针对整个图像执行更多操作。
// 0.13
let color_grading = ColorGrading {
post_saturation: 1.2,
exposure: 0.4,
};
// 0.14
let color_grading = ColorGrading {
global: ColorGradingGlobal {
post_saturation: 1.2,
exposure: 0.4,
..default()
},
..default()
};
将 BufferVec
重命名为 RawBufferVec
#
BufferVec
已重命名为 RawBufferVec
,因为 BufferVec
的新实现已经取了它的名字。新的 BufferVec<T>
不再需要 T: Pod
,而是来自 encase
库的 ShaderType
。
在大多数情况下,您可以简单地切换到使用 RawBufferVec
,但如果您有更复杂的数据,您可能对新的 BufferVec
实现感兴趣。
实现清漆 #
如果定义了 STANDARD_MATERIAL_CLEARCOAT
,则 pbr_lighting
WGSL 模块中的照明函数现在具有清漆参数。此外,R
反射矢量参数已从一些照明函数中删除,因为它没有被使用。
拆分 Node2d::MainPass
#
Node2d::MainPass
已被拆分为 3 个独立的阶段:StartMainPass
、MainTransparentPass
和 EndMainPass
。如果您以前使用 MainPass
对自己的自定义节点进行排序,则现在需要相对于 StartMainPass
和 EndMainPass
对其进行排序。
删除对 RenderLayers
的限制 #
现在不再限制 RenderLayers
的总数,因此与之相关的常量 TOTAL_LAYERS
和 all()
构造函数已被删除。期望在所有层上可见的实体(例如灯光)应该创建一个列出应用程序使用过的所有已知层的常量,或者在运行时计算正在使用的活动层。
RenderLayers
上不再实现 Copy
特性。相反,您应该使用 Renderlayers
仍然实现的 Clone
特性的 .clone()
函数。
修复了光晕所需的极端发射颜色 #
发射颜色和相机曝光现在可以很好地协同工作。以前,StandardMaterial
的 emissive
属性必须非常大(以千计),才能使光晕等效果可见。这已经缩小了规模,因此您可能需要重新调整您的发射颜色。
// 0.13
StandardMaterial {
emissive: Color::linear_rgb(23000.0, 9000.0, 3000.0),
..default()
}
// 0.14
StandardMaterial {
// Much more reasonable! :)
emissive: Color::linear_rgb(13.99, 5.32, 2.0),
..default()
}
您可能还会对 StandardMaterial::emissive_exposure_weight
属性感兴趣。
更具语义的 TextureAtlasBuilder
#
TextureAtlasBuilder
已被修改为更符合其他构建器的风格。作为修改的一部分,大多数方法现在返回 &mut Self
而不是 Self
,并且 finish()
已被重命名为 build()
。
// 0.13
let (texture_atlas_layout, texture) = TextureAtlasBuilder::default()
.padding(UVec2::default())
.format(TextureFormat::bevy_default())
.finish()
.unwrap();
// 0.14
let (texture_atlas_layout, texture) = TextureAtlasBuilder::default()
.padding(UVec2::default())
.format(TextureFormat::bevy_default());
.build() // This is now `build()`.
.unwrap();
矩阵命名规范化 #
所有矩阵已重命名为遵循 x_from_y
的约定,以减少混淆并提高可读性。
Frustum
的from_view_projection
、from_view_projection_custom_far
和from_view_projection_no_far
方法已重命名为from_clip_from_world
、from_clip_from_world_custom_far
和from_clip_from_world_no_far
。ComputedCameraValues::projection_matrix
已重命名为clip_from_view
。CameraProjection::get_projection_matrix
已重命名为get_clip_from_view
(这会影响Projection
、PerspectiveProjection
和OrthographicProjection
的实现)。ViewRangefinder3d::from_view_matrix
已重命名为from_world_from_view
。PreviousViewData
的成员已重命名为view_from_world
和clip_from_world
。ExtractedView
的projection
、transform
和view_projection
已重命名为clip_from_view
、world_from_view
和clip_from_world
。ViewUniform
的view_proj
、unjittered_view_proj
、inverse_view_proj
、view
、inverse_view
、projection
和inverse_projection
已重命名为clip_from_world
、unjittered_clip_from_world
、world_from_clip
、world_from_view
、view_from_world
、clip_from_view
和view_from_clip
。GpuDirectionalCascade::view_projection
已重命名为clip_from_world
。MeshTransforms
的transform
和previous_transform
已重命名为world_from_local
和previous_world_from_local
。MeshUniform
的transform
、previous_transform
、inverse_transpose_model_a
和inverse_transpose_model_b
已重命名为world_from_local
、previous_world_from_local
、local_from_world_transpose_a
和local_from_world_transpose_b
(WGSL 中的Mesh
类型反映了这一点,但transform
和previous_transform
被命名为model
和previous_model
)。Mesh2dTransforms::transform
已重命名为world_from_local
。Mesh2dUniform
的transform
、inverse_transpose_model_a
和inverse_transpose_model_b
已重命名为world_from_local
、local_from_world_transpose_a
和local_from_world_transpose_b
(WGSL 中的Mesh2d
类型反映了这一点)。- 在 WGSL 中,
bevy_pbr::mesh_functions
、get_model_matrix
和get_previous_model_matrix
已重命名为get_world_from_local
和get_previous_world_from_local
。 - 在 WGSL 中,
bevy_sprite::mesh2d_functions::get_model_matrix
已重命名为get_world_from_local
。
在聚类上下文中将 “点光源” 重命名为 “可聚类对象” #
在 PBR 着色器中,point_lights
现在被称为 clusterable_objects
,PointLight
现在被称为 ClusterableObject
,而 cluster_light_index_lists
现在被称为 clusterable_object_index_lists
。此重命名泛化了可聚类对象,这为将来添加光探针和贴花留下了空间。
使 Mesh::merge()
接受 Mesh
的引用 #
Mesh::merge()
现在接受 &Mesh
而不是 Mesh
。因此,您现在可以在多次 merge()
调用中共享相同的 Mesh
,而无需克隆它。
在 CameraOutputMode
中存储 ClearColorConfig
而不是 LoadOp<Color>
#
CameraOutputMode::Write
现在存储 ClearColorConfig
而不是 LoadOp<Color>
。请使用以下表格在两个枚举之间进行转换。
LoadOp<Color> | ClearColorConfig |
---|---|
Clear(color) | Custom(color) |
Load | None |
ClearColorConfig
还有一个额外的变体,Default
,它继承了 ClearColor
资源的清除颜色。
wgpu
0.20 #
Bevy 现在依赖于 wgpu
0.20、naga
0.20 和 naga_oil
0.14。如果您在 Cargo.toml
中手动指定了这些 crate,请确保将它们的版本更新以防止它们被重复。
此外,编码器内的 timestamps 现在在 WebGPU 上被禁止(尽管它们在原生上仍然有效)。使用 TIMESTAMP_QUERY_INSIDE_ENCODERS
功能来检查支持情况。
弃用 SpriteSheetBundle
和 AtlasImageBundle
#
- PR #12218
- 渲染
- UI
SpriteSheetBundle
已被弃用,作为向添加功能的可选组件转变的一部分,而不是大量捆绑包的激增。将 TextureAtlas
组件与 SpriteBundle
一起插入。
// 0.13
commands.spawn(SpriteSheetBundle {
texture,
atlas: TextureAtlas {
layout,
..default()
},
..default()
});
// 0.14
commands.spawn((
SpriteBundle {
texture,
..default()
},
TextureAtlas {
layout,
..default()
},
));
AtlasImageBundle
已被弃用。将 TextureAtlas
组件与 ImageBundle
一起插入。
// 0.13
commands.spawn(AtlasImageBundle {
image,
atlas: TextureAtlas {
layout,
..default()
},
..default()
});
// 0.14
commands.spawn((
ImageBundle {
image,
..default()
},
TextureAtlas {
layout,
..default()
},
));
将 BackgroundColor
与 UiImage
解耦 #
- PR #11165
- 渲染
- UI
BackgroundColor
组件现在在 UiImage
后面渲染一个纯色背景,而不是对其颜色进行着色。使用 UiImage
的 color
字段进行着色。
// 0.13
ButtonBundle {
image: UiImage::new(my_texture),
background_color: my_color_tint.into(),
..default()
}
// 0.14
ButtonBundle {
image: UiImage::new(my_texture).with_color(my_color_tint),
..default()
}
一些 UI 系统已被拆分或重命名。
bevy_ui::RenderUiSystem::ExtractNode
已被拆分为ExtractBackgrounds
、ExtractImages
、ExtractBorders
和ExtractText
。bevy_ui::extract_uinodes
已被拆分为extract_uinode_background_colors
和extract_uinode_images
。bevy_ui::extract_text_uinodes
已被重命名为extract_uinode_text
。
从 extract_default_ui_camera_view()
系统中删除通用相机 #
- PR #13462
- 渲染
- UI
bevy::ui::render::extract_default_ui_camera_view()
系统现在已硬编码为 Camera2d
和 Camera3d
组件,并且不再为每种类型添加两次。
此更改是为了修复在将渲染阶段移至资源后引入的错误。该系统所做的第一件事就是清除上一个帧中的所有实体。通过拥有两个独立的系统,一个系统总是会清除另一个系统,导致某些实体无法渲染。
将 need_new_surfaces()
系统重命名为 need_surface_configuration()
#
- PR #12055
- 渲染
- 窗口化
need_new_surfaces()
系统已重命名为 need_surface_configuration()
,作为修复 Bevy 应用程序在更改屏幕方向时会崩溃在 iOS 上的错误的一部分。
要求窗口系统在 WindowWrapper
中存储窗口 #
- PR #12978
- 渲染
- 窗口化
窗口系统现在需要将其窗口存储在新的 WindowWrapper
中,以便 Bevy 可以控制何时将其删除。这修复了许多与在管道渲染器完成绘制到窗口之前删除窗口相关的错误和崩溃。
任务 #
向并行迭代帮助器添加索引参数 #
作为参数传递给 par_chunk_map()
、par_splat_map()
、par_chunk_map_mut()
和 par_splat_map_mut()
的闭包现在将接受一个额外的索引参数,指定正在处理切片的哪一部分。
// 0.13
items.par_chunk_map(&task_pool, 100, |chunk| {
// ...
});
// 0.14
items.par_chunk_map(&task_pool, 100, |_index, chunk| {
// ...
});
UI #
修复生成 NodeBundle
会销毁之前生成的 NodeBundle
#
在 0.13.1 中,NodeBundle
会在生成时销毁之前的 NodeBundle
,原始解决方法是为所有根节点添加 position_type: Absolute
。此错误现已修复,因此您可以删除该解决方法。
将 Rect::inset()
重命名为 inflate()
#
Rect::inset()
、IRect::inset()
和 URect::inset()
已被重命名为 inflate()
以适应实际的行为。
将默认字体大小更新为 24px #
TextStyle
的默认字体大小已从 12px 增加到 24px。如果您更喜欢原始大小,可以使用 TextStyle::font_size
属性进行覆盖。
实用工具 #
将 bevy::utils
/bevy::core
的重新导出 crate 分开 #
- PR #12313
- 实用程序
bevy::utils
不再重新导出 petgraph
、uuid
、nonmax
、smallvec
或 thiserror
。此外,bevy::core
不再重新导出 bytemuck
的 bytes_of
、cast_slice
、Pod
和 Zeroable
。
如果您需要这些依赖项,可以将它们添加到您自己的 Cargo.toml
中。
窗口系统 #
重新添加 Window::fit_canvas_to_parent
#
- PR #11278
- 窗口化
Window::fit_canvas_to_parent
是 WASM 上的一个属性,它会自动将 canvas 元素的大小调整为其父级的大小,通常是屏幕。它在 0.13 中被删除,但这最终成为了问题,因为许多用户在无法自定义 CSS 时依赖于它的行为。它现在已被重新添加以满足这种需求。
关闭窗口时将其从 WinitWindows
中删除 #
- PR #12749
- 窗口化
WinitWindows::get_window_entity
现在在窗口关闭后返回 None
,而不是返回一个不再存在的实体。
使窗口在请求关闭后关闭帧 #
- PR #13236
- 窗口化
窗口现在在请求退出后关闭一帧,以修复几个回归。如果您有自定义退出逻辑,请确保它不依赖于应用程序在窗口关闭的同一帧中退出。
升级到 winit
0.30 #
- PR #13366
- 窗口化
自定义 UserEvent 现在已重命名为 WakeUp,用于在应用程序外部发生任何事情时唤醒循环(一个新的 custom_user_event 显示了此行为)。
内部 UpdateState
已被删除,并在内部被 AppLifecycle 替换。更改时,AppLifecycle 将作为事件发送。
UpdateMode
现在只接受两个值:Continuous
和 Reactive
,但后者公开了 3 个新属性以启用对设备、用户或窗口事件的响应。以前的 UpdateMode::Reactive
现在等效于 UpdateMode::reactive()
,而 UpdateMode::ReactiveLowPower
等效于 UpdateMode::reactive_low_power()
。
ApplicationLifecycle
已被重命名为 AppLifecycle
,现在包含事件循环中应用程序状态的可能值。
Idle
:循环尚未开始。Running
(以前称为Started
):循环正在运行。WillSuspend
:循环将要被挂起。Suspended
:循环被挂起。WillResume
:循环将要恢复。
注意:Resumed
状态已被删除,因为恢复的应用程序正在运行。
最后,现在 winit
启用了这一点,它扩展了 WinitPlugin
以支持自定义事件。
没有区域 #
修复 Node2d
拼写错误 #
bevy::core_pipeline::core_2d::graph
中的 Node2d::ConstrastAdaptiveSharpening
已经重命名以修复拼写错误。它最初为 Constrast
,现在已更名为 Contrast
。
// 0.13
Node2D::ConstrastAdaptiveSharpening
// 0.14
Node2D::ContrastAdaptiveSharpening
更新到 fixedbitset
0.5 #
bevy::ecs::query
中的 Access::grow
已被移除。现在许多操作会自动扩展容量。
// 0.13
let mut access = Access::new();
access.grow(1);
// Other operations...
// 0.14
let mut access = Access::new();
// Other operations...
将 WASM panic 处理程序从 LogPlugin
移动到 PanicHandlerPlugin
#
LogPlugin
以前会静默覆盖 WASM 目标上的 panic 处理程序。此功能现已拆分到新的 PanicHandlerPlugin
中,该插件已添加到 DefaultPlugins
中。
如果希望在 WASM 上获得更友好的错误消息,但没有使用 DefaultPlugins
,请确保手动将 PanicHandlerPlugin
添加到应用程序中。
App::new()
.add_plugins((MinimalPlugins, PanicHandlerPlugin))
.run()