Bevy Version: | 0.9 | (outdated!) |
---|
Transforms
Relevant official examples:
transform
,
translation
,
rotation
,
3d_rotation
,
scale
,
move_sprite
,
parenting
,
anything that spawns 2D or 3D objects.
First, a quick definition, if you are new to game development:
a Transform is what allows you to place an object in the game world. It is a combination of the object's "translation" (position/coordinates), "rotation", and "scale" (size adjustment).
You move objects around by modifying the translation, rotate them by modifying the rotation, and make them larger or smaller by modifying the scale.
// To simply position something at specific coordinates
let xf_pos567 = Transform::from_xyz(5.0, 6.0, 7.0);
// To scale an object, making it twice as big in all dimensions
let xf_scale = Transform::from_scale(Vec3::splat(2.0));
// To rotate an object in 2D (Z-axis rotation) by 30°
// (angles are in radians! must convert from degrees!)
let xf_rot2d = Transform::from_rotation(Quat::from_rotation_z((30.0_f32).to_radians()));
// 3D rotations can be complicated; explore the methods available on `Quat`
// Simple 3D rotation by Euler-angles (X, Y, Z)
let xf_rot2d = Transform::from_rotation(Quat::from_euler(
EulerRot::XYZ,
(20.0_f32).to_radians(),
(10.0_f32).to_radians(),
(30.0_f32).to_radians(),
));
// Everything:
let xf = Transform::from_xyz(1.0, 2.0, 3.0)
.with_scale(Vec3::new(0.5, 0.5, 1.0))
.with_rotation(Quat::from_rotation_y(0.125 * std::f32::consts::PI));
Transform Components
In Bevy, transforms are represented by two components:
Transform
and GlobalTransform
.
Any Entity that represents an object in the game world needs to have both. All of Bevy's built-in bundle types include them.
If you are creating a custom entity without using those bundles, you can use one of the following to ensure you don't miss them:
SpatialBundle
for transforms + visibilityTransformBundle
for just the transforms
fn spawn_special_entity(
mut commands: Commands,
) {
// create an entity that does not use one of the common Bevy bundles,
// but still needs transforms and visibility
commands.spawn((
ComponentA,
ComponentB,
SpatialBundle {
transform: Transform::from_scale(Vec3::splat(3.0)),
visibility: Visibility {
is_visible: false,
},
..Default::default()
},
));
}
Transform
Transform
is what you typically work with. It is
a struct
containing the translation, rotation, and scale. To read or
manipulate these values, access it from your systems using a
query.
If the entity has a parent, the Transform
component is relative to the parent. This means that the child object will
move/rotate/scale along with the parent.
fn inflate_balloons(
mut query: Query<&mut Transform, With<Balloon>>,
keyboard: Res<Input<KeyCode>>,
) {
// every time the Spacebar is pressed,
// make all the balloons in the game bigger by 25%
if keyboard.just_pressed(KeyCode::Space) {
for mut transform in query.iter_mut() {
transform.scale *= 1.25;
}
}
}
GlobalTransform
GlobalTransform
represents the absolute global
position in the world.
If the entity does not have a parent, then this will have
the same value as the Transform
.
The value of GlobalTransform
is calculated/managed
internally by Bevy. See below.
Transform Propagation
Beware: The two components are synchronized by a bevy-internal
system (the "transform propagation system"), which runs in the
PostUpdate
stage.
When you mutate the Transform
, the
GlobalTransform
is not updated immediately. They
will be out-of-sync until the transform propagation system runs.
If you need to work with GlobalTransform
directly,
you should add your system to the PostUpdate
stage and order it after the
TransformSystem::TransformPropagate
label.
/// Print the up-to-date global coordinates of the player as of **this frame**.
fn debug_globaltransform(
query: Query<&GlobalTransform, With<Player>>,
) {
let gxf = query.single();
debug!("Player at: {:?}", gxf.translation());
}
fn main() {
// the label to use for ordering
use bevy::transform::TransformSystem;
App::new()
.add_plugins(DefaultPlugins)
.add_system_to_stage(
CoreStage::PostUpdate,
debug_globaltransform
.after(TransformSystem::TransformPropagate)
)
.run();
}