Remove the GlobalTransform::translation_mut method (#7134)

# Objective

It is possible to manually update `GlobalTransform`.
The engine actually assumes this is not possible.
For example, `propagate_transform` does not update children
of an `Entity` which **`GlobalTransform`** changed,
leading to unexpected behaviors.

A `GlobalTransform` set by the user may also be blindly
overwritten by the propagation system.

## Solution

- Remove `translation_mut`
- Explain to users that they shouldn't manually update the `GlobalTransform`
- Remove `global_vs_local.rs` example, since it misleads users
  in believing that it is a valid use-case to manually update the
  `GlobalTransform`

---

## Changelog

- Remove `GlobalTransform::translation_mut`

## Migration Guide

`GlobalTransform::translation_mut` has been removed without alternative,
if you were relying on this, update the `Transform` instead. If the given entity
had children or parent, you may need to remove its parent to make its transform
independent (in which case the new `Commands::set_parent_in_place` and
`Commands::remove_parent_in_place` may be of interest)

Bevy may add in the future a way to toggle transform propagation on
an entity basis.
This commit is contained in:
Nicola Papale 2023-01-10 18:55:22 +00:00
parent fa40e2badb
commit 3600c5a340
4 changed files with 4 additions and 218 deletions

View file

@ -1384,17 +1384,6 @@ description = "Shows a visualization of gamepad buttons, sticks, and triggers"
category = "Tools"
wasm = false
# Transforms
[[example]]
name = "global_vs_local_translation"
path = "examples/transforms/global_vs_local_translation.rs"
[package.metadata.example.global_vs_local_translation]
name = "Global / Local Translation"
description = "Illustrates the difference between direction of a translation in respect to local object or global object Transform"
category = "Transforms"
wasm = true
[[example]]
name = "3d_rotation"
path = "examples/transforms/3d_rotation.rs"

View file

@ -8,6 +8,8 @@ use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect};
/// Describe the position of an entity relative to the reference frame.
///
/// * To place or move an entity, you should set its [`Transform`].
/// * [`GlobalTransform`] is fully managed by bevy, you cannot mutate it, use
/// [`Transform`] instead.
/// * 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`].
/// * You may use the [`TransformBundle`](crate::TransformBundle) to guarantee this.
@ -28,9 +30,9 @@ use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect};
///
/// # Examples
///
/// - [`global_vs_local_translation`]
/// - [`transform`]
///
/// [`global_vs_local_translation`]: https://github.com/bevyengine/bevy/blob/latest/examples/transforms/global_vs_local_translation.rs
/// [`transform`]: https://github.com/bevyengine/bevy/blob/latest/examples/transforms/transform.rs
#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect, FromReflect)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[reflect(Component, Default, PartialEq)]
@ -169,12 +171,6 @@ impl GlobalTransform {
self.0.translation.into()
}
/// Mutably access the internal translation.
#[inline]
pub fn translation_mut(&mut self) -> &mut Vec3A {
&mut self.0.translation
}
/// Get the translation as a [`Vec3A`].
#[inline]
pub fn translation_vec3a(&self) -> Vec3A {

View file

@ -302,7 +302,6 @@ Example | Description
Example | Description
--- | ---
[3D Rotation](../examples/transforms/3d_rotation.rs) | Illustrates how to (constantly) rotate an object around an axis
[Global / Local Translation](../examples/transforms/global_vs_local_translation.rs) | Illustrates the difference between direction of a translation in respect to local object or global object Transform
[Scale](../examples/transforms/scale.rs) | Illustrates how to scale an object in each direction
[Transform](../examples/transforms/transform.rs) | Shows multiple transformations of objects
[Translation](../examples/transforms/translation.rs) | Illustrates how to move an object along an axis

View file

@ -1,198 +0,0 @@
//! Illustrates the difference between direction of a translation in respect to local object or
//! global object Transform.
use bevy::{math::Vec3A, prelude::*};
// Define a marker for entities that should be changed via their global transform.
#[derive(Component)]
struct ChangeGlobal;
// Define a marker for entities that should be changed via their local transform.
#[derive(Component)]
struct ChangeLocal;
// Define a marker for entities that should move.
#[derive(Component)]
struct Move;
// Define a resource for the current movement direction;
#[derive(Resource, Default)]
struct Direction(Vec3);
// Define component to decide when an entity should be ignored by the movement systems.
#[derive(Component)]
struct ToggledBy(KeyCode);
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.init_resource::<Direction>()
.add_system(move_cubes_according_to_global_transform)
.add_system(move_cubes_according_to_local_transform)
.add_system(update_directional_input)
.add_system(toggle_movement)
.run();
}
// Startup system to setup the scene and spawn all relevant entities.
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
asset_server: Res<AssetServer>,
) {
// To show the difference between a local transform (rotation, scale and position in respect to a given entity)
// and global transform (rotation, scale and position in respect to the base coordinate system of the visible scene)
// it's helpful to add multiple entities that are attached to each other.
// This way we'll see that the transform in respect to an entity's parent is different to the
// global transform within the visible scene.
// This example focuses on translation only to clearly demonstrate the differences.
// Spawn a basic cube to have an entity as reference.
commands
.spawn((
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
material: materials.add(StandardMaterial {
base_color: Color::YELLOW,
alpha_mode: AlphaMode::Blend,
..Default::default()
}),
..default()
},
ChangeGlobal,
Move,
ToggledBy(KeyCode::Key1),
))
// Spawn two entities as children above the original main entity.
// The red entity spawned here will be changed via its global transform
// where the green one will be changed via its local transform.
.with_children(|child_builder| {
// also see parenting example
child_builder.spawn((
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.5 })),
material: materials.add(StandardMaterial {
base_color: Color::RED,
alpha_mode: AlphaMode::Blend,
..Default::default()
}),
transform: Transform::from_translation(Vec3::Y - Vec3::Z),
..default()
},
ChangeGlobal,
Move,
ToggledBy(KeyCode::Key2),
));
child_builder.spawn((
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.5 })),
material: materials.add(StandardMaterial {
base_color: Color::GREEN,
alpha_mode: AlphaMode::Blend,
..Default::default()
}),
transform: Transform::from_translation(Vec3::Y + Vec3::Z),
..default()
},
ChangeLocal,
Move,
ToggledBy(KeyCode::Key3),
));
});
// Spawn a camera looking at the entities to show what's happening in this example.
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(0.0, 10.0, 20.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
// Add a light source for better 3d visibility.
commands.spawn(PointLightBundle {
transform: Transform::from_translation(Vec3::splat(3.0)),
..default()
});
// Add text to explain inputs and what is happening.
commands.spawn(TextBundle::from_section(
"Press the arrow keys to move the cubes. Toggle movement for yellow (1), red (2) and green (3) cubes via number keys.
Notice how the green cube will translate further in respect to the yellow in contrast to the red cube.
This is due to the use of its LocalTransform that is relative to the yellow cubes transform instead of the GlobalTransform as in the case of the red cube.
The red cube is moved through its GlobalTransform and thus is unaffected by the yellows transform.",
TextStyle {
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
font_size: 22.0,
color: Color::WHITE,
},
));
}
// This system will move all cubes that are marked as ChangeGlobal according to their global transform.
fn move_cubes_according_to_global_transform(
mut cubes: Query<&mut GlobalTransform, (With<ChangeGlobal>, With<Move>)>,
direction: Res<Direction>,
timer: Res<Time>,
) {
for mut global_transform in &mut cubes {
*global_transform.translation_mut() += Vec3A::from(direction.0) * timer.delta_seconds();
}
}
// This system will move all cubes that are marked as ChangeLocal according to their local transform.
fn move_cubes_according_to_local_transform(
mut cubes: Query<&mut Transform, (With<ChangeLocal>, With<Move>)>,
direction: Res<Direction>,
timer: Res<Time>,
) {
for mut transform in &mut cubes {
transform.translation += direction.0 * timer.delta_seconds();
}
}
// This system updates a resource that defines in which direction the cubes should move.
// The direction is defined by the input of arrow keys and is only in left/right and up/down direction.
fn update_directional_input(mut direction: ResMut<Direction>, keyboard_input: Res<Input<KeyCode>>) {
let horizontal_movement = Vec3::X
* (keyboard_input.pressed(KeyCode::Right) as i32
- keyboard_input.pressed(KeyCode::Left) as i32) as f32;
let vertical_movement = Vec3::Y
* (keyboard_input.pressed(KeyCode::Up) as i32
- keyboard_input.pressed(KeyCode::Down) as i32) as f32;
direction.0 = horizontal_movement + vertical_movement;
}
// This system enables and disables the movement for each entity if their assigned key is pressed.
fn toggle_movement(
mut commands: Commands,
movable_entities: Query<(Entity, &Handle<StandardMaterial>, &ToggledBy), With<Move>>,
static_entities: Query<(Entity, &Handle<StandardMaterial>, &ToggledBy), Without<Move>>,
mut materials: ResMut<Assets<StandardMaterial>>,
keyboard_input: Res<Input<KeyCode>>,
) {
// Update the currently movable entities and remove their Move component if the assigned key was pressed to disable their movement.
// This will also make them transparent so they can be identified as 'disabled' in the scene.
for (entity, material_handle, toggled_by) in &movable_entities {
if keyboard_input.just_pressed(toggled_by.0) {
materials
.get_mut(material_handle)
.unwrap()
.base_color
.set_a(0.5);
commands.entity(entity).remove::<Move>();
}
}
// Update the currently non-movable entities and add a Move component if the assigned key was pressed to enable their movement.
// This will also make them opaque so they can be identified as 'enabled' in the scene.
for (entity, material_handle, toggled_by) in &static_entities {
if keyboard_input.just_pressed(toggled_by.0) {
materials
.get_mut(material_handle)
.unwrap()
.base_color
.set_a(1.0);
commands.entity(entity).insert(Move);
}
}
}