- Home /
Why is OnCollisionExit2D late?
I am having a problem with the "OnCollisionExit2D" callback. It seems to be occurring one physics update too late.
According to the documentation, it simply calls when a collider is no longer touching another. According to the documentation on execution order, it occurs after the physics update.
So if I move a Rigidbody2D in FixedUpdate, it would seem that this is the sequence of events that should happen:
Set Rigidbody2D velocity in FixedUpdate
Internal physics update (rigidbody moves)
OnCollisionExit2D is called
However, the ACTUAL sequence of events is something like this:
Set Rigidbody2D velocity in FixedUpdate
Internal physics update (rigidbody moves)
OnCollisionStay2D is called
FixedUpdate
OnCollisionExit2D is called
Here is some test code I wrote to confirm this problem:
int timesteps = 0;
Rigidbody2D _rigidbody;
// Use this for initialization
void Start()
{
_rigidbody = gameObject.GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void FixedUpdate()
{
timesteps++;
Vector3 velocity = new Vector3();
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.LogFormat("Moved {0}", timesteps);
velocity.y += 10000;
}
velocity.y -= 1;
_rigidbody.velocity = velocity;
}
private void OnCollisionEnter2D(Collision2D collision)
{
Debug.LogFormat("Enter {0}", timesteps);
}
private void OnCollisionStay2D(Collision2D collision)
{
Debug.LogFormat("Stay {0} {1}", timesteps, transform.position);
}
private void OnCollisionExit2D(Collision2D collision)
{
Debug.LogFormat("Exit {0}", timesteps);
}
Here is the logging for this code:
Why is this happening? Shouldn't the physics engine be aware that it stopped colliding? It seems like it is calling the OnCollisionExit2D on the physics update AFTER it stops colliding, rather than the same one. Is this always the case? Is there some way I can change this behavior? My game requires that the characters always know if they are on the ground after the physics update. Can/ should I use raycasting instead?
Well.. yes, using Physics2D.Raycast can give you RaycastHit2D which contains the same information than Collision2D.
Hi I have the exact same issue.
FixedUpdate : I'm changing velocity
(internal physics update)
FixedUpdate : I'm getting an updated rigidbody position, it has moved away from the touched collider, but Physics still 'think' it collides (tested using IsTouching).
(internal physics update)
OnCollisionExit2D : we now get the information that it has moved away from the touched collider
FixedUpdate : Now IsTouching returns false, it's one FixedUpdate too late !
In the FixedUpdate where your rigidbody position has been updated, the collision state is wrong (by listening to callbacks Enter2D/Exit2D, or by calling IsTouching method) because not updated yet (while the position has been !).
I have reproduced this behavior in a new project.
That's really annoying.
Answer by Tortuap · Oct 25, 2017 at 07:48 PM
I have created a ticket for that issue : https://fogbugz.unity3d.com/default.asp?962743_hdc18gmnt0jcl55j
Also I found those possible workarounds :
method OverlapCollider gives a correct result
method Distance gives a correct result
method Raycast gives you RaycastHit2D which contains the same info than Collision2D
Also note that when teleporting the rigidbody using rigidbody.position, the issue does not happen. While issue is produced when moving the rigidbody using rigidbody.AddForce, rigidbody.velocity or rigidbody.MovePosition.
Your answer
Follow this Question
Related Questions
Player appears on top of an Kinematic object or underneath it when walking forward. 0 Answers
How do I get collisions between Tilemap Collider 2d and a Kinematic Rigidbody 2d? 1 Answer
Rigidbody2D.attachedColliderCount question C# 0 Answers
Reset Rigidbody2D rotation after collision 2 Answers
Buggy touch controls? 0 Answers