Best way to handle several collisions on the same frame

I’m writing a system where I want to react to 2D collisions between a Rigidbody2Ds and Collider2Ds by modifying the Rigidbody’s velocity in a way that’s not possible to do by just messing with PhysicsMaterial2D’s.

This means that I want to look at all the Collisions that happen in a frame between the Rigidbody2D and other things, take all of them into account, and then act on that. The problem is that what I get from Unity is one OnCollisionEnter2D for each object, and no information about how many of them there are.

So if I hit a corner where two colliders meet, and intersect with both of the colliders on the same frame, I get one collision with one object, and a different collision with the second object:

The builtin physics handles this perfectly - with a 2D material with bounciness 1 and 0 gravity on the ball, if it’s moving with velocity (10, 10) before the collision, it’ll move with exactly (-10, -10) after the collision. But, as I said, I need to do this in script instead for gameplay reasons.

If I look at the Order of execution for event functions page, it seems like my best bet is to collect all of the collisions in OnCollisionEnter (copy values so I can keep reuseCollisionCallbacks) and then apply them in a coroutine that’s yielding a WaitForFixedUpdate. Then I know that the new values will be correct in FixedUpdate calls.

That feels a bit clunky, though! Is there some better way to collect information about all the physics interactions an object was involved in during a frame? Is the work with the contact dispatches that’s being done for 3D also being done for 2D, as that’d be very applicable here?

You want to handle the collision response yourself? If so, use a Kinematic Rigidbody2D and turn-on Rigidbody2D.useFullKinematicContacts. You’ll get callbacks then and can access all contacts i.e. Collision2D.contactCount and Collision2D.GetContacts.

Obviously a Dynamic body has already had its collision response applied during a callback.

That’s probably going to help a lot. I’m not quite sure if it gets me all the way there - you still get two callbacks on the same physics frame if you hit two different objects on that frame, right?

You’ll get a callback for each collider pair that come into contact so if you hit two colliders, you’ll get two callbacks. You get the exact same behaviour as if it were a Dynamic Rigidbody2D but there’s just the usual no collision response on the Kinematic body.

Likewise you can simulate physics and just get all the contacts on the Rigidbody2D or any individual Collider2D too in one go.

Its a bit wonky but a decent pattern to process this stuff in Unity is to simply accumulate all the collisions you care about and process them all at once.

I had to do this for my Jetpack Kurt game to properly handle slamming down on the ground. I needed to balance the effects of impulse applied across any number of contacts in a given frame. Otherwise if you slammed two colliders into the ground you would take double the damage vs one collider.

I think I sorted the damage contacts (from all colliders this entire frame) from biggest to littlest, then only consider the second plus half the first or something like that.

There’s also a temporal component as subsequent impacts, as long as they are smaller, are drastically discounted if they happened within the next frame, which addressed the impact-nearly-flat-but-not-quite.

Just to add, if you have a list of colliders you’re in contact with, you can perform Physics2D.Distance (there’s Collider2D/Rigidbody2D Distance too) to help you solve the collisions too. The returned ColliderDistance2D should contain everything you need.

Okay, that’s really cool! I’ll take it for a spin!

1 Like