Skip to content

Commit b04947d

Browse files
ecoskeyalice-i-ceciletim-blackbird
authored
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 <[email protected]> Co-authored-by: Tim <[email protected]>
1 parent a0c722f commit b04947d

File tree

10 files changed

+43
-67
lines changed

10 files changed

+43
-67
lines changed

crates/bevy_transform/src/bundles.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![expect(deprecated)]
12
use bevy_ecs::bundle::Bundle;
23

34
use crate::prelude::{GlobalTransform, Transform};
@@ -24,6 +25,10 @@ use crate::prelude::{GlobalTransform, Transform};
2425
/// update the [`Transform`] of an entity in this schedule or after, you will notice a 1 frame lag
2526
/// before the [`GlobalTransform`] is updated.
2627
#[derive(Clone, Copy, Debug, Default, Bundle)]
28+
#[deprecated(
29+
since = "0.15.0",
30+
note = "Use the `Transform` component instead. Inserting `Transform` will now also insert a `GlobalTransform` automatically."
31+
)]
2732
pub struct TransformBundle {
2833
/// The transform of the entity.
2934
pub local: Transform,

crates/bevy_transform/src/components/global_transform.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use {
1717
///
1818
/// * To get the global transform of an entity, you should get its [`GlobalTransform`].
1919
/// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`].
20-
/// * You may use the [`TransformBundle`](crate::bundles::TransformBundle) to guarantee this.
20+
/// ~* You may use the [`TransformBundle`](crate::bundles::TransformBundle) to guarantee this.~
21+
/// * [`TransformBundle`](crate::bundles::TransformBundle) is now deprecated.
22+
/// [`GlobalTransform`] is automatically inserted whenever [`Transform`] is inserted.
2123
///
2224
/// ## [`Transform`] and [`GlobalTransform`]
2325
///

crates/bevy_transform/src/components/transform.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use {
1313
/// * To place or move an entity, you should set its [`Transform`].
1414
/// * To get the global transform of an entity, you should get its [`GlobalTransform`].
1515
/// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`].
16-
/// * You may use the [`TransformBundle`](crate::bundles::TransformBundle) to guarantee this.
16+
/// ~* You may use the [`TransformBundle`](crate::bundles::TransformBundle) to guarantee this.~
17+
/// * [`TransformBundle`](crate::bundles::TransformBundle) is now deprecated.
18+
/// [`GlobalTransform`] is inserted automatically whenever [`Transform`] is inserted.
1719
///
1820
/// ## [`Transform`] and [`GlobalTransform`]
1921
///
@@ -39,6 +41,7 @@ use {
3941
#[cfg_attr(
4042
feature = "bevy-support",
4143
derive(Component, Reflect),
44+
require(GlobalTransform),
4245
reflect(Component, Default, PartialEq, Debug)
4346
)]
4447
#[cfg_attr(

crates/bevy_transform/src/helper.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ mod tests {
8888
use bevy_math::{Quat, Vec3};
8989

9090
use crate::{
91-
bundles::TransformBundle,
9291
components::{GlobalTransform, Transform},
9392
helper::TransformHelper,
9493
plugins::TransformPlugin,
@@ -122,7 +121,7 @@ mod tests {
122121
let mut entity = None;
123122

124123
for transform in transforms {
125-
let mut e = app.world_mut().spawn(TransformBundle::from(transform));
124+
let mut e = app.world_mut().spawn(transform);
126125

127126
if let Some(entity) = entity {
128127
e.set_parent(entity);

crates/bevy_transform/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub mod systems;
3232
/// The transform prelude.
3333
///
3434
/// This includes the most common types in this crate, re-exported for your convenience.
35+
#[doc(hidden)]
36+
#[expect(deprecated)]
3537
pub mod prelude {
3638
#[doc(hidden)]
3739
pub use crate::components::*;

crates/bevy_transform/src/systems.rs

Lines changed: 18 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ mod test {
190190
use bevy_math::{vec3, Vec3};
191191
use bevy_tasks::{ComputeTaskPool, TaskPool};
192192

193-
use crate::{bundles::TransformBundle, systems::*};
193+
use crate::systems::*;
194194
use bevy_hierarchy::{BuildChildren, ChildBuild};
195195

196196
#[test]
@@ -199,8 +199,7 @@ mod test {
199199
let mut world = World::default();
200200
let offset_global_transform =
201201
|offset| GlobalTransform::from(Transform::from_xyz(offset, offset, offset));
202-
let offset_transform =
203-
|offset| TransformBundle::from_transform(Transform::from_xyz(offset, offset, offset));
202+
let offset_transform = |offset| Transform::from_xyz(offset, offset, offset);
204203

205204
let mut schedule = Schedule::default();
206205
schedule.add_systems((sync_simple_transforms, propagate_transforms));
@@ -257,22 +256,14 @@ mod test {
257256
schedule.add_systems((sync_simple_transforms, propagate_transforms));
258257

259258
// Root entity
260-
world.spawn(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0)));
259+
world.spawn(Transform::from_xyz(1.0, 0.0, 0.0));
261260

262261
let mut children = Vec::new();
263262
world
264-
.spawn(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0)))
263+
.spawn(Transform::from_xyz(1.0, 0.0, 0.0))
265264
.with_children(|parent| {
266-
children.push(
267-
parent
268-
.spawn(TransformBundle::from(Transform::from_xyz(0.0, 2.0, 0.)))
269-
.id(),
270-
);
271-
children.push(
272-
parent
273-
.spawn(TransformBundle::from(Transform::from_xyz(0.0, 0.0, 3.)))
274-
.id(),
275-
);
265+
children.push(parent.spawn(Transform::from_xyz(0.0, 2.0, 0.)).id());
266+
children.push(parent.spawn(Transform::from_xyz(0.0, 0.0, 3.)).id());
276267
});
277268
schedule.run(&mut world);
278269

@@ -299,18 +290,10 @@ mod test {
299290
let mut commands = Commands::new(&mut queue, &world);
300291
let mut children = Vec::new();
301292
commands
302-
.spawn(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0)))
293+
.spawn(Transform::from_xyz(1.0, 0.0, 0.0))
303294
.with_children(|parent| {
304-
children.push(
305-
parent
306-
.spawn(TransformBundle::from(Transform::from_xyz(0.0, 2.0, 0.0)))
307-
.id(),
308-
);
309-
children.push(
310-
parent
311-
.spawn(TransformBundle::from(Transform::from_xyz(0.0, 0.0, 3.0)))
312-
.id(),
313-
);
295+
children.push(parent.spawn(Transform::from_xyz(0.0, 2.0, 0.0)).id());
296+
children.push(parent.spawn(Transform::from_xyz(0.0, 0.0, 3.0)).id());
314297
});
315298
queue.apply(&mut world);
316299
schedule.run(&mut world);
@@ -417,15 +400,12 @@ mod test {
417400
let mut grandchild = Entity::from_raw(1);
418401
let parent = app
419402
.world_mut()
420-
.spawn((
421-
Transform::from_translation(translation),
422-
GlobalTransform::IDENTITY,
423-
))
403+
.spawn(Transform::from_translation(translation))
424404
.with_children(|builder| {
425405
child = builder
426-
.spawn(TransformBundle::IDENTITY)
406+
.spawn(Transform::IDENTITY)
427407
.with_children(|builder| {
428-
grandchild = builder.spawn(TransformBundle::IDENTITY).id();
408+
grandchild = builder.spawn(Transform::IDENTITY).id();
429409
})
430410
.id();
431411
})
@@ -462,9 +442,9 @@ mod test {
462442
fn setup_world(world: &mut World) -> (Entity, Entity) {
463443
let mut grandchild = Entity::from_raw(0);
464444
let child = world
465-
.spawn(TransformBundle::IDENTITY)
445+
.spawn(Transform::IDENTITY)
466446
.with_children(|builder| {
467-
grandchild = builder.spawn(TransformBundle::IDENTITY).id();
447+
grandchild = builder.spawn(Transform::IDENTITY).id();
468448
})
469449
.id();
470450
(child, grandchild)
@@ -477,7 +457,7 @@ mod test {
477457
assert_eq!(temp_grandchild, grandchild);
478458

479459
app.world_mut()
480-
.spawn(TransformBundle::IDENTITY)
460+
.spawn(Transform::IDENTITY)
481461
.add_children(&[child]);
482462
core::mem::swap(
483463
&mut *app.world_mut().get_mut::<Parent>(child).unwrap(),
@@ -496,14 +476,9 @@ mod test {
496476
let mut schedule = Schedule::default();
497477
schedule.add_systems((sync_simple_transforms, propagate_transforms));
498478

499-
// Spawn a `TransformBundle` entity with a local translation of `Vec3::ONE`
500-
let mut spawn_transform_bundle = || {
501-
world
502-
.spawn(TransformBundle::from_transform(
503-
Transform::from_translation(translation),
504-
))
505-
.id()
506-
};
479+
// Spawn a `Transform` entity with a local translation of `Vec3::ONE`
480+
let mut spawn_transform_bundle =
481+
|| world.spawn(Transform::from_translation(translation)).id();
507482

508483
// Spawn parent and child with identical transform bundles
509484
let parent = spawn_transform_bundle();

errors/B0004.md

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn setup_cube(
2929
mut materials: ResMut<Assets<StandardMaterial>>,
3030
) {
3131
commands
32-
.spawn(TransformBundle::default())
32+
.spawn(Transform::default())
3333
.with_children(|parent| {
3434
// cube
3535
parent.spawn(PbrBundle {
@@ -61,8 +61,7 @@ doesn't have a [`ViewVisibility`] or [`InheritedVisibility`] component.
6161
Since the cube is spawned as a child of an entity without the
6262
visibility components, it will not be visible at all.
6363

64-
To fix this, you must use [`SpatialBundle`] over [`TransformBundle`],
65-
as follows:
64+
To fix this, you must use [`SpatialBundle`], as follows:
6665

6766
```rust,no_run
6867
use bevy::prelude::*;
@@ -73,7 +72,7 @@ fn setup_cube(
7372
mut materials: ResMut<Assets<StandardMaterial>>,
7473
) {
7574
commands
76-
// We use SpatialBundle instead of TransformBundle, it contains the
75+
// We use SpatialBundle instead of Transform, it contains the
7776
// visibility components needed to display the cube,
7877
// In addition to the Transform and GlobalTransform components.
7978
.spawn(SpatialBundle::default())
@@ -103,18 +102,15 @@ fn main() {
103102
```
104103

105104
A similar problem occurs when the [`GlobalTransform`] component is missing.
106-
However, when a parent [`GlobalTransform`] is missing,
107-
it will simply prevent all transform propagation,
108-
including when updating the [`Transform`] component of the child.
105+
However, it will be automatically inserted whenever `Transform` is
106+
inserted, as it's a required component.
109107

110108
You will most likely encounter this warning when loading a scene
111109
as a child of a pre-existing [`Entity`] that does not have the proper components.
112110

113111
[`InheritedVisibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.InheritedVisibility.html
114112
[`ViewVisibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.ViewVisibility.html
115113
[`GlobalTransform`]: https://docs.rs/bevy/*/bevy/transform/components/struct.GlobalTransform.html
116-
[`Transform`]: https://docs.rs/bevy/*/bevy/transform/components/struct.Transform.html
117114
[`Parent`]: https://docs.rs/bevy/*/bevy/hierarchy/struct.Parent.html
118115
[`Entity`]: https://docs.rs/bevy/*/bevy/ecs/entity/struct.Entity.html
119116
[`SpatialBundle`]: https://docs.rs/bevy/*/bevy/render/prelude/struct.SpatialBundle.html
120-
[`TransformBundle`]: https://docs.rs/bevy/*/bevy/transform/struct.TransformBundle.html

examples/animation/custom_skinned_mesh.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,9 @@ fn setup(
130130
for i in -5..5 {
131131
// Create joint entities
132132
let joint_0 = commands
133-
.spawn(TransformBundle::from(Transform::from_xyz(
134-
i as f32 * 1.5,
135-
0.0,
136-
i as f32 * 0.1,
137-
)))
138-
.id();
139-
let joint_1 = commands
140-
.spawn((AnimatedJoint, TransformBundle::IDENTITY))
133+
.spawn(Transform::from_xyz(i as f32 * 1.5, 0.0, i as f32 * 0.1))
141134
.id();
135+
let joint_1 = commands.spawn((AnimatedJoint, Transform::IDENTITY)).id();
142136

143137
// Set joint_1 as a child of joint_0.
144138
commands.entity(joint_0).add_children(&[joint_1]);

examples/asset/asset_decompression.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
111111
..default()
112112
},
113113
Sprite::default(),
114-
TransformBundle::default(),
114+
Transform::default(),
115115
VisibilityBundle::default(),
116116
));
117117
}

examples/stress_tests/transform_hierarchy.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ fn spawn_tree(
380380
}
381381

382382
// insert root
383-
ents.push(commands.spawn(TransformBundle::from(root_transform)).id());
383+
ents.push(commands.spawn(root_transform).id());
384384

385385
let mut result = InsertResult::default();
386386
let mut rng = rand::thread_rng();
@@ -426,7 +426,7 @@ fn spawn_tree(
426426
};
427427

428428
// only insert the components necessary for the transform propagation
429-
cmd = cmd.insert(TransformBundle::from(transform));
429+
cmd = cmd.insert(transform);
430430

431431
cmd.id()
432432
};

0 commit comments

Comments
 (0)