Unity: Input.GetButtonDown is not reliably detected in Update?

Viewed 1040

I have a player script that I'm trying to implement jumping in. The problem is that Input.GetButtonDown("Jump") doesn't consistently fire in Update. I know this is a problem when it's in FixedUpdate. Here is my code.

Note: I put [SerializeField] on pressingJump and holdingJump so I could see what's happening. pressingJump is inconsistent (as expected) but holdingJump works perfectly.

using UnityEngine;

public class Player : MonoBehaviour
{
    public float fallMultiplier = 15f;
    public float lowJumpMultiplier = 10f;
    public float walkSpeed = 20f;
    public float jumpSpeed = 15f;

    public bool canMove = true;
    public bool canJump = true;
    
    Rigidbody rb;

    float horizontalInput;
    bool doJump;
    bool pressingJump;
    bool holdingJump;
    
    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        CaputureInput();
    }

    void CaputureInput()
    {
        if (canMove) {
            horizontalInput = Input.GetAxisRaw("Horizontal");
        }
        

        pressingJump = Input.GetButtonDown ("Jump");
        doJump = pressingJump && canJump;
        holdingJump = Input.GetButton ("Jump") && canJump;
    }
    
    void FixedUpdate()
    {
        Move();
        Jump();
    }
    
    void Move()
    {
        rb.velocity = new Vector2(horizontalInput * walkSpeed, rb.velocity.y);
    }
    
    void Jump()
    {
        if (doJump) {
            rb.velocity += Vector3.up * jumpSpeed;
            doJump = false;
        }

        if (rb.velocity.y < 0) {
            rb.velocity += Vector3.up * Physics.gravity.y * (fallMultiplier - 1) * Time.deltaTime;
        } else if (rb.velocity.y > 0 && !holdingJump) {
            rb.velocity += Vector3.up * Physics.gravity.y * (lowJumpMultiplier - 1) * Time.deltaTime;
        }        
    }
}
1 Answers

Ok found the solution here: https://www.reddit.com/r/Unity3D/comments/9nr2sd/inputgetbuttondown_and_getbuttonup_dont_work/e7ogta1?utm_source=share&utm_medium=web2x

This was the problem I was having.

Edit: Comment pointed out a link might not be accepted. Here is the relevant content from link. It points out why the issue is occurring and how to fix it.

What you end up with, with the code you've written, is essentially the same as when you do input checking in FixedUpdate.

This is because Update runs several times in between every FixedUpdate. Now, what this means for your code in this case is that yes, you do capture the state of ButtonDown("Jump") during Update, but think about this: what happens to button_down/up_jump if another Update happens before a FixedUpdate? Both GetButtonDown and GetButtonUp are functions that are true only for the one frame in which the keypress/-release happened. In other words, this is happening

Update runs -> button_down_jump is false

user presses "Jump".

Update runs -> button_down_jump is true

Update runs -> button_down_jump is false

FixedUpdate runs -> nothing happens, because of button_down_jump's state

Now, you've actually had a few cases where you press/unpress "jump" at just the right time to manage to get anything printed at all. This will only happen given that the following happens:

User un-/press "jump"

Update runs (ONCE)

FixedUpdate runs

What you actually want to do is something like this:

void Update() { if(Input.GetButtonDown("jump")) { button_down_jump = true; //this captures the state of the boolean beyond the one frame, as it's only set whenever the input event happens } if(Input.GetButtonUp("jump")) { button_up_jump = true; } }

Related