avian3d::collision::hooks

Trait CollisionHooks

Source
pub trait CollisionHooks:
    ReadOnlySystemParam
    + Send
    + Sync {
    // Provided methods
    fn filter_pairs(
        &self,
        collider1: Entity,
        collider2: Entity,
        commands: &mut Commands<'_, '_>,
    ) -> bool { ... }
    fn modify_contacts(
        &self,
        contacts: &mut ContactPair,
        commands: &mut Commands<'_, '_>,
    ) -> bool { ... }
}
Expand description

A trait for user-defined hooks that can filter and modify contacts.

This can be useful for advanced contact scenarios, such as:

  • One-way platforms
  • Conveyor belts
  • Non-uniform friction and restitution

Collision hooks are more flexible than built-in filtering options like CollisionLayers, but can be more complicated to define, and can have slightly more overhead. It is recommended to use hooks only when existing options are not sufficient.

Only one set of collision hooks can be defined per broad phase and narrow phase.

§Defining Hooks

Collision hooks can be defined by implementing the CollisionHooks trait for a type that implements SystemParam. The system parameter allows the hooks to do things like access resources, query for components, and perform spatial queries.

Note that mutable access is not allowed for the system parameter, as hooks may be called during parallel iteration. However, access to Commands is provided for deferred changes.

Below is an example of using collision hooks to implement interaction groups and one-way platforms:

use avian3d::prelude::*;
use bevy::{ecs::system::SystemParam, prelude::*};

/// A component that groups entities for interactions. Only entities in the same group can collide.
#[derive(Component)]
struct InteractionGroup(u32);

/// A component that marks an entity as a one-way platform.
#[derive(Component)]
struct OneWayPlatform;

// Define a `SystemParam` for the collision hooks.
#[derive(SystemParam)]
struct MyHooks<'w, 's> {
    interaction_query: Query<'w, 's, &'static InteractionGroup>,
    platform_query: Query<'w, 's, &'static Transform, With<OneWayPlatform>>,
}

// Implement the `CollisionHooks` trait.
impl CollisionHooks for MyHooks<'_, '_> {
    fn filter_pairs(&self, collider1: Entity, collider2: Entity, _commands: &mut Commands) -> bool {
        // Only allow collisions between entities in the same interaction group.
        // This could be a basic solution for "multiple physics worlds" that don't interact.
        let Ok([group1, group2]) = self.interaction_query.get_many([collider1, collider2]) else {
           return true;
        };
        group1.0 == group2.0
    }

    fn modify_contacts(&self, contacts: &mut ContactPair, _commands: &mut Commands) -> bool {
        // Allow entities to pass through the bottom and sides of one-way platforms.
        // See the `one_way_platform_2d` example for a full implementation.
        let (entity1, entity2) = (contacts.collider1, contacts.collider2);
        !is_hitting_top_of_platform(entity1, entity2, &self.platform_query, &contacts)
    }
}

The hooks can then be added to the app using PhysicsPlugins::with_collision_hooks:

fn main() {
    App::new()
        .add_plugins((
            DefaultPlugins,
            PhysicsPlugins::default().with_collision_hooks::<MyHooks>(),
        ))
        .run();
}

This is equivalent to manually replacing the default BroadPhasePlugin and NarrowPhasePlugin with instances that have the desired hooks provided using generics.

§Activating Hooks

Hooks are only called for collisions where at least one entity has the ActiveCollisionHooks component with the corresponding flags set. By default, no hooks are called.

// Spawn a collider with filtering hooks enabled.
commands.spawn((Collider::capsule(0.5, 1.5), ActiveCollisionHooks::FILTER_PAIRS));

// Spawn a collider with both filtering and contact modification hooks enabled.
commands.spawn((
    Collider::capsule(0.5, 1.5),
    ActiveCollisionHooks::FILTER_PAIRS | ActiveCollisionHooks::MODIFY_CONTACTS
));

// Alternatively, all hooks can be enabled with `ActiveCollisionHooks::all()`.
commands.spawn((Collider::capsule(0.5, 1.5), ActiveCollisionHooks::all()));

§Caveats

Collision hooks can access the ECS quite freely, but there are a few limitations:

  • Only one set of collision hooks can be defined per broad phase and narrow phase.
  • Only read-only ECS access is allowed for the hook system parameter. Use the provided Commands for deferred ECS operations.
    • Note that command execution order is unspecified if the parallel feature is enabled.
  • Access to the ContactGraph resource is not allowed inside CollisionHooks::filter_pairs. Trying to access it will result in a panic.
  • Access to the ContactGraph resource is not allowed inside CollisionHooks::modify_contacts. Trying to access it will result in a panic.

Provided Methods§

Source

fn filter_pairs( &self, collider1: Entity, collider2: Entity, commands: &mut Commands<'_, '_>, ) -> bool

A contact pair filtering hook that determines whether contacts should be computed between collider1 and collider2. If false is returned, contacts will not be computed.

This is called in the broad phase, before the ContactPair has been computed.

The provided Commands can be used for deferred ECS operations that run after broad phase pairs have been found.

§Notes
Source

fn modify_contacts( &self, contacts: &mut ContactPair, commands: &mut Commands<'_, '_>, ) -> bool

A contact modification hook that allows modifying the contacts for a given contact pair. If false is returned, the contact pair will be removed.

This is called in the narrow phase, after the ContactPair has been computed for the pair, but before constraints have been generated for the contact solver.

The provided Commands can be used for deferred ECS operations that run after the narrow phase has computed contact pairs and generated constraints.

§Notes
  • Only called if at least one entity in the contact pair has ActiveCollisionHooks::MODIFY_CONTACTS set.
  • Only called if at least one entity in the contact pair is not RigidBody::Static and not Sleeping.
  • Impulses stored in contacts are from the previous physics tick.
  • Command execution order is unspecified if the parallel feature is enabled.
  • Access to the ContactGraph resource is not allowed in this method. Trying to access it will result in a panic.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl CollisionHooks for ()

Implementors§