Physics - how do I set the following:

  1. Define the movement for a rigid body’s velocity
  2. If two rigidbody’s colliders collide, the rigid bodies stop and do not pass through each other
  3. When scenario #2 occurs involving a non-moving, but not static rigidbody, NO PUSHING OCCURS.

Basically, I want to control my own movement and use Unity’s physics to prevent movement, but NEVER to trigger new movement.

I’ve tried setting the velocity on the objects every frame… but objects still end up pushing each other around.

A simple way to do this:

void OnCollisionEnter2D(Collision2D other) {
  other.GetComponent<Rigidbody2D>().isKinematic = true;
  GetComponent<Rigidbody2D>().isKinematic = true;
  other.GetComponent<Rigidbody2D>().isKinematic = false;
  GetComponent<Rigidbody2D>().isKinematic = false;
}

Maybe not the most efficient way to do it, but it should work…

I don’t understand how the above would work. Can you explain? In the end, don’t both continue reacting as normal?

Darn, turns out it doesn’t work with the 2D physics. I did something similar with the 3D physics way back, and just converted that. Unfortunately I didn’t test it until now, which was stupid.

What it is supposed to do is turn the colliding objects into kinematic objects (static might have been better), which should turn off movement and rotation. Then they are turned back to non-kinematic and they should be free to react to forces again. But it doesn’t seem to work properly with 2D physics. It kinda works, but after some research I see why it doesn’t work completely.

So, I’m sorry for that suggestion :frowning:

So, I did some tests. I had a number of boxes moving about and tried to find a way to minimize reactions on collision.

I got the best result when I used a Rigibody2D set to Kinematic, Simulated on and Use Full Kinematic Contacts to on. Then I placed a tiny script on the objects:

using UnityEngine;

public class test : MonoBehaviour
{
    void OnCollisionEnter2D()
    {      
        GetComponent<Rigidbody2D>().velocity = Vector2.zero;
    }
}

WIth low speeds this works perfectly. With higher speeds there might be some slight overlap, since they don’t push apart. However, this could be compensated for by making their colliders slightly larger.

When I tried this with Kinematic turned on, the objects didn’t collide with each other. Did this work for you?

Yes, but you have to turn on both Simulated and Use Full Kinematic Contacts.

If you were to use continuous collision detection (more expensive) then the colliders in question won’t be overlapping when you zero the velocties.

Note that the ‘Simulated’ should already be on by default otherwise nothing would happen anyway. :slight_smile:

If you set the Rigidbody2D bodyType to Kinematic and use kinematic contacts then you will get callbacks when its colliders contact any other bodyType but with them being kinematic the physics system will not apply forces to them. Note that you are still free to set the linear/angular velocity on these bodies as you would a Dynamic bodyType.

The above set-up is new and it’s effectively the equivalent of using dynamic triggers but with the advantage you get full collision callbacks including contact points.

Okay. Nervous, but will try this out.

1 Like

Weird, I did try that and I did get slight overlaps any way. (I guess I shouldn’t have delete my test scene, now I have to redo it to try again :slight_smile: )

That is odd indeed. Box2D performs a sweep during the update from the old to new position/rotation and moves the body to the correct position rather than with discrete where it leaves it in the new position and solves the overlap using impulse forces.

Here is a screenshoot of my new test scene:

I did use a pretty fast speed, just to make sure that the overlaps was more visible. However, I do get overlaps at smaller speeds as well. On of the scripts set a start velocity of the Rigidbody2D, nothing more and the other script does set the velocity to zero at OnCollisionEnter2D.

I found it a bit weird that Continuous Collisions didn’t get nice, precise intersections.

It’ll obviously only work if the Rigidbody2D is moving using its velocity (or using Rigidbody2D.MovePosition).

I’ll do a check of my own soon to ensure that the time-of-impact stuff is indeed working for kinematic bodies.

Yes, I did only set an initial velocity. All the brown object started a bit away and got a velocity towards the gray object (which was stationary). Once I did the Rigidbody2D.velocity change I didn’t touch it again until the collision. So there shouldn’t be anything else but the physics at work.

1 Like

I’ve just duplicated the issue. I’ll dig further to see why time-of-impact isn’t working.

1 Like

Okay so I just found an issue with the time-of-impact code for kinematic bodies using full-contact processing. I’ll work on a fix for that later. Box2D sets mass and inertia to zero for static/kinematic bodies which is why in a lot of its code, nothing affects it as calculations end up as zero. I’ve had to bypass some of this, seems like I missed something in the TOI code.

2 Likes

oh thank god, do you think this bug will get fixed by June?

Okay, I tried this out.

What happened was the callback was correctly called when I intersected another collider object… but it didn’t stop the objects from moving through each other if the velocity is updating during the FixedUpdate() function.

Look, what I want is simple:
If any objects try to push through each other, they stop. They don’t move each other. They just stop.

Why can’t this be easy? I am angry and frustrated.

I want to set my desired velocity in one place. Then be told if I hit something - and if I’m hitting something NOT move through it. This can’t be rocket science.

Instead, it’s telling me that I hit something, but continues to push through it. That’s because the OnCollisionEnter2D function is only fired once when the first touch happens, not every time.

Now, to get what I want, I need to be doing constant movement checks… keeping track of all of the contact points… FUCK THIS.

I just want my objects to not move through each other and not push each other around.

@MelvMay here’s an abbreviated version of what I’m doing:

Kinematic, Use Full Kinematic Contacts, Simulated, etc. Just like you mentioned in the 2d build thread

... class... MonoBehaviour etc
{
   
    public virtual void OnCollisionEnter2D(Collision2D coll)
    {
        MyRigidBody.velocity = Vector2.zero;
    }

    private Vector3 _lastVelocity;

    void FixedUpdate()
    {
          // Apply the final velocity
        _lastVelocity = GetCurrentVelocity();  // This is off elsewhere in the game scripts. Just trust me, it provides a non zero vector3. 
        MyRigidBody.velocity = _lastVelocity;

        // I actually want to freeze movement if the body's velocity is almost zero...
        if ( _lastVelocity.magnitude <= 0.05f )
            MyRigidBody.constraints = RigidbodyConstraints2D.FreezeAll;
        else
            MyRigidBody.constraints = RigidbodyConstraints2D.FreezeRotation;

        int contactCount = MyRigidBody.GetContacts(contacts);
        if ( contactCount > 0 )
        {
            Debug.LogFormat("Contact count: {0}", contactCount);
            MyRigidBody.velocity = Vector3.zero;
        }
}

I am getting 6-12 contact point 2d objects.

However, instead of the objects stopping (see Physics - how do I set the following: - Unity Engine - Unity Discussions) - the two colliders slowly push through each other like molasses.

I. Just. Want. Hard. Stops.

Why is this so complex to achieve.