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:
parent
fa40e2badb
commit
3600c5a340
11
Cargo.toml
11
Cargo.toml
@ -1384,17 +1384,6 @@ description = "Shows a visualization of gamepad buttons, sticks, and triggers"
|
|||||||
category = "Tools"
|
category = "Tools"
|
||||||
wasm = false
|
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]]
|
[[example]]
|
||||||
name = "3d_rotation"
|
name = "3d_rotation"
|
||||||
path = "examples/transforms/3d_rotation.rs"
|
path = "examples/transforms/3d_rotation.rs"
|
||||||
|
@ -8,6 +8,8 @@ use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect};
|
|||||||
/// Describe the position of an entity relative to the reference frame.
|
/// Describe the position of an entity relative to the reference frame.
|
||||||
///
|
///
|
||||||
/// * To place or move an entity, you should set its [`Transform`].
|
/// * 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`].
|
/// * 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::TransformBundle) to guarantee this.
|
/// * You may use the [`TransformBundle`](crate::TransformBundle) to guarantee this.
|
||||||
@ -28,9 +30,9 @@ use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect};
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # 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)]
|
#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect, FromReflect)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[reflect(Component, Default, PartialEq)]
|
#[reflect(Component, Default, PartialEq)]
|
||||||
@ -169,12 +171,6 @@ impl GlobalTransform {
|
|||||||
self.0.translation.into()
|
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`].
|
/// Get the translation as a [`Vec3A`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn translation_vec3a(&self) -> Vec3A {
|
pub fn translation_vec3a(&self) -> Vec3A {
|
||||||
|
@ -302,7 +302,6 @@ Example | Description
|
|||||||
Example | Description
|
Example | Description
|
||||||
--- | ---
|
--- | ---
|
||||||
[3D Rotation](../examples/transforms/3d_rotation.rs) | Illustrates how to (constantly) rotate an object around an axis
|
[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
|
[Scale](../examples/transforms/scale.rs) | Illustrates how to scale an object in each direction
|
||||||
[Transform](../examples/transforms/transform.rs) | Shows multiple transformations of objects
|
[Transform](../examples/transforms/transform.rs) | Shows multiple transformations of objects
|
||||||
[Translation](../examples/transforms/translation.rs) | Illustrates how to move an object along an axis
|
[Translation](../examples/transforms/translation.rs) | Illustrates how to move an object along an axis
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user