- Home /
Collider2D.GetContacts() Checking One Physics Step Behind
Hello,
First question here and I can't really find anything answering this specific question. I've tried to collect all the information I can about this that might be relevant and if I'm missing anything, please let me know.
Onto the question:
Is Collider2D.GetContacts() one physics step behind the Collider2D? It seems like weird behavior and I'm wondering if something I'm doing is causing this to happen.
I am trying to glean contact information by checking the collision points contained by the Collider2D itself...
// Get collider. We can promise that there's only one collider per unit.
Collider2D[] colliders = new Collider2D[1];
if (rb2d.GetAttachedColliders(colliders) != 1)
throw new System.InvalidOperationException();
Collider2D collider = colliders[0];
// DEBUG
Debug.DrawLine(collider.bounds.max, collider.bounds.min, Color.cyan, 5f);
Debug.DrawRay(collider.bounds.center, Vector2.down, Color.red, 5f);
// Collect each collision point on the collider.
ContactPoint2D[] contacts = new ContactPoint2D[20];
int contactCount = collider.GetContacts(contacts);
// Convert it to a list.
List<ContactPoint2D> contactList = new List<ContactPoint2D>();
for (int i = 0; i < contactCount; i++)
contactList.Add(contacts[i]);
// DEBUG
foreach (ContactPoint2D c in contactList) Debug.DrawRay(c.point, Vector2.up, Color.blue, 5f);
return contactList;
...then using that information to:
...detect the angle relative to the CollisionPoint2D
// Assume colliding with ground initially. downToCollisionAngle = 0;
// Iterate through all contacts and set the collision angle to the greatest value. List<ContactPoint2D> contactList = GetContactPoints(); foreach (ContactPoint2D c in contactList) { Vector2 length = c.point - prevPosition; float angle = Vector2.Angle(length, Vector2.down); downToCollisionAngle = angle > downToCollisionAngle ? angle : downToCollisionAngle;
...detect whether the point is within additional bounding conditions for grounded
// Presume not grounded upon checking. isGrounded = false;
// Iterate through all contacts and check for grounded state. List<ContactPoint2D> contactList = GetContactPoints(); foreach (ContactPoint2D c in contactList) if (c.point.y < prevPosition.y && c.point.x < prevPosition.x + (LESS_THAN_HALF * width) && c.point.x > prevPosition.x - (LESS_THAN_HALF * width)) isGrounded = true;
This seems to work... provided that the contacts given are in the same physics step as the Collider2D. I'd expect this to be a given. However, I kept running into odd behavior, and lo and behold, throwing some debug lines in...
Red: Center of the Collider2D, as gleaned from Debug.DrawLine() in GetContactPoints() Cyan: Cross-Sectional of Collider2D, as gleaned from Debug.DrawLine() in GetContactPoints() Blue: Detected Contact Point of Collider2D as gleaned from GetContacts() in GetContactPoints()
...You can see that the Blue contact points always line up with the previously checked center. (Note that these are called within OnCollisionStay2D, so if that's having an effect let me know.)
In the code, I am recording the previous Rigidbody's position to contrast, and the center lines up perfectly with the current contact, which would make sense.
This suggests to me that the contacts gleaned from GetContacts(), for whatever reason, is one physics step behind the Collider2D itself. Is there something I'm doing that's causing this? Is there a setting I haven't checked?
The Rigidbody2D is currently in continuous mode, if that helps.
Interesting issue, and it certainly is not consistent behaviour. I know it's not a solution, but maybe decreasing the physics time step (like in this answer) could mitigate the issue?
Changed the timestep, but the issue persists, just with smaller intervals.
At least it makes sense. And kind of looks pretty.