inconsistent jump height (2D)

Hello everyone,

I have the following very simple piece of code which lets my 2D character jump:

public float jumpVelocity = 10f;

...

private void Jump() {
        isGrounded = Physics2D.OverlapCircle(groundDetector.position, 1F, whatIsGrounded);
        if (isGrounded && Input.GetButtonDown("Jump")) {
            rb2d.velocity = Vector2.up * jumpVelocity;
        }
}

...

The problem is when the player is not moving on the horizontal axis (when player is idling) and wants to jump he is jumping higher than when the player is moving along the horizontal axis (when player is walking), but I want to have a consistent jump height for a walking jump and an idle jump. I hope someone can help me out. Thanks in advance

Do you have more code about how the player is moving, too? Maybe something is interfering.
Also note that you’re overriding the velocity in your posted code… no longer keeping any you might have had currently.

Thanks for the quick response. Yes there is more code, but it shouldnt really interfere with the jumping part, but I can post the whole script if it helps. About overriding the velocity…i was watching a tutorial for short and bigger jumps and I think that was supposed to be like that … and if not wouldnt it still be the same height for a walking jump and an idle jump?

public class JnR_PlayerController : MonoBehaviour {

    public float    fallMultiplier = 10f;
    public float lowJumpMultiplier =  2f;
    public float movementSpeed     = 10f;
    public float minMovementSpeed  = 15f;
    public float maxMovementSpeed  = 25f;
    public float jumpVelocity      = 10f;

    private float walkTime = 0f;
    private Animator animator;
    private bool isGrounded = true;
    private Transform groundDetector;
    private LayerMask whatIsGrounded;
    private Rigidbody2D rb2d;
    private AnimationStance animationStance;
    private enum AnimationStance {
        idle,
        walk,
        jump,
        land,
        attack
    }

    private void Awake () {
        rb2d = GetComponent<Rigidbody2D>();
        animator = GetComponentInChildren<Animator>();
        groundDetector = this.gameObject.transform.Find("GroundDetector");
        whatIsGrounded |= (1 << LayerMask.NameToLayer("Ground"));
    }

    private void FixedUpdate() {
        PlayAnimation();
        Movement();   
        Jump();
    }

    private void Jump() {
        isGrounded = Physics2D.OverlapCircle(groundDetector.position, 1F, whatIsGrounded);
        if (isGrounded && Input.GetButtonDown("Jump")) {
            rb2d.velocity = Vector2.up * jumpVelocity;       
            animationStance = AnimationStance.jump;
        }
        if (rb2d.velocity.y > 0 && !Input.GetButton("Jump")) {
            rb2d.velocity += Vector2.up * Physics2D.gravity.y * (lowJumpMultiplier - 1) * Time.deltaTime;
            animationStance = AnimationStance.jump;
        }
        if (rb2d.velocity.y < 0) {
            rb2d.velocity += Vector2.up * Physics2D.gravity.y * (fallMultiplier - 1) * Time.deltaTime;
            animationStance = AnimationStance.land;
        }
    }

    private void Movement() {
        movementSpeed = Mathf.Clamp(movementSpeed, minMovementSpeed, maxMovementSpeed);
        if (Input.GetAxis("Horizontal") == 0) {
            walkTime = 0f;
            movementSpeed = minMovementSpeed;
            animationStance = AnimationStance.idle;
        } else {
            transform.Translate(Vector3.right * Time.deltaTime * movementSpeed);
            walkTime += Time.deltaTime;
            if (walkTime > 1.5f) movementSpeed += 0.08f;
            else movementSpeed = minMovementSpeed;
            animationStance = AnimationStance.walk;
            FlipSpriteRotation();
        }
    }

    private void HandleLayers() {
        if (!isGrounded) animator.SetLayerWeight(1, 1);
        else animator.SetLayerWeight(1, 0);
    }

    public void PlayAnimation() {
        HandleLayers();
        switch (animationStance) {
            case (AnimationStance.idle):
                animator.SetBool("isWalking", false);
                animator.SetBool("isIdling" , true);
                animator.SetBool("isJumping", false);
                break;
            case (AnimationStance.walk):
                animator.SetBool("isWalking", true);
                animator.SetBool("isIdling" , false);
                animator.SetBool("isJumping", false);
                break;
            case (AnimationStance.jump):           
                animator.SetBool("isWalking", false);
                animator.SetBool("isIdling" , false);
                animator.SetTrigger("isJumping");
                break;
            case (AnimationStance.land):
                animator.SetBool("isWalking", false);
                animator.SetBool("isIdling", false);
                animator.SetBool("isLanding", true);
                break;
        }
        if(isGrounded) animator.SetBool("isLanding", false);
    }

    public void FlipSpriteRotation() {
        if (Input.GetAxis("Horizontal") < 0) transform.rotation = Quaternion.Euler(0, 180, 0);
        if (Input.GetAxis("Horizontal") > 0) transform.rotation = Quaternion.Euler(0, 0, 0);
    }
}

Nothing stands out to me right now about what could cause the issue you say you’re seeing.
It was only possible that maybe your movement code was interfering… not a sure thing :slight_smile:

An odd question, as I’ve not ever done anything with 2d and root motion… but is root motion checked on your animator? Sometimes that can alter things.

Beyond that, sorry I can’t spot any issue/be of more help.

1 Like

A quick glance at the code, and I found a few problems.

FixedUpdate uses Time.fixedDeltaTime, you have Time.deltaTime. This could be causing the inconsistencies as fixed update doesn’t trigger at the same rate as update.

Another problem with fixed update and the use of Input. Because of the fact that fixed update doesn’t trigger the same as update and input is synced with update, using it in fixed update will cause inconsistency as well.

As a guide I always poll input in update and set values that will affect what happens in fixedupdate.

1 Like

Good observation about the Input for jump. That should be done in Update, so it’s better. You can even add jump velocity in Update, without any issues.

However, Time.deltaTime returns fixedDeltaTime when called from FixedUpdate(), so there is no issue there.

One thing I could add is maybe just not even worry about the :

!Input.GetButton("Jump") // second part of the 'if' statement in your jump code

I don’t really think you’d need that.

I have not looked at your extended code, but based on the code from post 1, I suggest that you try to use Input.GetButtonUp and see if this produces a consistent result. I understand it is not how you want the controller to work but it is for testing purpose only. I am afraid that your IsGrounded is true, even if the player has already started to jump.

You could test this in your existing code, by inserting in front of line 9, Debug.Log(“set Velocity”);

Had to check the docs to confirm, damn if I had of known.

Thanks for that information. I will put my inputs in the regular Update function. However I found out that the cause of my problem wasn’t the code itself, but I accidentally chose “interpolate” as my interpolation option in rigidbody 2d instead of “none”. This was the reason for the inconsistent jump heights. Thanks everyone for your help :slight_smile:

Ah okay… :slight_smile: Glad you found and fixed the issue.