+++ title = "0.7 to 0.8" weight = 4 sort_by = "weight" template = "book-section.html" page_template = "book-section.html" insert_anchor_links = "right" [extra] long_title = "Migration Guide: 0.7 to 0.8" +++
This is a very complicated change and it is recommended to read the linked PRs for more details
// old 3d perspective camera
commands.spawn_bundle(PerspectiveCameraBundle::default())
// new 3d perspective camera
commands.spawn_bundle(Camera3dBundle::default())
// old 2d orthographic camera
commands.spawn_bundle(OrthographicCameraBundle::new_2d())
// new 2d orthographic camera
commands.spawn_bundle(Camera2dBundle::default())
// old 3d orthographic camera
commands.spawn_bundle(OrthographicCameraBundle::new_3d())
// new 3d orthographic camera
commands.spawn_bundle(Camera3dBundle {
projection: OrthographicProjection {
scale: 3.0,
scaling_mode: ScalingMode::FixedVertical,
..default()
}.into(),
..default()
})
UI no longer requires a dedicated camera. UiCameraBundle
has been removed. Camera2dBundle
and Camera3dBundle
now both default to rendering UI as part of their own render graphs. To disable UI rendering for a camera, disable it using the UiCameraConfig
component:
commands
.spawn_bundle(Camera3dBundle::default())
.insert(UiCameraConfig {
show_ui: false,
..default()
})
// 0.7
camera.world_to_screen(transform, world_position);
// 0.8
camera.world_to_viewport(transform, world_position);
Visibility
is now propagated into children in a similar way to Transform
. Root elements of a hierarchy must now contain Visibility
and ComputedVisiblity
for visibility propagation to work.
SpatialBundle
and VisibilityBundle
have been added for convenience. If you were using a TransformBundle
you should probably be using a SpatialBundle
now.
If you were previously reading Visibility::is_visible
as the "actual visibility" for sprites or lights, use ComputedVisibilty::is_visible()
instead:
// before (0.7)
fn system(query: Query<&Visibility>) {
for visibility in query.iter() {
if visibility.is_visible {
info!("found visible entity");
}
}
}
// after (0.8)
fn system(query: Query<&ComputedVisibility>) {
for visibility in query.iter() {
if visibility.is_visible() {
info!("found visible entity");
}
}
}
GlobalTransform
fields have changed
- Replace
global_transform.translation
byglobal_transform.translation()
(For other fields, use thecompute_transform
method) GlobalTransform
do not support non-linear scales anymore, we'd like to hear from you if it is an inconvenience for you- If you need the
scale
,rotation
ortranslation
property you can now useglobal_transform.to_scale_rotation_translation()
// 0.7
let transform = Transform::from(*global_transform);
transform.scale
transform.rotation
transform.translation
// 0.8
let (scale, rotation, translation) = global_transform.to_scale_rotation_translation();
// 0.7
commands.spawn_scene(asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"));
//0.8
commands.spawn_bundle(SceneBundle {
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
..Default::default()
});
The scene will be spawned as a child of the entity with the SceneBundle
Adds ability to specify scaling factor for WindowSize
, size of the fixed axis for FixedVertical
and FixedHorizontal
and a new ScalingMode
that is a mix of FixedVertical
and FixedHorizontal
bevy::input::system::exit_on_esc_system
has been removed. Use bevy::window::close_on_esc
instead.
CloseWindow
has been removed. Use Window::close
instead.
The Close variant has been added to WindowCommand
. Handle this by closing the relevant window.
The run criterion RunOnce
, which would make the controlled systems run only once, has been replaced with a new run criterion function ShouldRun::once. Replace all instances of RunOnce with ShouldRun::once
.
For code that was using a system param's fetch struct, such as EventReader's EventReaderState, the fetch struct can now be identified via the SystemParam trait associated type Fetch, e.g. for EventReader<T>
it can be identified as <EventReader<'static, 'static, T> as SystemParam>::Fetch
If you need a Task
to be a Component
you should use a wrapper type.
// 0.7
fn system(mut commands: Commands) {
let task = thread_pool.spawn(async move {
let start_time = Instant::now();
while Instant::now() - start_time < Duration::from_secs_f32(5.0) {
// Spinning for 'duration', simulating doing hard
}
Vec2::ZERO
});
commands.spawn().insert(task);
}
// 0.8
#[derive(Component)]
struct ComputeVec2(Task<Vec2>);
fn system(mut commands: Commands) {
let task = thread_pool.spawn(async move {
let start_time = Instant::now();
while Instant::now() - start_time < Duration::from_secs_f32(5.0) {
// Spinning for 'duration', simulating doing hard
}
Vec2::ZERO
});
commands.spawn().insert(ComputeVec2(task));
}
- Time related types (e.g.
Time
,Timer
,Stopwatch
,FixedTimestep
, etc.) should be imported frombevy::time::*
rather thanbevy::core::*
. - If you were adding
CorePlugin
manually, you'll also want to addTimePlugin
frombevy::time
. - The
bevy::core::CorePlugin::Time
system label is replaced withbevy::time::TimeSystem
.
Replace imports of bevy::core::FloatOrd
with bevy::utils::FloatOrd
.
The Rect
type has been renamed to UiRect
.
The ElementState
type has been renamed to ButtonState
.
Renamed HasRawWindowHandleWrapper
to ThreadLockedRawWindowHandleWrapper
.
- removed
set_body()
,values()
,values_mut()
,clear()
,push()
,append()
- added
set()
,get()
,get_mut()
- renamed
uniform_buffer()
tobuffer()
- removed
len()
,is_empty()
,capacity()
,push()
,reserve()
,clear()
,values()
- added
set()
,get()
- renamed
uniform_buffer()
tobuffer()
- removed
capacity()
,reserve()
Timer::times_finished
has been renamed to Timer::times_finished_this_tick
for clarity.
Default Image
filtering changed from Nearest
to Linear
.
// 0.7
// Nothing, nearest was the default
// 0.8
App::new()
.insert_resource(ImageSettings::default_nearest())
You can no longer use .system()
. It was deprecated in 0.7.0. You can just remove the method call.
If you needed this for tests purposes, you can use bevy_ecs::system::assert_is_system
instead.
The Gamepad
, GamepadButton
, GamepadAxis
, GamepadEvent
and GamepadEventRaw
types are now normal structs instead of tuple structs and have a new
function.
To migrate change every instantiation to use the new()
function instead and use the appropriate field names instead of .0 and .1.
Replace calls to EntityMut::get_unchecked
with calls to EntityMut::get
.
The trait ReadOnlyFetch
has been replaced with ReadOnlyWorldQuery
along with the WorldQueryGats::ReadOnlyFetch
assoc type which has been replaced with <WorldQuery::ReadOnly as WorldQueryGats>::Fetch
The trait ReadOnlyFetch
has been replaced with ReadOnlyWorldQuery
along with the WorldQueryGats::ReadOnlyFetch
assoc type which has been replaced with <WorldQuery::ReadOnly as WorldQueryGats>::Fetch
- Any where clauses such as
QueryFetch<Q>: ReadOnlyFetch
should be replaced withQ: ReadOnlyWorldQuery
. - Any custom world query impls should implement
ReadOnlyWorldQuery
instead ofReadOnlyFetch
Functions update_component_access
and update_archetype_component_access
have been moved from the FetchState
trait to WorldQuery
- Any callers should now call
Q::update_component_access(state
instead ofstate.update_component_access
(andupdate_archetype_component_access
respectively) - Any custom world query impls should move the functions from the
FetchState
impl toWorldQuery
impl
WorldQuery
has been made an unsafe trait
, FetchState
has been made a safe trait
. (I think this is how it should have always been, but regardless this is definitely necessary now that the two functions have been moved to WorldQuery
)
- If you have a custom
FetchState
impl make it a normalimpl
instead ofunsafe impl
- If you have a custom
WorldQuery
impl make it anunsafe impl
, if your code was sound before it is going to still be sound
Query conflicts from Or
/AnyOf
/Option
have been fixed, and made stricter to avoid undefined behaviour.
If you have new query conflicts due to this you must refactor your systems; consider using ParamSet
.
The task_pool
parameter for Query(State)::par_for_each(_mut)
has been removed. Remove these parameters from all calls to these functions.
Before:
fn parallel_system(
task_pool: Res<ComputeTaskPool>,
query: Query<&MyComponent>,
) {
query.par_for_each(&task_pool, 32, |comp| {
// ...
});
}
After:
fn parallel_system(query: Query<&MyComponent>) {
query.par_for_each(32, |comp| {
// ...
});
}
If using Query
or QueryState
outside of a system run by the scheduler, you may need to manually configure and initialize a ComputeTaskPool
as a resource in the World
.
bevy_ecs
will now explicitly fail to compile on 16-bit platforms, because it is unsound on those platforms due to various internal assumptions.
There is currently no alternative, but we're open to adding support. Please file an issue (https://github.com/bevyengine/bevy/issues) to help detail your use case.
Assets::<T>::get
and Assets::<T>::get_mut
now require that the passed handles are Handle<T>
, improving the type safety of handles. If you were previously passing in:
- a
HandleId
, use&Handle::weak(id)
instead, to create a weak handle. You may have been able to store a type safeHandle
instead. - a
HandleUntyped
, use&handle_untyped.typed_weak()
to create a weak handle of the specified type. This is most likely to be the useful when using load_folder - a
Handle<U>
of of a different type, consider whether this is the correct handle type to store. If it is (i.e. the same handle id is used for multiple different Asset types) useHandle::weak(handle.id)
to cast to a different type.
SystemParamFunction
has changed. It was not previously part of the public API, so no migration instructions are provided. (It is now included in the public API, although you still should not implement this trait for your own types).
If possible, any custom System
implementations should be migrated to use higher order systems, which are significantly less error-prone.
Research is needed into allowing this to work for more cases.
Calls to TextureAtlas::from_grid_with_padding
should be modified to include a new parameter, which can be set to Vec2::ZERO
to retain old behaviour.
from_grid_with_padding(texture, tile_size, columns, rows, padding)
|
V
from_grid_with_padding(texture, tile_size, columns, rows, padding, Vec2::ZERO)
- In shaders for 3D meshes:
#import bevy_pbr::mesh_view_bind_group
->#import bevy_pbr::mesh_view_bindings
#import bevy_pbr::mesh_struct
->#import bevy_pbr::mesh_types
- NOTE: If you are using the mesh bind group at bind group index 2, you can remove those binding statements in your shader and just use
#import bevy_pbr::mesh_bindings
which itself imports the mesh types needed for the bindings.
- NOTE: If you are using the mesh bind group at bind group index 2, you can remove those binding statements in your shader and just use
- In shaders for 2D meshes:
#import bevy_sprite::mesh2d_view_bind_group
->#import bevy_sprite::mesh2d_view_bindings
#import bevy_sprite::mesh2d_struct
->#import bevy_sprite::mesh2d_types
- NOTE: If you are using the mesh2d bind group at bind group index 2, you can remove those binding statements in your shader and just use
#import bevy_sprite::mesh2d_bindings
which itself imports the mesh2d types needed for the bindings.
- NOTE: If you are using the mesh2d bind group at bind group index 2, you can remove those binding statements in your shader and just use
Camera::projection_matrix
is no longer a public field. Use the new Camera::projection_matrix()
method instead:
// 0.7
let projection = camera.projection_matrix;
// 0.8
let projection = camera.projection_matrix();
Exhaustive matches on RenderGraphRunnerError
will need to add a branch to handle the new MismatchedInputCount
variant.
- Reflect derives should not have to change anything
- Manual reflect impls will need to remove the
unsafe
keyword, addany()
implementations, and rename the oldany
andany_mut
toas_any
andas_mut_any
. - Calls to
any
/any_mut
must be changed toas_any
/as_mut_any
If you experienced any problems caused by this change, please create an issue explaining in detail what you were doing with those apis.
Thread pools don't need to be stored in a resource anymore since they are now stored globally. You can now use get()
to access it.
// 0.7
fn spawn_tasks(thread_pool: Res<AsyncComputeTaskPool>) {
// Do something with thread_pool
}
// 0.8
fn spawn_tasks() {
let thread_pool = AsyncComputeTaskPool::get();
// Do something with thread_pool
}
- Any previous use of
Box<dyn SystemLabel>
should be replaced withSystemLabelId
. AsSystemLabel
trait has been modified.- No more output generics.
- Method
as_system_label
now returnsSystemLabelId
, removing an unnecessary level of indirection.
- If you need a label that is determined at runtime, you can use
Box::leak
. Not recommended.
- added bevy_utils::get_short_name, which strips the path from a type name for convenient display.
- removed the TypeRegistry::get_short_name method. Use the function in bevy_utils instead.
This struct had no internal use, docs, or intuitable external use.
It has been removed.
Rename ReflectComponent::add_component
into ReflectComponent::insert_component
.
Updated struct_trait, tuple_struct, tuple, array, list and map to return None
when comparison couldn't be performed.
The Extract
RenderStage
now runs on the render world (instead of the main world as before).
You must use the Extract
SystemParam
to access the main world during the extract phase. Extract
takes a single type parameter, which is any system parameter (such as Res
, Query
etc.).
It will extract this from the main world.
Note that Commands
will not work correctly in Extract
- it will currently silently do nothing.
// 0.7
fn extract_clouds(mut commands: Commands, clouds: Query<Entity, With<Cloud>>) {
for cloud in clouds.iter() {
commands.get_or_spawn(cloud).insert(Cloud);
}
}
// 0.8
fn extract_clouds(mut commands: Commands, mut clouds: Extract<Query<Entity, With<Cloud>>>) {
for cloud in clouds.iter() {
commands.get_or_spawn(cloud).insert(Cloud);
}
}
You can now also access resources from the render world using the normal system parameters during Extract
:
fn extract_assets(mut render_assets: ResMut<MyAssets>, source_assets: Extract<Res<MyAssets>>) {
*render_assets = source_assets.clone();
}
Please note that all existing extract systems need to be updated to match this new style; even if they currently compile they will not run as expected. A warning will be emitted on a best-effort basis if this is not met.
D-pad inputs can no longer be accessed as axes. Access them as gamepad buttons instead.
Changed the following fields
WindowCommand::SetWindowMode.resolution
from(u32, u32)
toUVec2
WindowCommand::SetResolution.logical_resolution
from(f32, f32)
toVec2
-
Rename
FileAssetIo::get_root_path
uses toFileAssetIo::get_base_path
FileAssetIo::root_path()
is a getter for theroot_path
field, whileFileAssetIo::get_root_path
returned the parent directory of the asset root path, which was the executable's directory unlessCARGO_MANIFEST_DIR
was set. This change solves the ambiguity between the two methods.
The Parent
and Children
component fields are now private.
- Replace
parent.0
byparent.get()
- Replace
children.0
with*children
- You can't construct
Children
orParent
component anymore, you can use this as a stopgap measure, which may introduce a single frame delay
#[derive(Component)]
pub struct MakeChildOf(pub Entity);
fn add_parent(
mut commands: Commands,
orphans: Query<(Entity, &MakeChildOf)>,
) {
for (child, MakeChildOf(parent)) in &orphans {
commands.entity(*parent).add_child(child);
commands.entity(child).remove::<MakeChildOf>();
}
}
.register_type
for generic types likeOption<T>
,Vec<T>
,HashMap<K, V>
will no longer insertReflectSerialize
andReflectDeserialize
type data. Instead you need to register it separately for concrete generic types like so:
.register_type::<Option<String>>()
.register_type_data::<Option<String>, ReflectSerialize>()
.register_type_data::<Option<String>, ReflectDeserialize>()