Future features in the readme lists Collision Filtering as something not yet implemented and I would like to get the ball rolling if possible.
Topics discussed in the xpbd help channel on Discord
Some topics that were discussed on Discord included:
- Global physics hooks that can iterate over all collisions
- Per-entity filter components
- Filtering collisions with entities by EntityId
- Filtering collisions by predicate
- Being able to modify the individual contacts
- The possibility of being able to use one-shot systems in the future
- The possibility of being able to use entity relations to allow more efficient filtering
Global Physics hooks
Adding a schedule after the SubstepSet::NarrowPhase
, and exposing a way to filter collisions from the Collisions
resource gives a very open-ended and straightforward way to allow for modifying collisions.
I've got a working example on this fork here.
I'm in two minds about whether it's worth the schedule to have built-in sets (e.g. First
, Filter
, Modify
, Last
), or whether that complexity should be left up to the user. I can see a potential want to pre-filter collisions with faster filters before any slower ones execute, for example.
Per-entity filter components
@Jondolf suggested something in the following form:
ContactFilter::new()
.with_excluded_entities([...])
.with_predicate(|mut contact: ContactData| {
// Modify contact (optional)
contact.penetration = 0.1;
// Return the contact or use None to ignore contact
Some(contact)
}),
It was also suggested that some form of combination rule may be needed to handle when two entities with conflicting filter predicates are present.
Modifying individual contacts
Being able to modify the individual contacts is desirable. Therefore, being able to return Some(contact)
from a post-processing step is more useful than only being able to remove or keep collisions.
One-shot systems
@Jondolf showed the following code on Discord as something that it would be nice to be able to do. There was discussion about how this may not be possible with one-shot systems, but using run_system_with
* may allow it as long as the overhead was acceptable.
* run_system_with
was added to bevy with this merged but unreleased-at-the-time-of-writing pull request.
fn setup(mut commands: Commands, contact_hook_pipeline: ContactHookPipeline) {
commands.spawn((
ContactHook::new(
&contact_hook_pipeline,
|In(mut contact): In<ContactData>, query: Query<&MyBundle>| {
// Modify contact, query for entities, do whatever
// Return new contact data to narrow phase; if None, skip contact
Some(contact)
}
),
));
}
Entity Relations
Something along the lines of (Body1, CollidesWith(Contacts), Body2)
was suggested by @Jondolf.
Bevy currently has a tracking issue for entity relations here: bevyengine/bevy#3742
Other notes/questions
Should filtering be treated as a separate issue from modification?
My current personal needs for collision filtering are very simplistic: I just want to implement one-way platforms, which is easily solved by the first bullet point above. I therefore have a very narrow view of what needs exist when it comes to being able to filter/modify collisions, and so would like to get input from other interested parties.
One shortfall of bevy_rapier that I would like to avoid was that it seemed impossible to register more than one set of query params to use with collision hooks because the parameters are registered on the plugin itself as a generic type. Being able to access queries while filtering and modifying collisions seems very important in an ECS.
Where to go from here
I've started work on global filters and entity-entity collision exclusion in a fork here, but am looking for input. I'd be interested in creating a pull request at some point, even if it's only for the global collision hook, as it's a small enough change that gives quite a bit of power from the get-go.