So I’m trying to use GetContacts to get the normals of all colliders in contact with the rigidbody of choice. For some reason though it seems like the results it’s giving me don’t represent the current state of the rigidbody, but rather it’s state before Unity’s internal physics update last Physics Loop.
My current assumption as to how GetContacts work is that it’s updated sometime during OnCollision thus the progression would be…
Internal Physics Update (Object is moved)
Trigger Check
Collision Check (Contacts are Updated)
----New Physics Loop----
Use Get Contacts In FixedUpdate get the results of the updated collisions.
GetContacts always returns the current state of contacts, we don’t store the previous set anywhere so it just can’t be true.
The MonoBehaviour.FixedUpdate is called before the physics is simulated when you’re not manually simulating physics. If you perform a GetContacts or any spatial query or read the body positions (etc) then you’re getting the previous simulation step.
Let’s say on Frame 0 my rigidbody is in contact with the “Ground” (some Collider below it) and I set it’s y velocity to something like 15 in FixedUpdate.
In Frame 1, the rigidbody should be slightly just slightly airborne (having moved 15 * Time.fixedDeltaTime units upward last frame)
If I use GetContacts in Frame 1, I should expect no Contacts. Correct?
In frame 0, my rigidbody is standing still on a ground collider. Collider2D.GetContacts returns two contact points, both with the ground collider. So far so good.
In frame 1, my rigidbody is airborne (Y coordinate more than 0.2 units higher). Collider2D.GetContacts returns almost exactly the same two contact points as in frame 0: same point and separation values, different (and correct) relativeVelocity value.
In my case, I’m calling Collider2D.GetContacts from my own PlayerLoopSystem that gets executed at the end of the “FixedUpdate” parent system, i.e. right after the “ScriptRunDelayedFixedFrameRate” system. Physics2D simulation step has already happened at that point.
Box2D (Unity 2D Physics) calculates new contacts, updates/deletes exising ones at the start of the simulation step. There’s no bug in GetContacts, it simply returns existing contacts in Box2D. It’s the same with IsTouching which just looks at existing contacts for instance. Box2D does not calculate contacts at the end of the simulation step.
The misconception about contacts are that they represent where the body is currently in contact but they’re actually how the body was contacting at the start of the simulation step prior to any movement and the solver calculating a response based upon those contacts. Contacts inform you that it did contact, not that this is the absolutely current state of play. Same with OnCollisionEnter2D for instance, it doesn’t mean it’s currently in contact, it means it did contact and it may well have been a transient contact. Next frame you’ll get an OnCollisionExit2D.
For instance, if you’re in contact and run the simulation step, then the contact will be updated and show a contact. The body then might move (let’s say you added an impulse upwards) and the solver will deal with that but you’ll be left away from the contact. This’ll contact will be removed during the next simulation step.
Box2D could calculate contacts at the start AND at the end of the simulation step so it always has the correct contacts prior to solving and leaves with the most current ones but it doesn’t do that due to performance issues. It could do it only at the end but that also causes other subtle issues such as (for instance), if you were to place a collider overlapping the ground then run the simulation step, the solver wouldn’t solve this ground overlap because there’s no conacts to be solved as they’d only be created at the end of the simulation step thus it’d only be solved next simulation step.
It’s set-up to start with the best info so calculates contacts at the start. This introduces a latency but it means contacts do not represent contacts at the current position but the last one as posiion/velocity integration happens after that. Mostly this is seen when contacts are destroyed i.e. you jump away from a surface.
I think I misread/misunderstood the original poster here as that may have been what they were referring to.