Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KinematicCharcaterController: the up vector cannot point downward #413

Closed
Linentio opened this issue Jul 29, 2023 · 6 comments · Fixed by dimforge/rapier#529
Closed

KinematicCharcaterController: the up vector cannot point downward #413

Linentio opened this issue Jul 29, 2023 · 6 comments · Fixed by dimforge/rapier#529

Comments

@Linentio
Copy link

Linentio commented Jul 29, 2023

Hello, I'm working on a game where I can reverse gravity. By doing that, I need to be able to switch the direction of the up vector of the KinematicCharcaterController so that it points downward.
But as soon as I set the up vector to Vec2::new(0.0, -1.0) the game crashes, stating that "The loosening margin must be positive" (parry2d is throwing this error message).
For your information, the same problem occurs if I set the up vector to Vec2::new(-1.0, 0.0).

I don't know if it's intended but because of that, I cannot manage to have the grounded property of the KinematicCharcaterControllerOutput to be true when the player touches the "ground" once the gravity is reversed.

Here is a small example illustrating the issue, just change the up attribute of the KinematicCharacterController component to Vec2::NEG_Y and the game will crash (bevy_rapier2d version used : v0.22.0):

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

fn main() {
    App::new()
        .insert_resource(ClearColor(Color::rgb(
            0xF9 as f32 / 255.0,
            0xF9 as f32 / 255.0,
            0xFF as f32 / 255.0,
        )))
        .add_plugins((
            DefaultPlugins,
            RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0),
            RapierDebugRenderPlugin::default(),
        ))
        .add_systems(Startup, (setup_graphics, setup_physics))
        .add_systems(Update, gravity)
        .run();
}

fn setup_graphics(mut commands: Commands) {
    commands.spawn(Camera2dBundle {
        transform: Transform::from_xyz(0.0, 20.0, 0.0),
        ..default()
    });
}

pub fn setup_physics(mut commands: Commands) {
    /*
     * Ground
     */
    let ground_size = 500.0;
    let ground_height = 10.0;

    commands.spawn((
        TransformBundle::from(Transform::from_xyz(0.0, 10.0 * ground_height, 0.0)),
        Collider::cuboid(ground_size, ground_height),
    ));

    /*
     * Player 
     */
    commands
        .spawn(KinematicCharacterController {
            up: Vec2::Y, // if up = Vec2::NEG_Y, the game crashes
            ..default()
        })
        .insert(
            (TransformBundle::from(Transform::from_xyz(16., 0., 0.0)),
            Collider::cuboid(10.0, 10.0)
        ));
}

fn gravity(
    mut player_query: Query<&mut KinematicCharacterController>, 
    player_output_query: Query<&KinematicCharacterControllerOutput>
) {
    for mut controller in &mut player_query {
        controller.translation = Some(Vec2::new(0.0, 1.0)); // Since the gravity is reversed, the player goes upward
    }

    for player_output in &player_output_query {
        println!("Player is on the ground: {}", player_output.grounded);
    }
}
@Aceeri
Copy link
Contributor

Aceeri commented Aug 15, 2023

I think this is fine, just missed an .abs() for the loosening so should be a simple fix.

@Linentio
Copy link
Author

Okay this seems to work, thank you. The game no longer crashes when I set the up vector to Vec2::NEG_Y.

Where am I supposed to put the .abs() please?
Because for now I've placed it directly inside the lossened function as a temporary workaround, like this:

#[inline]
fn loosened(&self, amount: Real) -> Aabb
    assert!(amount.abs() >= 0.0, "The loosening margin must be positive.");
    Aabb {
        mins: self.mins + Vector::repeat(-amount),
        maxs: self.maxs + Vector::repeat(amount),
    }
}

And this causes a new issue: the player is not blocked by the floor when the up vector is reversed. When it touches the ground, player_output.grounded switches to true, so this part of the problem is fixed, but the player slowly go through the floor before falling again at normal speed once it is on the other side.

@Aceeri
Copy link
Contributor

Aceeri commented Aug 15, 2023

Try adding the abs before the assert like let amount = amount.abs();

@Linentio
Copy link
Author

I still have the same problem.
But doing that is the same as placing .abs() directly inside the assert isn't it?
Here is what I did:

#[inline]
fn loosened(&self, amount: Real) -> Aabb {
    let amount = amount.abs();
    assert!(amount >= 0.0, "The loosening margin must be positive.");
    Aabb {
        mins: self.mins + Vector::repeat(-amount),
        maxs: self.maxs + Vector::repeat(amount),
    }
}

@Aceeri
Copy link
Contributor

Aceeri commented Aug 16, 2023

It wouldn't be the same thing the mins would be constrained not loosened if it was negative.

@Linentio
Copy link
Author

Of course, my bad. I was focused on the assert!(...) and did not pay attention to what was happening with the amount variable after it.
But since there is still this issue with the player going through the floor, which should be solid, I think that there is something else to fix.
If you have any ideas I'm interested, as I have very little knowledge on how rapier works under the hood, and in any case I'll try to investigate when I've got some time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants