dimforge / rapier

2D and 3D physics engines focused on performance.
https://rapier.rs
Apache License 2.0
3.89k stars 242 forks source link

World.intersectionsWithPoint sometimes fails mysteriously #487

Closed viridia closed 1 year ago

viridia commented 1 year ago

Apologies for the long message, we chatted about this on the discord.

The symptoms I am seeing is that intersectionsWithPoint() sometimes doesn't return any results (it never calls the callback) even though it should. Unfortunately, I have not been able to come up with a small example program that reproduces the error (I've tried).

Here's the setup: In my dungeon, there is a pressure plate trap. The trap has a collision box which is triggered when an actor's origin point is within the collision box. The collision box's collision groups are set up so that it does not collide with anything - it is only used for intersection queries.

Each animation frame, before I call world.step(), I call world.intersectionsWithPoint() for each actor, to test whether an actor's origin point is inside the collision box. In other words, I am not testing for intersections with the actor's shape (which is what a sensor would normally do), but only for a single point - the idea being that the pressure plate is only active when the character's center of gravity is above the plate.

This works only when the actor is moving under their own power, but not when the actor is still or being pushed by another actor. The reason for this is due to the way I handle movement: when an actor is following a pathfind route, the actor's RB is kinematic. When an actor is doing anything else - standing still, falling, or being pushed - the kinematic RB is deleted from the world and replaced by a dynamic RB.

In other words - it seems as if intersectionsWithPoint only calls the callback for a collider, if that collider is not intersecting with an actor's dynamic collider. If it's intersecting with nothing, or an actor's kinematic collider, then results are returned as expected.

At this point I am not sure what else to try. The problem is completely reproducible in my complex game, but I have not been able to reproduce it in a simple test app. I've tried messing around with collision groups and such, but so far none of my experiments have paid off. If I disable the code that switches actors between dynamic and kinematic - so that the actor is always a kinematic RB - then the pressure plate works correctly as I would expect. This is truly weird because the collision box and the actor's RB have no overlap in their collision groups, and should have no effect on each other.

viridia commented 1 year ago

I figured it out, finally - turns out that the Y-coordinate of the actor is slightly different between dynamic and kinematic. I'll close the issue.