Search code examples
rustbevy

How to rotate a rectangle in Bevy?


I've been learning Bevy and I can't figure out how to simply rotate a sprite.

Here is a minimal example illustrating what appears to be a correctly rotated square but an incorrectly rotated rectangle with one dependency bevy = "0.6.1" and main.rs:

use bevy::prelude::*;
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_startup_system(setup)
        .run();
}
fn setup(mut commands: Commands) {
    // cameras
    commands.spawn_bundle(OrthographicCameraBundle::new_2d());
    // square
    commands.spawn_bundle(SpriteBundle {
        transform: Transform {
            translation: Vec3::from((0f32, 0f32, 0f32)),
            rotation: Quat::from_rotation_z(2f32),
            scale: Vec3::new(100f32, 100f32, 0f32),
        },
        sprite: Sprite {
            color: Color::rgb(1., 1., 1.),
            ..Default::default()
        },
        ..Default::default()
    });
    // line
    commands.spawn_bundle(SpriteBundle {
        transform: Transform {
            translation: Vec3::from((0f32, 200f32, 0f32)),
            rotation: Quat::from_rotation_z(2f32),
            scale: Vec3::new(100f32, 10f32, 0f32),
        },
        sprite: Sprite {
            color: Color::rgb(1., 1., 1.),
            ..Default::default()
        },
        ..Default::default()
    });
}

enter image description here

How could I properly rotate the rectangle?

(I've read How to rotate and move object in bevy and I cannot see how it might answer my problem)


Solution

  • You should have better described what you mean by "incorrectly rotated rectangle". In fact your code does exactly what one would expect.

    However I think the issue that you are describing is that because you scaled your sprite using the Transform along the coordinate axes and then rotate the sprite, the scaling axes stay fixed which leads to the effect that the rectangle is constantly scaled differently while rotating. You can see this easily when using the rotate_system below with your original code.

    So how do you set the size of the sprite in its local frame? One would use the custom_size for this as shown below and then set the scale of the Transform to Vec3::new(1f32, 1f32, 1f32).

    I think you want to rotate the rectangle like so based on your code:

    use bevy::prelude::*;
    fn main() {
        App::new()
            .add_plugins(DefaultPlugins)
            .add_startup_system(setup)
            .add_system(rotate_system.system())
            .run();
    }
    #[derive(Component)]
    struct RotationEntity;
    
    fn setup(mut commands: Commands) {
        // cameras
        commands.spawn_bundle(OrthographicCameraBundle::new_2d());
        // square
        commands.spawn_bundle(SpriteBundle {
            transform: Transform {
                translation: Vec3::from((0f32, 0f32, 0f32)),
                rotation: Quat::from_rotation_z(0f32),
                scale: Vec3::new(1f32, 1f32, 1f32),
            },
            sprite: Sprite {
                color: Color::rgb(1., 1., 1.),
                custom_size: Some(Vec2::new(100f32, 100f32)),
                ..Default::default()
            },
            ..Default::default()
        }).insert(RotationEntity);
        // rectangle
        commands.spawn_bundle(SpriteBundle {
            transform: Transform {
                translation: Vec3::from((0f32, 200f32, 0f32)),
                rotation: Quat::from_rotation_z(0f32),
                scale: Vec3::new(1f32, 1f32, 1f32),
            },
            sprite: Sprite {
                color: Color::rgb(1., 0., 0.),
                custom_size: Some(Vec2::new(100f32, 10f32)),
                ..Default::default()
            },
            ..Default::default()
        }).insert(RotationEntity);
    }
    
    fn rotate_system(
        time: Res<Time>,
        mut query: Query<(
            &mut Transform,
            With<RotationEntity>
        )>,
    ) {
        for (mut transform, is_rotation_entity) in query.iter_mut() {
            if is_rotation_entity {
                transform.rotation = Quat::from_rotation_z(time.seconds_since_startup() as f32);
            }
        }
    }
    

    which gives you this capture