Migrate bevy_transform
to required components (#14964)
The first step in the migration to required components! This PR removes `GlobalTransform` from all user-facing code, since it's now added automatically wherever `Transform` is used. ## Testing - None of the examples I tested were broken, and I assume breaking transforms in any way would be visible *everywhere* --- ## Changelog - Make `Transform` require `GlobalTransform` ~~- Remove `GlobalTransform` from all engine bundles~~ - Remove in-engine insertions of GlobalTransform and TransformBundle - Deprecate `TransformBundle` - update docs to reflect changes ## Migration Guide Replace all insertions of `GlobalTransform` and/or `TransformBundle` with `Transform` alone. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Tim <JustTheCoolDude@gmail.com>
This commit is contained in:
parent
a0c722ff4c
commit
b04947d44f
@ -1,3 +1,4 @@
|
|||||||
|
#![expect(deprecated)]
|
||||||
use bevy_ecs::bundle::Bundle;
|
use bevy_ecs::bundle::Bundle;
|
||||||
|
|
||||||
use crate::prelude::{GlobalTransform, Transform};
|
use crate::prelude::{GlobalTransform, Transform};
|
||||||
@ -24,6 +25,10 @@ use crate::prelude::{GlobalTransform, Transform};
|
|||||||
/// update the [`Transform`] of an entity in this schedule or after, you will notice a 1 frame lag
|
/// update the [`Transform`] of an entity in this schedule or after, you will notice a 1 frame lag
|
||||||
/// before the [`GlobalTransform`] is updated.
|
/// before the [`GlobalTransform`] is updated.
|
||||||
#[derive(Clone, Copy, Debug, Default, Bundle)]
|
#[derive(Clone, Copy, Debug, Default, Bundle)]
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.15.0",
|
||||||
|
note = "Use the `Transform` component instead. Inserting `Transform` will now also insert a `GlobalTransform` automatically."
|
||||||
|
)]
|
||||||
pub struct TransformBundle {
|
pub struct TransformBundle {
|
||||||
/// The transform of the entity.
|
/// The transform of the entity.
|
||||||
pub local: Transform,
|
pub local: Transform,
|
||||||
|
@ -17,7 +17,9 @@ use {
|
|||||||
///
|
///
|
||||||
/// * To get the global transform of an entity, you should get its [`GlobalTransform`].
|
/// * To get the global transform of an entity, you should get its [`GlobalTransform`].
|
||||||
/// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`].
|
/// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`].
|
||||||
/// * You may use the [`TransformBundle`](crate::bundles::TransformBundle) to guarantee this.
|
/// ~* You may use the [`TransformBundle`](crate::bundles::TransformBundle) to guarantee this.~
|
||||||
|
/// * [`TransformBundle`](crate::bundles::TransformBundle) is now deprecated.
|
||||||
|
/// [`GlobalTransform`] is automatically inserted whenever [`Transform`] is inserted.
|
||||||
///
|
///
|
||||||
/// ## [`Transform`] and [`GlobalTransform`]
|
/// ## [`Transform`] and [`GlobalTransform`]
|
||||||
///
|
///
|
||||||
|
@ -13,7 +13,9 @@ use {
|
|||||||
/// * To place or move an entity, you should set its [`Transform`].
|
/// * To place or move an entity, you should set its [`Transform`].
|
||||||
/// * To get the global transform of an entity, you should get its [`GlobalTransform`].
|
/// * To get the global transform of an entity, you should get its [`GlobalTransform`].
|
||||||
/// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`].
|
/// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`].
|
||||||
/// * You may use the [`TransformBundle`](crate::bundles::TransformBundle) to guarantee this.
|
/// ~* You may use the [`TransformBundle`](crate::bundles::TransformBundle) to guarantee this.~
|
||||||
|
/// * [`TransformBundle`](crate::bundles::TransformBundle) is now deprecated.
|
||||||
|
/// [`GlobalTransform`] is inserted automatically whenever [`Transform`] is inserted.
|
||||||
///
|
///
|
||||||
/// ## [`Transform`] and [`GlobalTransform`]
|
/// ## [`Transform`] and [`GlobalTransform`]
|
||||||
///
|
///
|
||||||
@ -39,6 +41,7 @@ use {
|
|||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "bevy-support",
|
feature = "bevy-support",
|
||||||
derive(Component, Reflect),
|
derive(Component, Reflect),
|
||||||
|
require(GlobalTransform),
|
||||||
reflect(Component, Default, PartialEq, Debug)
|
reflect(Component, Default, PartialEq, Debug)
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
|
@ -88,7 +88,6 @@ mod tests {
|
|||||||
use bevy_math::{Quat, Vec3};
|
use bevy_math::{Quat, Vec3};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundles::TransformBundle,
|
|
||||||
components::{GlobalTransform, Transform},
|
components::{GlobalTransform, Transform},
|
||||||
helper::TransformHelper,
|
helper::TransformHelper,
|
||||||
plugins::TransformPlugin,
|
plugins::TransformPlugin,
|
||||||
@ -122,7 +121,7 @@ mod tests {
|
|||||||
let mut entity = None;
|
let mut entity = None;
|
||||||
|
|
||||||
for transform in transforms {
|
for transform in transforms {
|
||||||
let mut e = app.world_mut().spawn(TransformBundle::from(transform));
|
let mut e = app.world_mut().spawn(transform);
|
||||||
|
|
||||||
if let Some(entity) = entity {
|
if let Some(entity) = entity {
|
||||||
e.set_parent(entity);
|
e.set_parent(entity);
|
||||||
|
@ -32,6 +32,8 @@ pub mod systems;
|
|||||||
/// The transform prelude.
|
/// The transform prelude.
|
||||||
///
|
///
|
||||||
/// This includes the most common types in this crate, re-exported for your convenience.
|
/// This includes the most common types in this crate, re-exported for your convenience.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[expect(deprecated)]
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::components::*;
|
pub use crate::components::*;
|
||||||
|
@ -190,7 +190,7 @@ mod test {
|
|||||||
use bevy_math::{vec3, Vec3};
|
use bevy_math::{vec3, Vec3};
|
||||||
use bevy_tasks::{ComputeTaskPool, TaskPool};
|
use bevy_tasks::{ComputeTaskPool, TaskPool};
|
||||||
|
|
||||||
use crate::{bundles::TransformBundle, systems::*};
|
use crate::systems::*;
|
||||||
use bevy_hierarchy::{BuildChildren, ChildBuild};
|
use bevy_hierarchy::{BuildChildren, ChildBuild};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -199,8 +199,7 @@ mod test {
|
|||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
let offset_global_transform =
|
let offset_global_transform =
|
||||||
|offset| GlobalTransform::from(Transform::from_xyz(offset, offset, offset));
|
|offset| GlobalTransform::from(Transform::from_xyz(offset, offset, offset));
|
||||||
let offset_transform =
|
let offset_transform = |offset| Transform::from_xyz(offset, offset, offset);
|
||||||
|offset| TransformBundle::from_transform(Transform::from_xyz(offset, offset, offset));
|
|
||||||
|
|
||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
schedule.add_systems((sync_simple_transforms, propagate_transforms));
|
schedule.add_systems((sync_simple_transforms, propagate_transforms));
|
||||||
@ -257,22 +256,14 @@ mod test {
|
|||||||
schedule.add_systems((sync_simple_transforms, propagate_transforms));
|
schedule.add_systems((sync_simple_transforms, propagate_transforms));
|
||||||
|
|
||||||
// Root entity
|
// Root entity
|
||||||
world.spawn(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0)));
|
world.spawn(Transform::from_xyz(1.0, 0.0, 0.0));
|
||||||
|
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
world
|
world
|
||||||
.spawn(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0)))
|
.spawn(Transform::from_xyz(1.0, 0.0, 0.0))
|
||||||
.with_children(|parent| {
|
.with_children(|parent| {
|
||||||
children.push(
|
children.push(parent.spawn(Transform::from_xyz(0.0, 2.0, 0.)).id());
|
||||||
parent
|
children.push(parent.spawn(Transform::from_xyz(0.0, 0.0, 3.)).id());
|
||||||
.spawn(TransformBundle::from(Transform::from_xyz(0.0, 2.0, 0.)))
|
|
||||||
.id(),
|
|
||||||
);
|
|
||||||
children.push(
|
|
||||||
parent
|
|
||||||
.spawn(TransformBundle::from(Transform::from_xyz(0.0, 0.0, 3.)))
|
|
||||||
.id(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
|
||||||
@ -299,18 +290,10 @@ mod test {
|
|||||||
let mut commands = Commands::new(&mut queue, &world);
|
let mut commands = Commands::new(&mut queue, &world);
|
||||||
let mut children = Vec::new();
|
let mut children = Vec::new();
|
||||||
commands
|
commands
|
||||||
.spawn(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0)))
|
.spawn(Transform::from_xyz(1.0, 0.0, 0.0))
|
||||||
.with_children(|parent| {
|
.with_children(|parent| {
|
||||||
children.push(
|
children.push(parent.spawn(Transform::from_xyz(0.0, 2.0, 0.0)).id());
|
||||||
parent
|
children.push(parent.spawn(Transform::from_xyz(0.0, 0.0, 3.0)).id());
|
||||||
.spawn(TransformBundle::from(Transform::from_xyz(0.0, 2.0, 0.0)))
|
|
||||||
.id(),
|
|
||||||
);
|
|
||||||
children.push(
|
|
||||||
parent
|
|
||||||
.spawn(TransformBundle::from(Transform::from_xyz(0.0, 0.0, 3.0)))
|
|
||||||
.id(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
queue.apply(&mut world);
|
queue.apply(&mut world);
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
@ -417,15 +400,12 @@ mod test {
|
|||||||
let mut grandchild = Entity::from_raw(1);
|
let mut grandchild = Entity::from_raw(1);
|
||||||
let parent = app
|
let parent = app
|
||||||
.world_mut()
|
.world_mut()
|
||||||
.spawn((
|
.spawn(Transform::from_translation(translation))
|
||||||
Transform::from_translation(translation),
|
|
||||||
GlobalTransform::IDENTITY,
|
|
||||||
))
|
|
||||||
.with_children(|builder| {
|
.with_children(|builder| {
|
||||||
child = builder
|
child = builder
|
||||||
.spawn(TransformBundle::IDENTITY)
|
.spawn(Transform::IDENTITY)
|
||||||
.with_children(|builder| {
|
.with_children(|builder| {
|
||||||
grandchild = builder.spawn(TransformBundle::IDENTITY).id();
|
grandchild = builder.spawn(Transform::IDENTITY).id();
|
||||||
})
|
})
|
||||||
.id();
|
.id();
|
||||||
})
|
})
|
||||||
@ -462,9 +442,9 @@ mod test {
|
|||||||
fn setup_world(world: &mut World) -> (Entity, Entity) {
|
fn setup_world(world: &mut World) -> (Entity, Entity) {
|
||||||
let mut grandchild = Entity::from_raw(0);
|
let mut grandchild = Entity::from_raw(0);
|
||||||
let child = world
|
let child = world
|
||||||
.spawn(TransformBundle::IDENTITY)
|
.spawn(Transform::IDENTITY)
|
||||||
.with_children(|builder| {
|
.with_children(|builder| {
|
||||||
grandchild = builder.spawn(TransformBundle::IDENTITY).id();
|
grandchild = builder.spawn(Transform::IDENTITY).id();
|
||||||
})
|
})
|
||||||
.id();
|
.id();
|
||||||
(child, grandchild)
|
(child, grandchild)
|
||||||
@ -477,7 +457,7 @@ mod test {
|
|||||||
assert_eq!(temp_grandchild, grandchild);
|
assert_eq!(temp_grandchild, grandchild);
|
||||||
|
|
||||||
app.world_mut()
|
app.world_mut()
|
||||||
.spawn(TransformBundle::IDENTITY)
|
.spawn(Transform::IDENTITY)
|
||||||
.add_children(&[child]);
|
.add_children(&[child]);
|
||||||
core::mem::swap(
|
core::mem::swap(
|
||||||
&mut *app.world_mut().get_mut::<Parent>(child).unwrap(),
|
&mut *app.world_mut().get_mut::<Parent>(child).unwrap(),
|
||||||
@ -496,14 +476,9 @@ mod test {
|
|||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
schedule.add_systems((sync_simple_transforms, propagate_transforms));
|
schedule.add_systems((sync_simple_transforms, propagate_transforms));
|
||||||
|
|
||||||
// Spawn a `TransformBundle` entity with a local translation of `Vec3::ONE`
|
// Spawn a `Transform` entity with a local translation of `Vec3::ONE`
|
||||||
let mut spawn_transform_bundle = || {
|
let mut spawn_transform_bundle =
|
||||||
world
|
|| world.spawn(Transform::from_translation(translation)).id();
|
||||||
.spawn(TransformBundle::from_transform(
|
|
||||||
Transform::from_translation(translation),
|
|
||||||
))
|
|
||||||
.id()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Spawn parent and child with identical transform bundles
|
// Spawn parent and child with identical transform bundles
|
||||||
let parent = spawn_transform_bundle();
|
let parent = spawn_transform_bundle();
|
||||||
|
@ -29,7 +29,7 @@ fn setup_cube(
|
|||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
) {
|
) {
|
||||||
commands
|
commands
|
||||||
.spawn(TransformBundle::default())
|
.spawn(Transform::default())
|
||||||
.with_children(|parent| {
|
.with_children(|parent| {
|
||||||
// cube
|
// cube
|
||||||
parent.spawn(PbrBundle {
|
parent.spawn(PbrBundle {
|
||||||
@ -61,8 +61,7 @@ doesn't have a [`ViewVisibility`] or [`InheritedVisibility`] component.
|
|||||||
Since the cube is spawned as a child of an entity without the
|
Since the cube is spawned as a child of an entity without the
|
||||||
visibility components, it will not be visible at all.
|
visibility components, it will not be visible at all.
|
||||||
|
|
||||||
To fix this, you must use [`SpatialBundle`] over [`TransformBundle`],
|
To fix this, you must use [`SpatialBundle`], as follows:
|
||||||
as follows:
|
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
@ -73,7 +72,7 @@ fn setup_cube(
|
|||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
) {
|
) {
|
||||||
commands
|
commands
|
||||||
// We use SpatialBundle instead of TransformBundle, it contains the
|
// We use SpatialBundle instead of Transform, it contains the
|
||||||
// visibility components needed to display the cube,
|
// visibility components needed to display the cube,
|
||||||
// In addition to the Transform and GlobalTransform components.
|
// In addition to the Transform and GlobalTransform components.
|
||||||
.spawn(SpatialBundle::default())
|
.spawn(SpatialBundle::default())
|
||||||
@ -103,9 +102,8 @@ fn main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
A similar problem occurs when the [`GlobalTransform`] component is missing.
|
A similar problem occurs when the [`GlobalTransform`] component is missing.
|
||||||
However, when a parent [`GlobalTransform`] is missing,
|
However, it will be automatically inserted whenever `Transform` is
|
||||||
it will simply prevent all transform propagation,
|
inserted, as it's a required component.
|
||||||
including when updating the [`Transform`] component of the child.
|
|
||||||
|
|
||||||
You will most likely encounter this warning when loading a scene
|
You will most likely encounter this warning when loading a scene
|
||||||
as a child of a pre-existing [`Entity`] that does not have the proper components.
|
as a child of a pre-existing [`Entity`] that does not have the proper components.
|
||||||
@ -113,8 +111,6 @@ as a child of a pre-existing [`Entity`] that does not have the proper components
|
|||||||
[`InheritedVisibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.InheritedVisibility.html
|
[`InheritedVisibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.InheritedVisibility.html
|
||||||
[`ViewVisibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.ViewVisibility.html
|
[`ViewVisibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.ViewVisibility.html
|
||||||
[`GlobalTransform`]: https://docs.rs/bevy/*/bevy/transform/components/struct.GlobalTransform.html
|
[`GlobalTransform`]: https://docs.rs/bevy/*/bevy/transform/components/struct.GlobalTransform.html
|
||||||
[`Transform`]: https://docs.rs/bevy/*/bevy/transform/components/struct.Transform.html
|
|
||||||
[`Parent`]: https://docs.rs/bevy/*/bevy/hierarchy/struct.Parent.html
|
[`Parent`]: https://docs.rs/bevy/*/bevy/hierarchy/struct.Parent.html
|
||||||
[`Entity`]: https://docs.rs/bevy/*/bevy/ecs/entity/struct.Entity.html
|
[`Entity`]: https://docs.rs/bevy/*/bevy/ecs/entity/struct.Entity.html
|
||||||
[`SpatialBundle`]: https://docs.rs/bevy/*/bevy/render/prelude/struct.SpatialBundle.html
|
[`SpatialBundle`]: https://docs.rs/bevy/*/bevy/render/prelude/struct.SpatialBundle.html
|
||||||
[`TransformBundle`]: https://docs.rs/bevy/*/bevy/transform/struct.TransformBundle.html
|
|
||||||
|
@ -130,15 +130,9 @@ fn setup(
|
|||||||
for i in -5..5 {
|
for i in -5..5 {
|
||||||
// Create joint entities
|
// Create joint entities
|
||||||
let joint_0 = commands
|
let joint_0 = commands
|
||||||
.spawn(TransformBundle::from(Transform::from_xyz(
|
.spawn(Transform::from_xyz(i as f32 * 1.5, 0.0, i as f32 * 0.1))
|
||||||
i as f32 * 1.5,
|
|
||||||
0.0,
|
|
||||||
i as f32 * 0.1,
|
|
||||||
)))
|
|
||||||
.id();
|
|
||||||
let joint_1 = commands
|
|
||||||
.spawn((AnimatedJoint, TransformBundle::IDENTITY))
|
|
||||||
.id();
|
.id();
|
||||||
|
let joint_1 = commands.spawn((AnimatedJoint, Transform::IDENTITY)).id();
|
||||||
|
|
||||||
// Set joint_1 as a child of joint_0.
|
// Set joint_1 as a child of joint_0.
|
||||||
commands.entity(joint_0).add_children(&[joint_1]);
|
commands.entity(joint_0).add_children(&[joint_1]);
|
||||||
|
@ -111,7 +111,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
Sprite::default(),
|
Sprite::default(),
|
||||||
TransformBundle::default(),
|
Transform::default(),
|
||||||
VisibilityBundle::default(),
|
VisibilityBundle::default(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -380,7 +380,7 @@ fn spawn_tree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// insert root
|
// insert root
|
||||||
ents.push(commands.spawn(TransformBundle::from(root_transform)).id());
|
ents.push(commands.spawn(root_transform).id());
|
||||||
|
|
||||||
let mut result = InsertResult::default();
|
let mut result = InsertResult::default();
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
@ -426,7 +426,7 @@ fn spawn_tree(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// only insert the components necessary for the transform propagation
|
// only insert the components necessary for the transform propagation
|
||||||
cmd = cmd.insert(TransformBundle::from(transform));
|
cmd = cmd.insert(transform);
|
||||||
|
|
||||||
cmd.id()
|
cmd.id()
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user