character_controller_filtering
It is possible to let the character controller ignore some obstacles. This is achieved by configuring the following
fields of the KinematicCharacterController component:
filter_flags: to exclude whole families of obstacles (e.g. all the colliders attached to dynamic rigid-bodies).filter_groups: to filter based on the colliders collision groups.exclude_colliders: the set of entities of colliders to ignore.exclude_rigid_bodies: the set of entities of rigid-bodies whose attached colliders must all be ignored.filter_predicate: an arbitrary closure, wrapped into aControllerFilterPredicate, to filter-out colliders based on user-defined rules. It is given the entity of each collider as well as its Rapier collider (rapier::geometry::Collider). Since it is stored in a component, this closure can't borrow any system parameter.
/* Configure the character controller filters when the collider is created. */
commands
.spawn(Collider::ball(0.5))
.insert(KinematicCharacterController {
// Ignore all the sensors and all the colliders attached to dynamic rigid-bodies.
filter_flags: QueryFilterFlags::EXCLUDE_SENSORS | QueryFilterFlags::EXCLUDE_DYNAMIC,
// The character is part of the group 1 and only interacts with the group 2.
filter_groups: Some(CollisionGroups::new(Group::GROUP_1, Group::GROUP_2)),
// Ignore the collider attached to the `platform` entity.
exclude_colliders: [platform].into_iter().collect(),
// Ignore the colliders with a ball shape.
filter_predicate: Some(ControllerFilterPredicate::new(|_entity, collider| {
collider.shape().as_ball().is_none()
})),
..default()
});
When the obstacles to ignore depend on the state of your game (e.g. to let the characters walk through the doors that
are open), it is simpler to insert the ControllerIgnored marker component on these colliders from your own systems.
A collider with this component (or attached to a rigid-body with this component) is ignored by every character
controller, as well as by the wheels of the vehicle controllers,
until the component is removed:
/// A door the characters can only walk through while it is open.
#[derive(Component)]
struct Door {
open: bool,
}
/* Hide the open doors from every controller inside of a system. */
fn update_doors(mut commands: Commands, doors: Query<(Entity, &Door), Changed<Door>>) {
for (entity, door) in doors.iter() {
if door.open {
commands.entity(entity).insert(ControllerIgnored);
} else {
commands.entity(entity).remove::<ControllerIgnored>();
}
}
}
The collider moved by the character controller (and the rigid-body it may be attached to) is always excluded automatically from the set of obstacles: there is no need to exclude it manually.