Can't detect Keypress inside OnCollisionEnter()

Hi all.

I have a Button switch that my Player should be able to turn on when I hit key “E”. So on OnCollisionEnter(), I’ve checked if the Player is colliding with the Switch, and then checked if “E” is pressed to turn the switch On:

private void OnCollisionEnter(Collision collision)
    {
//..
if (collision.gameObject.name.Equals("Switch S1 1"))
        {
            Debug.Log("!!!");
           if (Input.GetKeyDown(KeyCode.E))
            {
                ltS1_1.enabled = true;
                ltS1_2.enabled = true;
                ltS1_3.enabled = true;
                ltS1_4.enabled = true;
                ltS1_5.enabled = true;
                ltS1_6.enabled = true;
                //anim.SetBool("BtnPush", true);
            }
        }

But it won’t detect the Keypress. Only When I remove the if-statement, the code runs detecting the collision, and enabling the relevant light sources:

if (collision.gameObject.name.Equals("Switch S1 1"))
        {
            Debug.Log("!!!");
            //if (Input.GetKeyDown(KeyCode.E))
            {
                ltS1_1.enabled = true;
                ltS1_2.enabled = true;
                ltS1_3.enabled = true;
                ltS1_4.enabled = true;
                ltS1_5.enabled = true;
                ltS1_6.enabled = true;
                //anim.SetBool("BtnPush", true);
            }
        }

Can anyone Please point out why it won’t detect the E-keypress inside the collision detection function?

Thanks!!

OnCollisoinEnter runs once when you first make contact
OnCollisionStay runs while your in contact
OnCollisionExit runs one after you stop touching

all of them run of fixed update also, so you’ve got that problem too. (inputs update on the renderer loop)

you can set a class level bool (true on enter, false on exit) and check for input in update

As Sparrow pointed out, edge-triggered “Down” and “Up” queries are ONLY valid in Update().

Second paragraph here:

https://docs.unity3d.com/ScriptReference/Input.GetKeyDown.html

QUOTE: “You need to call this function from the Update function”

OnCollisionEnter is NOT the same as Update()

Therefore you need to use Input.GetKeyDown() in Update() and record the key down in a class boolean variable, then act on it in the collision responder, and clear it appropriately once acted upon, otherwise it could be acted upon multiple times.

Here is some timing diagram help:

https://docs.unity3d.com/Manual/ExecutionOrder.html

I think one other thing you can do is convert the OnCollisionEnter function to a coroutine and “return null”(yield until next frame) in a while loop to sync with the update loop and receive input.

Ok guys, thanks!! So, I just put the above code inside OnCollisionStay(), and it just Worked. So do I need to set a tracking bool variable in Update() still? Or it’s just a good practice than just detecting keypresses in OnCollisionStay()?

Edit: btw here’s what it looks like. I haven’t assigned a Button press animation yet, I just press ‘E’ near the switch.

If you put Input.GetKeyDown() inside a function that is NOT called from Update(), that just means you became a test pilot and it is not specified why it is working, or why it might even not work in the future at different frame rates.

Since the docs specifically advise you where to use the function, generally it is good practice to follow that advice, especially if you looked at the timing diagram I liked above.

But of course, it is your project.

Thanks, yes, i have to make a tracking var inside Update. Cuz now i have other functions like lifting those vases when i hit ‘E’. I cannot carry them around if i don’t check that if i have pressed E without a tracking var. Thanks again.

1 Like