Skip to main content

scene_queries_filters

It is common to exclude some colliders from being considered by a scene query. For example, a ray-cast performed for a character controller will usually want to skip the character itself. Sometimes, we may even want it to ignore both the character and any collider attached to a dynamic rigid-body, and ignore all sensors. To allow this filtering, most scene queries take a QueryFilter argument that lets you describe what needs to be excluded. In particular its fields:

  • flags allows you to discard whole families of colliders based on their types or their parent types (e.g. exclude all sensors and all the colliders attached to a dynamic rigid-body).
  • groups is used to apply the collision group rules for the scene query. The scene query will only consider hits with colliders with collision groups compatible with this collision group (using the bitwise test described in the collision groups section).
  • exclude_collider is the handle of one collider the query must ignore.
  • exclude_rigid_body is the handle of one rigid-body with attached colliders the query must ignore.
  • predicate is a user-defined closure to apply any filtering rule. This can be used if the other filtering options above are not flexible enough.

The exclude_collider and exclude_rigid_body fields are set to the entity of the collider or rigid-body to exclude (instead of its handle). The predicate is given the entity of each collider as well as its Rapier collider (rapier::geometry::Collider), so its shape, position, or parent can be read without any additional ECS query. Since the filter only holds a reference to the predicate closure, that closure can borrow other system parameters, e.g., a Query for reading the components of the collider's entity.

Here is an an example of usage of the query filters with ray-casting:

/* Cast a ray inside of a system. */
fn cast_ray_filtered(
rapier_context: ReadRapierContext,
player_query: Query<Entity, With<Player>>,
custom_data_query: Query<&CustomData>,
) {
let rapier_context = rapier_context.single().unwrap();
let player_handle = player_query.single().unwrap();
let ray_pos = Vec2::new(1.0, 2.0);
let ray_dir = Vec2::new(0.0, 1.0);
let max_toi = 4.0;
let solid = true;
let predicate = |entity, _collider: &_| {
// We can use a query to bevy inside the predicate.
custom_data_query
.get(entity)
.is_ok_and(|custom_data| custom_data.data == 10)
};
let filter = QueryFilter::exclude_dynamic()
.exclude_sensors()
.exclude_rigid_body(player_handle)
.groups(CollisionGroups::new(
Group::GROUP_1 | Group::GROUP_2,
Group::GROUP_1,
))
.predicate(&predicate);

if let Some((entity, toi)) = rapier_context.cast_ray(ray_pos, ray_dir, max_toi, solid, filter) {
// Handle the hit.
}
}