🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Fix Inconsistent Jump Heights

Started by
6 comments, last by Thaumaturge 2 years, 5 months ago

Hi, I am new to game development and I followed a tutorial on a 2d platformer character controller script. Everything is working perfectly, except for the jump height. Jumping while standing still is much lower than jumping while running. I assume somewhere in my code the vector force is being influenced by the horizontal input, but I don't know where. If anyone could help me, I'd greatly appreciate it!

No horizontal input
With horizontal input

Here is my code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    [Header("Components")]
    private Rigidbody2D rb;

    [Header("Layer Masks")]
    [SerializeField] private LayerMask groundLayer;

    [Header("Movement Variables")]
    [SerializeField] private float movementAcceleration;
    [SerializeField] private float maxMoveSpeed;
    [SerializeField] private float groundLinearDrag;
    private float horizontalDirection;
    private bool changingDirection => (rb.velocity.x > 0f && horizontalDirection < 0f) || (rb.velocity.x < 0f && horizontalDirection > 0f);

    [Header("Jump Variables")]
    [SerializeField] private float jumpForce = 12f;
    [SerializeField] private float airLinearDrag = 2.5f;
    [SerializeField] private float fallMultiplier = 8f;
    [SerializeField] private float lowJumpFallMultiplier = 5f;
    private bool canJump => Input.GetButtonDown("Jump") && onGround;

    [Header("Ground Collision Variables")]
    [SerializeField] private float groundRaycastLength = 0.9f;
    private bool onGround;

    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    private void Update()
    {
        horizontalDirection = GetInput().x;
        if (canJump) Jump();
    }

    private void FixedUpdate()
    {
        CheckCollisions();
        MoveCharacter();
        if (onGround){
            ApplyGroundLinearDrag();
        }else{
            ApplyAirLinearDrag();
            FallMultiplier();
        }
  
    }


    private Vector2 GetInput()
    {
        return new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
    }

    private void MoveCharacter()
    {
        rb.AddForce(new Vector2(horizontalDirection, 0f) * movementAcceleration);

        if (Mathf.Abs(rb.velocity.x) > maxMoveSpeed)
            rb.velocity = new Vector2(Mathf.Sign(rb.velocity.x) * maxMoveSpeed, rb.velocity.y);
    }

    private void ApplyGroundLinearDrag()
    {
        if (Mathf.Abs(horizontalDirection) < 0.4f || changingDirection)
        {
            rb.drag = groundLinearDrag;
        }
        else
        {
            rb.drag = 0f;
        }
    }

    private void ApplyAirLinearDrag()
    {
        rb.drag = airLinearDrag;
    }

    private void Jump()
    {
        ApplyAirLinearDrag();
        rb.velocity = new Vector2(rb.velocity.x, 0f);
        rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);   
    }

    private void CheckCollisions()
    {
        onGround = Physics2D.Raycast(transform.position * groundRaycastLength, Vector2.down, groundRaycastLength, groundLayer); 
    }

    private void OnDrawGizmos(){
        Gizmos.color = Color.green;
        Gizmos.DrawLine(transform.position, transform.position + Vector3.down * groundRaycastLength);
    }

    private void FallMultiplier()
    {
        if (rb.velocity.y < 0)
        {
            rb.gravityScale = fallMultiplier;
        }
        else if (rb.velocity.y > 0 && !Input.GetButton("Jump"))
        {
            rb.gravityScale = lowJumpFallMultiplier;
        }
        else
        {
            rb.gravityScale = 1f;
        }
    }
}
Advertisement

I can just guess but I think this happens around your FallMultiplier function. You're applying different multipliers under different cirumstances which looks clear on the first view. If you jump then add a certain multiplier, I assume to control the ‘natural’ jump mechanic but it depends on how long the ‘Jump’-Button is pressed. So you might try to hold the jump button until your character has reached the peak and try to just tip the jump button once to trigger jumping. I expect there would be 2 different heights reached regardless if you stand or move.

If you however limit this check to just the first frame the button has become pressed, the result should be the same in both, standing and moving jumps

@Shaarigan After some testing I don't believe the FallMultiplier is the culprit, I think it has to do with how drag is implemented. While standing still, I can still have different jump heights but holding it down for my max jump height doesnt reach the same max as when moving.

I think it has to do with drag because I found that changing the variables for drag changed how large the difference is between standing and running jumps. I think this is because while moving, I set the ground drag to 0 until I stop moving, but while standing still, my ground drag is instead a positive number and I assume is also unintentionally applying drag on my y-axis.

I wonder whether it's not to do with the code that determines whether the character is “on the ground”: if that code is finding the character to be “on the ground” during the start of the jump, then ground-based drag might be being applied.

As a test, what happens if you change the “CheckCollisions” method to additionally consider the character to “not be on the ground” while moving upwards, regardless of the ray-cast?

Something like this:

    private void CheckCollisions()
    {
    	// I'm presuming that "upwards" corresponds with positive
    	// numbers; if I have that the wrong way around, reverse the
    	// "greater-than" sign.
    	if (rb.velocity.y > 0)
    	{
    		onGround = False;
    	}
    	else
    	{
        	onGround = Physics2D.Raycast(transform.position * groundRaycastLength, Vector2.down, groundRaycastLength, groundLayer); 
        }
    }

MWAHAHAHAHAHAHA!!!

My Twitter Account: @EbornIan

@Thaumaturge This fixed the jump issue! But it also introduced a new issue with the drag.

The jumps work exactly how I want them to now, but when I run to the left at max speed and stop, I no longer get the groundDrag applied and instead of a quick stop I kind of slide. The drag is still applied correctly when running to the right, so I have no clue why this is.

@Brandon102002 I found the problem, thanks for the help!

It's my pleasure! I'm glad that you got these things working! ^_^

MWAHAHAHAHAHAHA!!!

My Twitter Account: @EbornIan

This topic is closed to new replies.

Advertisement