Physics, interpenetration, need an explanation

Hi everyone, first post (that I remember of anyways), long time lurker.

I’m an industry professional trying to get started in Unity and so far I’m having a lot of problems with how physics work. I hope someone can give me some answers and explanations.

I am using the 2d framework, and I’m trying to create a 2D character controller, with a square collider. The problem is that the physics seem to allow interpenetration to happen all the time. If my character simply walks on the ground and jumps around, he never lands at the exact same height. On some occasions, the character falls a bit too far and gets stuck there. I saw 2 solutions being offered on various threads.

1- Boost the physics timestep. In my opinion this is not a valid solution as it only reduces the chance of seeing that issue occur. a stable solution should work no matter what your performances are. I don’t mind my game being a bit more jaggy and less precise if the physics frame count is lower, but it should not allow my character to become stuck.

2- Use raycasts. While this is a bit better, I still do not understand why this should be needed. Ideally I expect my engine to push any colliding elements away from one another until they no longer intersect. Why does unity allow things to interpenetrate in the first place? Is there a way to do such a thing? When a collision occurs, check the contact normals, push them away following that normal, check if they still collide and so on, in a single frame (aka not waiting for the next fixed update to figure if you pushed them far enough). I know there is a script around that prevents that, but it simply nullifies an object movement if said movement would make it penetrate something else. I’d want the movement to still occur, but be shortened to get to the edge of said collision.

I did try to implement raycasts, but a couple of issues still occur. for example, if i jump on a higher platform and I hit the corner of said platform with the character’s feet, I can get stuck. I also believe that performances would quickly degrade if I had for example 50 enemies on screen, each raycasting the ground to avoid getting stuck.

So I guess my question is, why does the engine allow interpenetration, and is it possible to force any object colliding with another, to stand edge to edge with the other one, instead of being inside it?

Thank you all for your help, and please refrain from giving workarounds such as “use a capsule collider” or “don’t use unity” :wink:

My understanding is that some collider penetration is allowed because it reduces “vibration” or jitter upon low-speed collisions. Thinking through your proposal to fully push a collider away in the frame of contact, this would create a vibrating competition of forces if there is another force (ie gravity) pushing the objects together. There has to be some margin of error where the an object can come to rest relative to the one it collides with, and that margin is found inside the collider.
In the Physics Manager there is a “Min Penetration For Penalty” setting where you can tweak this margin to your liking. Very low values create vibration/jitter as mentioned above. But I don’t know if it applies to the new 2D physics or not.

My question is why your character is getting stuck. In my experience any collider will jump back outside of another as soon as any force is applied to get it moving again (ie Unity will act as though they never penetrated).
That said, this is all my experience with the regular 3D physics system and I’m unsure if the behaviour is different in Box2D. But I do wonder whether this may in fact be due to how you are approaching moving your character - perhaps in a collision or “grounded” check before allowing movement?

Given that you are dealing with a physics simulation in any case (and one that is optimized for the speed requirements of realtime gaming, not real scientific simulation), it is unreasonable to expect deterministic results. If you need that absolute determinably, then you need to abandon physics simulation and move to a deterministic system of movement. In my mind this makes boosting the physics timestep a totally reasonable expectation for a compromise.

Thanks for your reply Dasbin. I did experiment a bit more and the Min Penetration For Penalty value was as close as it gets to a fix so far. My character stands pretty much at the same height at all time. I did not experience any jittering or vibration, even at extremely low values, so everything seems perfect.

I could not determine exactly what got the character stuck, it could be as you said, a grounding issue. I moved on from a raycast solution to one based on entering and exiting collisions. By maintaining a list of “floor” elements currently colliding at a near upwards angle, I can tell if the character is colliding with one such floor, and determine if he is grounded or not, without wasting cpu cycles with raycasting.

You may also be right, maybe I’d be better off not using physics, and creating my own deterministic system. But physics simplify so much stuff :wink:
Also, don’t quote me on this, but it seems like setting a Force does get the element clear of whatever it was stuck in, but setting a velocity apparently does not. I took a look at the 2D sample available, and noticed they used a force for the jump. It seemed to work fine, but my setVelocity did not. Once again, an issue with using a realistic physics system, and trying to bend it a bit (by setting velocity instead of relying on forces).

Just a thought here regarding your grounding issue. If you follow most tutorials on this, they will tell you to cast a ray from the bottom of the character (ie his feet) down. But this doesn’t work when the point you cast from (his feet) are already a little bit inside the collider you are casting against (the ground). It will register no hit when it originates inside. It has to hit the outside edge to register.
So a simple way around this is to cast from farther up (the torso?) down the distance to his feet / the floor and check that instead.