Search Unity

Question In 2D, how to stop colliders from overlapping when kinematic rb is pushing dynamic rb? (incl. gif)

Discussion in 'Physics' started by spvn, Jun 22, 2021.

  1. spvn

    spvn

    Joined:
    Dec 10, 2013
    Posts:
    80
    overlapping.gif

    In the above gif, both squares have a rigidbody 2D and box collider 2D. The larger square on the left is "Dynamic", affected by gravity, and does not have any scripts on it. The smaller square on the right is "Kinematic" and has a script on it that calls Rigidbody2D.MovePosition() every FixedUpdate(). In the gif, I've paused the game to show that while the kinematic rb is pushing the dynamic rb there's a clear overlap in the colliders. What's the best way to mitigate this overlap while the boxes are moving. The moment MovePosition() stops being called, the overlap is gone. But I want to be able to push a dynamic rb with a kinematic rb without any overlap. Is this possible?

    I've also already tried the usual things like collision detection being Continuous and not Discrete. Any other tips?
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Use Continuous Collision detection.

    EDIT: Seems you have tried continuous but note that any collision overlaps take time to solve. You are causing the overlaps and you are asking for the solver to solve those during a single simulation step. You can control the speed of this overlap solving using Physics2D.baumgarteScale (or Physics2D.baumgarteTOIScale for continuous) but doing it too quick means that the 2D physics engine can overshoot the separation.

    You are also free to give the solver more time to solve it by increasing the solver iterations from the defaults but it just seems like you're moving so fast that it just cannot solve it quick enough. It's also note clear on the scale of these objects. The Kinematic might be moving at the speed of sound here as I cannot see the units.

    If you can host a simple reproduction then I'd be happy to take a look for you.
     
  3. spvn

    spvn

    Joined:
    Dec 10, 2013
    Posts:
    80
    Right totally forgot to mention the scale. The bigger box is 5,5,5 and the smaller box is 3,3,3. The code used to move the square is


    rb.MovePosition(transform.position + Vector3.left * Time.fixedDeltaTime * 100);


    Regarding the baumgarte variables, thanks for some explanation. I was messing around with them but got weird results and couldn't tell what they were doing. DIdn't realise one was for discrete and the other was for continuous. However I'm still a bit unsure about what the values mean. E.g. if I decrease the baumgarteTOIScale, what exactly does that mean? That overlaps will be resolved "faster"? What does them being resolved faster mean?

    In essence, should I be trying to increase or decrease the baumgarteTOIScale to resolve this issue?

    I will try to upload a sample project when I get some time tomorrow. Just FYI this project is meant to be an "infinite runner" game. My use case is that platforms are kinematic rb and move towards the player which is a dynamic rb. But I was realising that my player was overlapping with the platforms when the game speed started going faster. I'm not missing anything more straightforward here right?
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    You're moving 100 meters/sec so 1/3 speed of sound. ;)

    Note that this is 2D so you should use Vector2.left. Also, you should always use the Rigidbody2D.position and not the Transform because the Rigidbody2D is the authority here and they won't be the same if you're using interpolation.

    Resolved faster? Well the physics knows how to resolve the overlap all at once but because of numerical precision, using a large impulse to do so means it can overshoot i.e. move too far out of overlap. A solver doesn't just look at one thing, it looks at the whole system and balances impulses.

    Know that you're also free to set velocity directly too. Doing rb.velocity = Vector2.left * 100 once will cause that Kinematic body to continue moving like that forever. No need to keep doing MovePosition calls.