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.
- Note that command execution order is unspecified if the
- Access to the
ContactGraph
resource is not allowed insideCollisionHooks::filter_pairs
. Trying to access it will result in a panic. - Access to the
ContactGraph
resource is not allowed insideCollisionHooks::modify_contacts
. Trying to access it will result in a panic.
Provided Methods§
Sourcefn filter_pairs(
&self,
collider1: Entity,
collider2: Entity,
commands: &mut Commands<'_, '_>,
) -> bool
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
- Only called if at least one entity in the contact pair has
ActiveCollisionHooks::FILTER_PAIRS
set. - Only called if at least one entity in the contact pair is not
RigidBody::Static
and notSleeping
. - Access to the
ContactGraph
resource is not allowed in this method. Trying to access it will result in a panic.
Sourcefn modify_contacts(
&self,
contacts: &mut ContactPair,
commands: &mut Commands<'_, '_>,
) -> bool
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 notSleeping
. - 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.