#Inconsistent jump height when changing game gravity

1 messages · Page 1 of 1 (latest)

finite brook
#

Hello there, I am working on a 2D "platformer", I want the character to be able to double jump, and I want the jump to be always consistent with the jump height set in the editor. That means I wanna jump 5 units high whether the character is going up or going down, but the fact that the gravity is changing to make the game more snappy throws off the jump force calculations. Does any one of you know the solution to this problem?

#

This is the code:

    private void FixedUpdate() {
        setGravity();
        if (_input.intendedJump) {
            jump();
            return; // This is here to prevent double jump bug (according to some youtube video)
        }
        changeGravity();
    }

    private void setGravity() { // some physics formula for calculating gravity
        Vector2 newGravity = new Vector2(0, (-2 * jumpHeight) / (jumpApexTime * jumpApexTime));
        _RB2D.gravityScale = (newGravity.y / Physics2D.gravity.y) * defaultGravityMultiplier;
    }

    private void changeGravity() {
        if (_RB2D.velocity.y > verticalVelocityEpsilon) {
            defaultGravityMultiplier = upwardGravityMultiplier;
        } else if (_RB2D.velocity.y < -verticalVelocityEpsilon) {
            defaultGravityMultiplier = downwardGravityMultiplier;
        } else {
            if (_groundCheck.isGrounded) {
                isJumping = false;
            }
            defaultGravityMultiplier = defaultGravity;
        }
    }

    private void CalculateJumpForce() {
        jumpForce = Mathf.Sqrt(-2f * Physics2D.gravity.y * _RB2D.gravityScale * jumpHeight); // "consistent" jump height in "unity units" depending on 
        jumpForce = (jumpForce - _RB2D.velocity.y);
    }

    private void jump() {
        if (_groundCheck.isGrounded || (airJumpCounter < maxAirJumps) || (coyoteTimeCounter < coyoteJump && coyoteTimeCounter > 0.03f)) {
            _input.intendedJump = false;
            jumpBufferCounter = 0;
            coyoteTimeCounter = 0;

            CalculateJumpForce();
            _RB2D.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);

            airJumpCounter++;
            isJumping = true;
        }
    }    
}
sterile token
#

Hi @finite brook .
A solution for this problem has previously been provided here: https://discussions.unity.com/t/addforce-to-go-a-specific-distance-and-height/61013/2
Have a look and let me know if that works for you.

#

In a nutshell, you want to set the target velocity rather than force in order to achieve the desired height, regardless of the object's mass. The gravity acceleration is taken into account in the calculation of the target velocity, and the velocity is decomposed into a horizontal (where gravity doesn't matter) and vertical component (where gravity does matter).

finite brook
#

Based on that, i should remove the AddForce and exchange it for rb2d.velocity = vector2(rb2d.velocity.x, jumpForce) and the jumpForce should be calculated just like is, but without the other line?

finite brook
#

(I tried that and it didnt help, the behaviour was the same)

sterile token
#

It is quite surprising that the behavior is identical, since setting the velocity and adding a force (or impulse here) are two entirely different things, UNLESS the mass is 1 and you are applying the force when the current force is zero. Then the behavior would be the same.

So, I am seeing that you are changing gravity in your FixedUpdate function in the frames after having initiated the jump. This obviously invalidates the formula and you will not reach the intended height if the gravity is changed to a different value than what you used when calculating the force/velocity you are applying.

finite brook
finite brook
#

I tried changing the order of the methods. (i think i tried every combination possible) and the jump is still inconsistent, but in a more consistent way if that makes any sense? 😅

#

This is the code now.

private void FixedUpdate() {
    changeGravity();
    setGravity();
    CalculateJumpForce();

    if (_input.intendedJump) {
        jump();
        return; // This is here to prevent double jump bug (according to some youtube video)
    }

    
}

private void setGravity() { // some physics formula for calculating gravity
    Vector2 newGravity = new Vector2(0, (-2 * jumpHeight) / (jumpApexTime * jumpApexTime));
    _RB2D.gravityScale = (newGravity.y / Physics2D.gravity.y) * newGravityMultiplier;
}

private void changeGravity() {
    if (_RB2D.velocity.y > verticalVelocityEpsilon) {
        newGravityMultiplier = upwardGravityMultiplier;
    } else if (_RB2D.velocity.y < -verticalVelocityEpsilon) {
        newGravityMultiplier = downwardGravityMultiplier;
    } else {
        if (_groundCheck.isGrounded) {
            isJumping = false;
        }
        newGravityMultiplier = defaultGravity;
    }
}

private void CalculateJumpForce() {
    jumpForce = Mathf.Sqrt(-2f * Physics2D.gravity.y * _RB2D.gravityScale * jumpHeight);
}

private void jump() {
    if (_groundCheck.isGrounded || (airJumpCounter < maxAirJumps) || (coyoteTimeCounter < coyoteJump && coyoteTimeCounter > 0.03f)) {
        _input.intendedJump = false;
        jumpBufferCounter = 0;
        coyoteTimeCounter = 0;

        _RB2D.velocity = new Vector2(_RB2D.velocity.x, jumpForce);

        airJumpCounter++;
        isJumping = true;
    }
}
finite brook
#

I think i finally understood the issue.

The jumping is consistent and gravity behaves like its supposed to, but, when i was falling i had the downwardGravity applied, and with that I got the jump force, which was calculated correctly, but for the downward gravity, so the moment I jumped, the gravity switched to the "lighter" one but i was still using the force calculated for the strong gravity.

So the solution I came up with is just to simply calculate jump force always using the upward gravity scale, because i always wanna go up when i jump.

I don't know if that's a good or elegant solution, but it works. (so far i havent found a bug)