Inconsistent Jump height

The problem is that my character sometimes jumps high and after 5/6 button press he jumps really low.
the only thing i did different from Rick is that i used to put the input detection in the Update method and the physics management in FixedUpdate.
if i try to call the Jump in Update the issue does not occur, but in these days i believed i understood that common sense was to listen for Input only in Update, and for physics related stuff (rigidbody, forces etc…) in FixedUpdate :confused: why does this happen

    bool checkjump;
    float dir;
    float controlThrow;

 private void Update()
    {
        InputDetection();
       
        
    }

   
    private void InputDetection()
    {
        dir = Input.GetAxis("Horizontal"); //prendo la direzione
        controlThrow = Input.GetAxisRaw("Vertical"); //per il controllo del climbing
        checkjump = Input.GetButtonDown("Jump");
    }
   
    private void FixedUpdate()
    {
        Move();
        Jump();
        FlipSprite();
        ClimbLadder();
    }

   private void Jump() 

    {
        if (!myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Ground"))) { return; }

        if (checkjump)
        {
            Vector2 jumpVelocityToAdd = new Vector2(0f, jumpSpeed);
            rb.velocity += jumpVelocityToAdd;
        }
                     
      
    }

Ok little update, it seems like i fixed this by adding rb.velocity = Vector2.zero; before jumping, i thought that maybe something was messing up the velocity additions (?) and it worked it seems, but i would like to know if this is an expected behavior or i solved this only by luck by doing a random thing ahhaha
(also why in fixed update it didn’t worked properly but in update it did? and also i would like to know if i did good to put the input detections in update and the physics in fixed or if it has been all pointless .-. )
private void Jump()

{
    if (!myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Ground"))) { return; }

    if (checkjump)
    {
       rb.velocity = Vector2.zero; 
        Vector2 jumpVelocityToAdd = new Vector2(0f, jumpSpeed);
        rb.velocity += jumpVelocityToAdd;
    }
                 
  
}
1 Like

You can have the physics in FixedUpdate and the input in Update, that’s fine and it’s actually common practice, but there’s an issue with how you are handling your jump.

FixedUpdate runs multiple times per frame while Update only runs once, that means that your jump method will run several times and your input check only once, that will cause really weird behaviors like the one you are describing.

To fix that you should put your jump method inside Update, But what about the physics? Shouldn’t physics be handled in FixedUpdate? Yes, but that’s just for constant physics, like moving or casting a ray, but if you are just going to add velocity once there’s no need for FixedUpdate to handle that, you don’t even need to use deltaTime because it’s just a change of velocity in a single frame.

2 Likes

Thank you Yee!
so my solution was just pure luck(?) ahahahahah i understand how this works better now i will just stick jump into update
anyway looking a bit further on the web i saw that other people too used the escamotage i used by putting the rb.velocity to 0, but as you said it’s still a solution on the top of a weird behavior

1 Like

can i ask you something more since you are here? :sob:

it’s been half an hour i’m trying to implement the ability to jump when i am on a ladder, but i cannot understand why it doesn’t work


this is the simple method for the ladder

 private void ClimbLadder()
    {   
        if (!myBodycollider.IsTouchingLayers(LayerMask.GetMask("Climbing"))) 
        {            
            rb.gravityScale = gravityScaleAtStart;
            return; 
        }

       

        Vector2 climbVelocity = new Vector2(rb.velocity.x, controlThrow * climbingSpeed);
            rb.velocity = climbVelocity;
           rb.gravityScale = 0;
    }

the jump is above as you already have seen,
i tried to add in the ladder method something like this

 if (myBodycollider.IsTouchingLayers(LayerMask.GetMask("Climbing")) && checkjump)
        {
                      
            Debug.Log("touching and jumpinh");
          rb.gravityScale = gravityScaleAtStart;
            rb.velocity = Vector2.zero;
            Vector2 jumpVelocityToAdd = new Vector2(0f, jumpSpeed);
            rb.velocity += jumpVelocityToAdd;
        }

the debug.log is shown when i am on a ladder and press W or Space but nothing happens

1 Like

Your methods are probably overriding the velocity of the character at the same time and that’s why it’s not behaving as you are expecting, you’ll need to find a way to jump without doing that.

I don’t think you found the solution by luck, it’s actually a clever solution, but as you said, it’s a solution on top of a weird behaviour.

1 Like

yeah but this ladder is driving me crazy i can’t find out how to do this even on web :sob: :sob: and i found also an other “bug” at the top of the ladder if you keep pressing W the character will keep doing little bounce on top

Maybe i found this thread where the last guy did a solution to do something similiar, i think i’ll look onto it

1 Like

Oh, that’s great! Hope you find the solution, if you need help I might be able to write you an example but it will take me some time.

1 Like

it seems like that this code was also about achieving the jump at the bottom of the ladder, and “through” it it’s working but it caused a lot of other bugs, it’s not a good solution unfortunately, i’ll look more into it.
PS: if ycould try in giving it a shot and doing me an example i would be really grateful, when you have time :sob:

Ok so i have a nice update!
i modified a bit the code of the dude above the 70% of the bugs where due the fact that at the last branch of the if-statement in the climb method he didn’t set the isAttachedToLadder to false, that caused the player to fall with a weird behavior when arriving at the top of the ladder

   private void Climb()
    {
        if (myBodycollider.IsTouchingLayers(LayerMask.GetMask("Climbing")) && Input.GetAxis("Vertical") != 0)
        {
            attach = true;
            Vector2 climbVelocity = new Vector2(rb.velocity.x, controlThrow * climbingSpeed);
            rb.velocity = climbVelocity;
            rb.gravityScale = 0f;
        }
        else if (attach && myBodycollider.IsTouchingLayers(LayerMask.GetMask("Climbing")))
            {
                rb.gravityScale = 0f;                                                                          // If player attached but not climbing, we still have 0 gravity.
            }
        else
        {
            attach = false;
            rb.gravityScale = gravityScaleAtStart;
            return;
        }
            }


        private void Jump() 

    {
        if (myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Ground", "Climbing")) && checkjump) 
           
        {
            attach=false;
            Vector2 jumpVelocityToAdd = new Vector2(0f, jumpSpeed);
            rb.velocity += jumpVelocityToAdd;
        }

               
      
    }

so i’m happy but i still am trying to resolve the “”"“bounciness”"""" and the fact that when i press jump/ press W it still kinda falls off the ladder: (i know it’s not real bounciness, it’s just that it falls when i press one of these so if i keep pushing it, it does this effect because while falling it goes in the colliders of the ladders again)

i think is something related to the colliders

1 Like

I managed to solve all the bugs and jump on the ladder. The script I’m copy-pasting is not refactored, I’ll leave that up to you.

With this script, you’ll be able to jump on ladders but the jump will be “canceled” when the character starts to fall, that happens only when touching the ladders, if the character isn’t touching them it will fall as always.

The solution to stop the bouncing at the stop is not precisely elegant but it works, I just added a trigger collider on top of the ladder with a custom Layer called “Ladder Top”, when the character is touching that collider it will prevent the character from trying to climb, stopping that bounce.

I didn’t write any comments in the script, if you have any questions feel free to ask.

Here's the full script.
using UnityEngine;

[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(Collider2D))]
public class Move : MonoBehaviour
{
    [SerializeField] float speed = 0;
    [SerializeField] LayerMask jumpLayer = 0;
    [SerializeField] float jumpForce = 0;
    [SerializeField] LayerMask ladderLayer = 0;
    [SerializeField] LayerMask ladderTopLayer = 0;

    bool canJump;
    bool isJumping;
    bool canClimb;
    float hAxis;
    float vAxis;
    Collider2D col;
    Rigidbody2D rg2D;

    private void Awake()
    {
        rg2D = GetComponent<Rigidbody2D>();
        col = GetComponent<Collider2D>();
    }

    void Update()
    {
        hAxis = Input.GetAxisRaw("Horizontal");
        vAxis = col.IsTouchingLayers(ladderTopLayer) && Input.GetAxisRaw("Vertical") > 0 ? 0 : Input.GetAxisRaw("Vertical");

        if (canJump && Input.GetButtonDown("Jump"))
        {
            isJumping = true;
            rg2D.AddForce(Vector2.up * jumpForce);
        }
        else if (rg2D.velocity.y < 0 || (!Mathf.Approximately(vAxis, 0) && canClimb))
        {
            isJumping = false;
        }
    }

    private void FixedUpdate()
    {
        canJump = col.IsTouchingLayers(jumpLayer) || col.IsTouchingLayers(ladderLayer);
        canClimb = col.IsTouchingLayers(ladderLayer);

        rg2D.gravityScale = canClimb && !isJumping ? 0 : 1;

        rg2D.velocity = GetInputVelocity();
    }

    private Vector2 GetInputVelocity()
    {
        Vector2 newVelocity = Vector2.right * hAxis * speed;
        newVelocity.y = canClimb && !isJumping ? vAxis * speed : rg2D.velocity.y;

        return newVelocity;
    }
}

ezgif-5-7830a120feba

If you want, you can modify this code to make the character fall until the player presses the climb key, which might be better, because right now the ladders behaves like a very sticky wall.

1 Like

Thank you yee !! Your timing is outstanding i was just writing that i was going to try something like the trigger you mentioned, it’s not elegant but it’a the only solution i thought after hours of trying, this ladder is driving me crazy lol i will look at the code you made :smile:

1 Like

The only thing that was stopping me from doing this is that I am using tileset so it would really bother me to do an other layer just for the “top” pieces of the ladders, but I cannot think of an other elegant solution :frowning:
Also if we dont do this, when a player is approaching a ladder from the “top” he would just fly all the way down lol

If you think about something else let me now!

Ok wait I am understanding better your code, maybe you solved this better than i was thinking

So you used the layer only for the bounce to stop the player from trying to climb

I used that solution because the other ways to do this make the code a little bit convoluted and redundant, but you can totally use Raycast to check for the collider, then see if the player is at the top of that collider.

1 Like

And how could i use the raycast that to make it understand when I am at the top(?)

You can use any of the cast methods, circle, line, ray, it doesn’t matter, what you need is just the info of the collider, then see where’s the top of the collider, that you can tell by using bounds.

1 Like

Now i’m not at home so i cannot try this, but I need also the ability to jump “through” the ladder without sticking with it, like with the code i used before, and that was one of the thing that made the player fall when at the top, so i have to check on how to use the best of the two codes

I would like to solve this without raycast as for now

1 Like

As for now the ladder you showed work more like a “sticky spider web”

Privacy & Terms