#rapier3D Ground detection

1 messages · Page 1 of 1 (latest)

normal geode
#

Hello, I'm very new to both bevy and rust but they looked really fun to mess around with so i want to give them a try
I want to make a simple 3D game and i want to get some things figured out first. I want to use RigidBody::KinematicPositionBased and KinematicCharacterController to handle player physics, and i dont know how to apply gravity to my player. The rapier docs says that u need to handle the gravity manualy but KinematicCharacterControllerOutput has a grounded bool to handle this stuff

pub struct KinematicCharacterControllerOutput {
    /// Indicates whether the shape is grounded after its kinematic movement.
    pub grounded: bool,
    /// The initial desired movement of the character if there were no obstacle.
    pub desired_translation: Vect,
    /// The translation calculated by the last character control step taking obstacles into account.
    pub effective_translation: Vect,
    /// Collisions between the character and obstacles found in its path.
    pub collisions: Vec<CharacterCollision>,
}

Im just very confused i've been trying to solve this problem for days now 🥲

shell coral
#

it should work if you build a system, which will apply a gravity vector to either the Position or Velocity based on which you want to use.
Something similar to this logic here:

translation += Vec3::Y * YOUR_GRAVITY;
normal geode
#

i need to check if the entity is grounded first

#

thats the part im stuck in xddd

#

i know i need to ray/shape cast and check if thta collides with the groud

#

i just have no clue how to acctually do iit 😅

normal geode
#

This is how i spawn my character

#
#[derive(Component)]
pub struct Character;

fn spawn_character(mut commands: Commands, scene_assets: Res<SceneAssets>) {
    let mut input_map = InputMap::default();

    for action in PlayerAction::variants() {
        input_map.insert(PlayerAction::default_keyboard_mouse_input(action), action);
        input_map.insert(PlayerAction::default_gamepad_input(action), action);
    }

    commands.spawn((
        MovingObjectBundle {
            velocity: Velocity::new(Vec3::ZERO),
            acceleration: Acceleration::new(Vec3::ZERO),
            model: SceneBundle {
                scene: scene_assets.character.clone(),
                transform: Transform::from_translation(STARTING_TRANSLATION),
                ..default()
            },
        },
        RigidBody::KinematicPositionBased,
        KinematicCharacterController::default(),
        Collider::ball(0.5),
        Restitution::coefficient(0.7),
        InputManagerBundle::<PlayerAction> {
            input_map,
            ..default()
        },
        Character,
    ));
}
#

and i move the character using its velocity

#
fn character_movement_controls(
    mut query: Query<
        (
            &mut Transform,
            &mut Velocity,
            &mut ActionState<PlayerAction>,
        ),
        With<Character>,
    >,
    keyboard_input: Res<Input<KeyCode>>,
    time: Res<Time>,
) {
    let (mut transform, mut velocity, input) = query.single_mut();

    let mut rotation = 0.0;
    let mut movement = 0.0;

    // if input.pressed(PlayerAction::Run) {
    //     println!("Running");
    // }

    if keyboard_input.pressed(KeyCode::W) {
        movement = SPEED;
    } else if keyboard_input.pressed(KeyCode::S) {
        movement = -SPEED;
    }

    if keyboard_input.pressed(KeyCode::D) {
        rotation = -ROTATION_SPEED * time.delta_seconds();
    } else if keyboard_input.pressed(KeyCode::A) {
        rotation = ROTATION_SPEED * time.delta_seconds();
    }

    transform.rotate_y(rotation);

    velocity.value = -transform.forward() * movement;
}
#

And this is the plane im using as ground

#
#[derive(Component)]
pub struct Ground;

fn spawn_plane(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    commands.spawn((
        PbrBundle {
            mesh: meshes.add(shape::Plane::from_size(20.0).into()),
            material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
            ..default()
        },
        Collider::cuboid(100.0, 0.1, 100.0),
        Ground,
    ));
}
#

@shell coral sorry for tagging you but i really can't figure this out, i need some help 😅

shell coral
#

You can probably spawn a sensor on the ground to find collisions with the ground. The bevy_ecs_ldtk crate has an implementation of a 2d platformer, which uses this approach. Though it is 2d, it might come in helpful if you read through the code that isn't specific to the ldtk implementation: https://github.com/Trouv/bevy_ecs_ldtk/tree/main/examples/platformer

GitHub

ECS-friendly ldtk plugin for bevy, leveraging bevy_ecs_tilemap - Trouv/bevy_ecs_ldtk