dimforge / rapier

2D and 3D physics engines focused on performance.
https://rapier.rs
Apache License 2.0
3.8k stars 236 forks source link

Kinematic character controller collision groups not working #497

Open DevinLeamy opened 1 year ago

DevinLeamy commented 1 year ago

Edit

You can fix this by adding the CollisionGroups component to the entity as well as setting the filter_groups feild inside of the KinematicCharacterController.

Overview

The KinematicCharacterController collision groups filters are not working as expected. If we assign CollisionGroups::new(Group::GROUP_1, Group::GROUP_2) to two character controllers we would not expect them to collide as per the docs:

An interaction is allowed between two filters a and b when two conditions are met simultaneously:

The groups membership of a has at least one bit set to 1 in common with the groups filter of b. The groups membership of b has at least one bit set to 1 in common with the groups filter of a.

In other words, interactions are allowed between two filter iff. the following condition is met: (self.memberships & rhs.filter) != 0 && (rhs.memberships & self.filter) != 0

However, they do collide.

Investigation

The correct QueryFilter is being sent to the KinematicCharacterController::move_shape method so, from my testing, the problem lies in there.

Example

[derive(Clone, Bundle)]

pub struct KinematicColliderBundle { pub kinematic: KinematicCharacterController, pub collider: Collider, pub collider_scale: ColliderScale, pub velocity: Velocity, pub locked_axes: LockedAxes, pub ccd: Ccd, }

impl Default for KinematicColliderBundle { fn default() -> Self { Self { kinematic: KinematicCharacterController { up: Vec3::Y, autostep: Some(CharacterAutostep { max_height: CharacterLength::Absolute(0.05), min_width: CharacterLength::Absolute(0.05), include_dynamic_bodies: false, }), ..default() }, collider: Collider::cuboid(1., 1., 1.), collider_scale: ColliderScale::Absolute(Vec3::new(1., 1., 1.)), velocity: Velocity::zero(), locked_axes: LockedAxes::ROTATION_LOCKED | LockedAxes::TRANSLATION_LOCKED_Z, ccd: Ccd::enabled(), } } }

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) .add_plugin(RapierPhysicsPlugin::::default()) .add_plugin(RapierDebugRenderPlugin::default()) .add_startup_system(setup_graphics) .add_startup_system(setup_physics) .add_system(input) .run(); }

fn setup_graphics(mut commands: Commands) { commands.spawn(Camera3dBundle { transform: Transform::from_xyz(0.0, 0.0, -30.0) .looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y), ..Default::default() }); }

[derive(Component)]

struct Controlled;

fn input( mut q_player: Query<&mut KinematicCharacterController, With>, keyboard_input: Res<Input>, ) { let mut player = q_player.single_mut();

let power = 0.1;
if keyboard_input.any_pressed([KeyCode::Up, KeyCode::W, KeyCode::Space]) {
    player.translation = Some(Vec3::new(0.0, power, 0.0));
}
if keyboard_input.any_pressed([KeyCode::Down, KeyCode::S]) {
    player.translation = Some(Vec3::new(0.0, -power, 0.0));
}
if keyboard_input.any_pressed([KeyCode::Left, KeyCode::A]) {
    player.translation = Some(Vec3::new(power, 0.0, 0.0));
}
if keyboard_input.any_pressed([KeyCode::Right, KeyCode::D]) {
    player.translation = Some(Vec3::new(-power, 0.0, 0.0));
}

}

pub fn setup_physics(mut commands: Commands) { let group = Some(CollisionGroups::new(Group::GROUP_1, Group::GROUP_2));

let mut player1 = KinematicColliderBundle {
    ..Default::default()
};
let mut player2 = KinematicColliderBundle {
    ..Default::default()
};
player1.kinematic.filter_groups = group.clone();
player2.kinematic.filter_groups = group.clone();
commands.spawn((
    Controlled {},
    player1,
    TransformBundle {
        local: Transform::from_translation(Vec3::new(0.0, 3.0, 0.0)),
        ..default()
    },
     group.unwrap().clone() // This is the fix (adding it a second time, to the entity)
));
commands.spawn((
    player2,
    TransformBundle {
        local: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
        ..default()
    },
    group.unwrap().clone() // (again)
));

}