'Rigidbodies touching but OnCollisionStay stops being called (Unity3D)

I want to simulate two pistons that replicates the behaviour of a balance. I'm doing this with spring joints and applying the inverse weight one another when OnCollisionStay is called. This are my pistons and their rigidbodies and joints. Are exactly the same on both.

two pistons

This is my SpringForceTransmisor.cs code: using UnityEngine;

public Rigidbody InverseJoint;

private void OnCollisionEnter(Collision collision) {
    Debug.Log("Enter");
}

private void OnCollisionExit(Collision collision) {
    Debug.Log("Exit");
}

private void OnCollisionStay(Collision collision) {
    InverseJoint.AddForce(-(collision.rigidbody.mass * Physics.gravity));
    Debug.Log("Stay");
}

And this is a video of what's happening.

So, according to the log showed on the video, OnCollisionStay() stops being called even if OnCollisionExit() had never been called. How is this possible? I've always thought that OnCollisionStay() is called every frame from OnCollisionEnter frame and OnCollisionExit frame.

Can anyone shed some light about what's going on here?



Solution 1:[1]

According to the documentation on OnCollisionStay, it says:

OnCollisionStay is called once per frame for every collider/rigidbody that is touching rigidbody/collider.

Unfortunately, this is not true sometimes. The OnCollisionStay function is called few times in some cases and the call is then stopped. This is either a long time bug that has not been fixed for years or the documentation is wrong.

My usual advise to people is to abandon the OnCollisionStay function and simply set a boolean variable to true in the OnCollisionEnter function then set it to false in the OnCollisionExit function. You can then use the Update function as the OnCollisionStay function by checking that boolean variable in the Update function.

public Rigidbody InverseJoint;

bool collisionStay = false;
Collision collision = null;

private void OnCollisionEnter(Collision collision)
{
    Debug.Log("Enter");
    collisionStay = true;
    this.collision = collision;
}

private void OnCollisionExit(Collision collision)
{
    Debug.Log("Exit");
    collisionStay = false;
    this.collision = collision;
}

void Update()
{
    if (collisionStay)
    {
        InverseJoint.AddForce(-(collision.rigidbody.mass * Physics.gravity));
        Debug.Log("Stay");
    }
}

Solution 2:[2]

The answer to your question would become obvious if you included in the video the part, where the "Enter" is being registered.

Now to explain what is happening, let me show an example on a traingulated sphere . Here is how it looks like (with some triangles intentionally made invisible).

(primitive sphere mesh in unity)

Keep in mind that it is hollow, all it essentially is are a bunch of points that form triangles. Now say this is a mesh for some mesh collider component. If any other collider interacts with this sphere_mesh_collider, the only way for unity to detect it is by checking for the triangles of those two colliders having intersections. This is to say that ANY OTHER area that is not covered INSIDE the triangles will not be checked. In other words the volume of my sphere here will never detect collisions (nor call the collision stay, but the collider havent exited either, so neither it calls exit).

That is what I think is happening in your case, although I can not say for certain because I do not see the whole process of colliders starting to interact (Enter) and than coming apart (Exit).

Edit: You can easily observe this if you enable unity wireframe (or shaded wirefram) in the editor window.

Solution 3:[3]

Another note from the Unity documentation:

Note: [...] Collision stay events are not sent for sleeping Rigidbodies.

You could try setting Rigidbody.SleepThreshold to zero to see if that solves your problem.

Solution 4:[4]

Just solved this myself. This is because your rigidbodies are sleeping, try setting the rigid body sleep to "Never sleep" and it will work.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Programmer
Solution 2 Community
Solution 3 atkins
Solution 4 Gaspa79