Your concern, expressed in the comment to the first answer is valid, but the bad news is that there is no simple trick to go around it. What you should be looking for is called continuous collision detection with a simplified version described in my answer on a somewhat similar matter:
Basically, for each moving object in your scene you have to calculate
moment of next collision within the fraction of the frame 0<t0<1
,
then advance positions to this moment t0 within the frame, update
velocities due to collision and proceed further to the next collision
t0<t1<1
, until you reach time of tn=1
(end of frame), making sure
you don't get stuck in a the middle of the frame due to rounding of
calculation or "cornered" objects. For spherical colliders, that is
usually done by using capsule vs capsule (for pairs of objects)
intersection and capsule vs box for the boundaries.
In oppose to the simple engine from the answer I'm referring to, Unity has continuous collision detection.
So you can enable continuous collisions and continuous dynamic which computationally is very expensive.
You can also try using RigidBody.SweepTest which returns the closest collision information. Notice that even though there is also RigidBody.SweepTestAll, it doesn't help much. Not only because it returns only first 128 collisions, but also because it doesn't process them as there is no reflection. For physically correct behaviour you have to do what described above - advance time till the first collision and update velocities. Either with the physics engine or by yourself. This is very costly and not many games are doing that even cheating by using simplified objects (spheres are the cheapest ones as two swept spheres are two capsules and their intersection is a relatively cheap calculation), but amount of steps, especially in the "cornered" case when objects have nowhere to go and therefore are constantly colliding could be very large and such cases happen more than one can expect.
For complex objects you unlikely can do better than SweepTest, unless you trigger it based on the simpler primitives, such as Physics.BoxCast
or Physics.SphereCast
. Again, even though there are Physics.BoxCastAll
and Physics.SphereCastAll
they are not particularly useful as only first collision is guaranteed to occur. Those xxxCastAll are the functions you wrote you were looking for, so give it a try, they might work well enough for your use case.