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 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.
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.
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.
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.
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.
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.
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;
}
}