OnCollisionEnter fires, but OnCollisionExit does not

I have code that looks like this:

void OnCollisionEnter2D(Collision2D collider)
{
  //"Blast" the object backwards on collision
  rigidbody2d.velocity = new Vector3(-3.5f, 4f, 0f);

  collider2d.isTrigger = true;
}

void OnTriggerExit2D(Collider2D collider)
{
  Debug.Log("OnTriggerExit2D Here!");
}

void OnCollisionExit2D(Collision2D collider)
{
  Debug.Log("OnCollisionExit2D Here!");
}

So the gist is that on collision, I set the velocity of the object to blast backwards on collision, and turn the collider into a trigger.

Technically when this happens depending how fast the code to switch isTrigger = true; is run, either OnTriggerExit2D will run, or OnCollisionExit2D will run, right? One of which must run, right!?

However what I’m seeing is that neither of them will run and I do not get either of the Debug.Log() calls.

This was working perfectly fine on Unity <4.5.1. At some point (I believe it’s 4.5.2 that broke it, but not too sure which version)

Any idea what might have changed and why this is happening?

First of all, your code isn’t compiling*, but I guess you wrote it from memory instead of copying it directly, so I’ll just assume everything’s in order.

I checked what was happening, and you’re completely correct, neither of the exit messages are fired. OnCollisionExit does fire if you don’t turn the collider into a trigger. If you make a coroutine that delays adding the force until the next frame, you get an OnTriggerEnter, then an OnTriggerExit:

void OnCollisionEnter2D(Collision2D collider)
{
    Debug.Log("On collision enter 2D");

    //"Blast" the object backwards on collision
    //rigidbody2D.velocity = new Vector2(-3.5f, 4f);
    collider2D.isTrigger = true;

    StartCoroutine(Bounce());
}

IEnumerator Bounce()
{
    yield return null;
    rigidbody2D.velocity = new Vector3(-3.5f, 4f, 0f);
}

void OnTriggerExit2D(Collider2D collider)
{
    Debug.Log("OnTriggerExit2D Here!"); 
}

The really strange thing here is that if you’re using 3D components, all four messages are fired without the need for a coroutine to delay anything. You get a Collision enter, then a trigger enter, then a collision exit, then a trigger exit. It seems like that in the 3D world, if an object is turned from a non-trigger to a trigger while colliding with something, OnTriggerEnter is immediately fired, and after that OnCollisionExit fires. Finally the Trigger exit fires when the object moves away from the other collider again. Meaning that where you get four distinct messages in 3D, you get a single one in 2D. This is really strange, and probably a bug.

As I said, everything works if you delay setting the bounce for a frame, the trigger exit is fired, just after an enter. A better suggestion is perhaps just to do the thing you want to do on the exit straight away, or if it needs to wait for a frame or two, just put it in a coroutine. Hope that helps, I’ll probably make a bug report about this.

*Both OnCollisionEnter and OnCollisionExit needs to have a Collision2D parameter (not Collider2D), and you have written collider2D and rigidbody2D with a small d. Finally, the velocity of a Rigidbody2D needs to be a Vector2, not a Vector3. That last part doesn’t prevent anything from working, but you don’t need that extra 0.