bevy_rapier icon indicating copy to clipboard operation
bevy_rapier copied to clipboard

Add `Grounded` marker for `KinematicCharacterController`

Open Jondolf opened this issue 1 year ago • 1 comments

A pretty common question I see people ask is "how do I know if my character is grounded?"

This is currently done by querying for the KinematicCharacterControllerOutput component and checking the is_grounded property.

fn log_grounded(controllers: Query<(Entity, &KinematicCharacterControllerOutput)>) {
    for (entity, output) in &controllers {
        println!("Entity {:?} touches the ground: {:?}", entity, output.grounded);
    }
}

However, in my opinion, a more idiomatic approach would be a Grounded marker component. Paired with the Without filter, it would make some systems more ergonomic while also reducing the amount of iteration. For example, a simple jumping system could filter out entities that aren't grounded:

fn jump(
    mut jump_event_reader: EventReader<JumpEvent>,
    mut controllers: Query<&mut Velocity, With<Grounded>>,
) {
    for event in jump_event_reader.read() {
        for (jump_impulse, mut velocity) in &mut controllers {
            // A KCC isn't controlled like this, but imagine it works for demonstration purposes.
            velocity.linvel.y = event.jump_impulse;
        }
    }
}

For the boolean value, the idiomatic approach is to use Has:

fn log_grounded(controllers: Query<(Entity, Has<Grounded>)>) {
    for (entity, is_grounded) in &controllers {
        println!("Entity {:?} touches the ground: {:?}", entity, is_grounded);
    }
}

If desired, the name could also be more specific like CharacterGrounded or even KinematicCharacterGrounded, but I think just Grounded is fine too.

Jondolf avatar May 09 '24 16:05 Jondolf

The grounded field of KinematicCharacterControllerOuptput is not very useful on its own, as it fluctuates a lot even when the character is not moving.

For example, the character_controller3 example uses a timer to consider a character grounded and avoid missing jump inputs

so having it as a marker component in fact be great, but it would require some options to define what is grounded or not, like with a time threshold, or frame average, etc

ManevilleF avatar Jan 19 '25 13:01 ManevilleF