bevy_rapier icon indicating copy to clipboard operation
bevy_rapier copied to clipboard

Limited RigidBody rotation in 2d

Open vinsynth opened this issue 1 year ago • 4 comments

I've noticed that directly altering the rotation of an entity containing a RigidBody component is only possible around the z-axis; however, entities without a RigidBody (even entities containing a Collider) can have their rotations directly altered:

use bevy::prelude::*;
use bevy_rapier2d::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugin(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(10.))
        .add_startup_system(setup)
        .add_system(flip_colliders)
        .add_system(flip_rigid_bodies)
        .add_system(test)
        .run();
}

fn setup(
    mut commands: Commands
) {
    // spawn entity with collider
    commands
        .spawn()
        .insert(Collider::cuboid(10., 10.))
        .insert(Transform::from_rotation(Quat::IDENTITY))
        .insert(GlobalTransform::default());

    // spawn entity with rigid body
    commands
        .spawn()
        .insert(RigidBody::Dynamic)
        .insert(Transform::from_rotation(Quat::IDENTITY))
        .insert(GlobalTransform::default());
}

fn flip_colliders(
    mut colliders: Query<&mut Transform, Added<Collider>>,
) {
    for mut transform in colliders.iter_mut() {
        transform.rotation = Quat::from_rotation_y(std::f32::consts::PI);
    }
}

fn flip_rigid_bodies(
    mut rigid_bodies: Query<&mut Transform, Added<RigidBody>>
) {
    for mut transform in rigid_bodies.iter_mut() {
        transform.rotation = Quat::from_rotation_y(std::f32::consts::PI);
    }
}

fn test(
    colliders: Query<&Transform, With<Collider>>,
    rigid_bodies: Query<&Transform, With<RigidBody>>
) {
    // check if collider rotation changed
    for transform in colliders.iter() {
        assert_eq!(transform.rotation, Quat::from_rotation_y(std::f32::consts::PI),
            "Collider rotation didn't change!");
    }

    // check if rigid body rotation changed
    for transform in rigid_bodies.iter() {
        assert_eq!(transform.rotation, Quat::from_rotation_y(std::f32::consts::PI),
            "RigidBody rotation didn't change!");
    }
}

The above code panics with the following:

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `Quat(0.0, 0.0, 0.0, 1.0)`,
 right: `Quat(0.0, 1.0, 0.0, -4.371139e-8)`: RigidBody rotation didn't change!', src\main.rs:61:9

Is there an effective way to instantly change the rotation of a RigidBody? I understand that bevy_rapier2d is a 2d physics engine, but the ability to rotate the entity around the x- and y-axes is especially useful for changing its orientation (e.g., flipping the player sprite in a platformer).

vinsynth avatar Aug 23 '22 18:08 vinsynth

You can use TextureAtlasSprite flip_x = true or false

laodino avatar Dec 03 '22 15:12 laodino

Flipping the sprite would only change its orientation visibly, while changing the entity's rotation would both change its orientation and the orientation of its child entities.

For example, if I coded an attack hitbox to spawn as a child of an attacker, the attack's Transform would be relative to that of its parent attacker. Thus, if said attack always spawned with a positive translation from the parent attacker, and the attacker was facing to the right, the attack would spawn right of the attacker and thusly be correctly orientated in front of the attacker.

However, if I faced the attacker left by flipping its sprite, the attack's positive translation would still spawn it right of the attacker, thereby incorrectly orientating the attack behind the attacker.

If I instead faced the attacker left by rotating it 180 degrees about its y-axis, the attack's positive translation would again spawn it right of the attacker, but the parent attacker's Transform would then rotate the attack 180 degrees around the attacker's y-axis, thereby placing the attack left of its attacker and correctly orienting the attack in front of its attacker. This rotation would also "flip" the attack's sprite like the attacker's.

vinsynth avatar Dec 03 '22 22:12 vinsynth

Sorry,I didn't take into account attacks and other features. I am learning BEVY, and when I write about MOVEMENT and SPRITE ANIMATION, I also encounter the same problem.Simply thought that inverting the sprite would solve it, but it looks like there are more problems to be solved.

laodino avatar Dec 04 '22 02:12 laodino

that's not easy, how would a rotation of 45 degrees react ? A user could expect to have the collider shorter like this image:

image

I think a "flip" method/property is probably safer ; and/or opt out from bevy Transform for a specific PhysicsTransform so we don't end up in weird half 3d / half 2d components

Vrixyz avatar May 24 '24 07:05 Vrixyz