OnCollisionStay is inaccurate

I’ve been using OnCollisionStay for ground checking but it seems to be detected collisions for a few frames after they have clearly stopped colliding. This is pretty important to me as I’m using this to stick the player to the ground. I’ve tried messing with the physics step but it hasn’t done anything so far.

Anyone have any ideas?

Hello,

maybe try with OnCollisionEnter and OnCollisionExit, which set an isGrounded boolean to True or False after testing that it was the player who made the collision.

Hey there,

from my experience @jmhoubre 's suggestion wont help as OnCollisionStay will not yield different results than OnCollisionEnter and OnCollisionExit.

Problem is rather that the physics engine is based on a so called numeric solver based on floating point numbers. Along with this there come some implications, one of which beeing: you do not get an exact result. floats bring inaccuracy and numeric iterations towards any solution bring some inaccuracy.

This is why in the physics settings there is a collision threshold which defines at which distance 2 objects count as colliding. This is not zero and should not be too small as this will only f up things.
So depending on what you mean by “clearly” they have stopped colliding this might something that you cannot do that much about.

For anything further like options on what you could potentially do different to evade this issue would require a lot more information by you on what you actually do in detail.

I don’t know if you’ve found your solution or not (since I’m 18 days late), but here’s my answer nonetheless:

As you said the onTriggerStay has a delay (because an object needs to stay in it for a little time to be triggered) so let’s just go with a Sphere Cast that will check the Enter and Exit states.

Cast a Sphere on the player feet (I used an Empty Object for position), and check with a Sphere/Circle Cast if the player is Grounded or not;

I’m gonna post my code here but it’s for 2D and I’m too lazy to convert it. So if you’re working on 3D you need to make a few small tweaks like turning Circle to Sphere and such.

public Transform groundChecker; //Position where the circle/sphere will be made
    public float groundDist = 2.2f; //Distance amount
    public LayerMask layermask; //Active Layers - will ignore other layers

    bool grounded;

    // Update is called once per frame
    void FixedUpdate()
    {
        ///Casts a circle to act as Ground Check Trigger
        ///If it reaches the ground, then player is grounded
        if (Physics2D.CircleCast(groundChecker.position, 0.49f, Vector2.down, groundDist, layermask))
        {
            grounded = true;
        }
        else
        {
            grounded = false;
        }
    }

Hope this helps