OnCollisionStay only sending for 1 second

My void OnCollisionStay only sends for the first few frames that my object collides with another. Am I misunderstanding what the command is supposed to do or am I just using it wrong?

   void OnCollisionStay2D(Collision2D collisionInfo)
    {
        Debug.Log("Collision");
           
    }

I think you’re understanding it properly. There’s something that is causing the collision to “Exit”. It could a bunch of things like:

  • The objects no longer overlap because one or both have moved
  • One of the objects was deactivated.
  • One of the objects had its collider destroyed
  • One of the objects was destroyed.

Praetor is right on, except there’s one more reason: lazy Rigidbody2Ds.

Yes, it’s true. Despite their best intentions, even the most professional Rigidbody2D will get lazy and fall asleep, even while they’re on the job, supposedly working for you.

You may think I’m joking, but I’m not. Your collider is falling asleep. You need to wake it up, or else change its sleep criteria. You can wake it up with:

https://docs.unity3d.com/ScriptReference/Rigidbody2D.WakeUp.html

The rationale for sleeping is to reduce CPU power consumption by the physics system. It will auto-wakeup if you apply a force to it, or something bumps into it, but it will otherwise fall asleep soon after it stops moving.

1 Like

Thank you, it works now

1 Like

Sweet! You can actually make them not be lazy by setting their sleep mode to NeverSleep.

https://docs.unity3d.com/ScriptReference/Rigidbody2D-sleepMode.html

That may suit your use case better rather than always waking it up. :slight_smile:

Actually, now I’m having a different issue that might not be related, but I’m not sure. Even if I rapidly press the spacebar, this command does not go off every time I land, but its inconsistent, sometimes it will go off right when I land. I have both of the rigidbodys set to continuous collision detection

    void OnCollisionStay2D(Collision2D collisionInfo)
    {
       
            if (Input.GetKeyDown("space"))
            {
            Debug.Log("Jump");
            rb.velocity = new Vector3(0, jump, 0);
            }
    }

Ah yeah, you can’t use Input.GetKeyDown() anywhere except in Update() functions.

Do the check in Update(), set a boolean true, then check the boolean in your collision, and clear it when you do the jump.

It has to do with this timing diagram:

Thinking more on it, this will cause the bool to remain true as you’re falling (like if you hit jump midair), and the instant you touch down you’ll jump because the bool will be true, even if you’re nowhere near the jump key at that moment.

This is usually why you use Exit and Enter rather than Stay

On Enter you set a different boolean (such as “isgrounded”) and on Exit you clear it, and then you don’t check the jump button or set the jump boolean unless you are grounded. There’s tons of tutorials that sorta follow this common pattern. You would still only check the key in Update() obviously.

Got it, thanks again

1 Like