Ladder animation bug

I’ve implemented the ladder system a slightly different way because I noticed that previously the Player couldn’t jump when they were touching the ground and ladder layers at the same time. Everything works except for when the player goes up the ladder from the ground, the climbing animation doesn’t play. This has something to do with my NotClimbingLadder Method with the second if statement. Any ideas on how to fix this issue?

Video of problem: https://youtu.be/lVgt25ZQQEM

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

public class PlayerMovement : MonoBehaviour
{
    Vector2 moveInput;
    Rigidbody2D rb2D;
    Animator animator;
    CapsuleCollider2D capsuleCollider2D;
    LadderLogic ladderLogicScript;
  
    
    float gravityStartScale;

    [SerializeField] float moveSpeed = 5f;
    [SerializeField] float jumpHeight = 5f;
    [SerializeField] float climbSpeed = 5f;
    [SerializeField] float climbSpeedDOWN = -3f;

    void Awake()
    {
        rb2D = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
        capsuleCollider2D = GetComponent<CapsuleCollider2D>();

        ladderLogicScript = FindObjectOfType<LadderLogic>();
       

        gravityStartScale = rb2D.gravityScale;
    }


    void Update()
    {
        Run();
        FlipSprite();
        NotClimbingLadder();
        
        
       
    }

    void OnMove(InputValue value)
    {
        moveInput = value.Get<Vector2>();
        Debug.Log(moveInput);
    }

     void OnJump(InputValue value)
    {
        if(!capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")))
        {
            
            return;
            
        }

        
        if(capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")))
        {
            
            if (value.isPressed)
            {
                rb2D.velocity += new Vector2 (0f, jumpHeight);
            }
            
        }


        
    }

    void Run()
    {
        Vector2 playerVelocity = new Vector2(moveInput.x * moveSpeed, rb2D.velocity.y);
        rb2D.velocity = playerVelocity;

        if (Mathf.Abs(rb2D.velocity.x) > Mathf.Epsilon)
        {
            animator.SetBool("IsRunning", true);
        }

        else
        {
            animator.SetBool("IsRunning", false);
        }
        
    }

    void FlipSprite()
    {
        bool playerHasHorizontalSpeed = Mathf.Abs(rb2D.velocity.x) > Mathf.Epsilon;

        if (playerHasHorizontalSpeed)
        {
        transform.localScale = new Vector2 (Mathf.Sign(rb2D.velocity.x), 1f);
        }
        
    }
        
    void NotClimbingLadder()
    {

         if(!capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ladder")))
        {
            rb2D.gravityScale = gravityStartScale;
            animator.SetBool("IsClimbing", false);
            return;
        }

       if(capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")))
            {
                animator.SetBool("IsClimbing", false);
            }
            

        
    }

    
    void OnClimbingUP(InputValue value)
        {
            if(capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ladder")))
            {
            
            Vector2 climbVelocity = new Vector2(rb2D.velocity.x, moveInput.y * climbSpeed);
            rb2D.velocity = climbVelocity;
            rb2D.gravityScale = 0f;

            bool playerHasVerticalSpeed = Mathf.Abs(rb2D.velocity.y) > Mathf.Epsilon;
            animator.SetBool("IsClimbing", playerHasVerticalSpeed);

            Debug.Log("ClimbingUP");
            }
        }

    void OnClimbingDOWN(InputValue value)
    {
        
        
        if(capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ladder")))
            {
            
            Vector2 climbVelocityDOWN = new Vector2(rb2D.velocity.x, moveInput.y * climbSpeedDOWN * -1);
            rb2D.velocity = climbVelocityDOWN;
            rb2D.gravityScale = 0f;

            bool playerHasVerticalSpeed = Mathf.Abs(rb2D.velocity.y) > Mathf.Epsilon;
            animator.SetBool("IsClimbing", playerHasVerticalSpeed);
            }

        

        
    }
    


}

Hi,

Have you already tried to add Debug.Logs to your code to see what is going on during runtime?

Ye when I put debug.log on the ClimbingUp and Climbing down methods both of them show up when they’re supposed to but when I add debug.log to the is touching ground layer if statement in the Notclimbingladder method the ClimbingUp debug.log doesn’t show up when going up the ladder from the ground. It has something to do with having the isTouching ground if statement in the Update function but I’m not sure what an alternative method would be to say when the player is touching the ground, set the climbing animation to false.

Finally got it working but now there’s a bug where if I jump up the ladder and then grab onto the ladder heading down, when the player hits the ground the velocity doesn’t go to zero instead its at 4.6. Is this a Unity bug or did I do something wrong in the OnClimbingDownMethod?

Video: https://youtu.be/JCC6d2kSCkE

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

public class PlayerMovement : MonoBehaviour
{
    Vector2 moveInput;
    Rigidbody2D rb2D;
    Animator animator;
    CapsuleCollider2D capsuleCollider2D;
    LadderLogic ladderLogicScript;
  
    
    float gravityStartScale;

    [SerializeField] float moveSpeed = 5f;
    [SerializeField] float jumpHeight = 5f;
    [SerializeField] float climbSpeed = 5f;
    [SerializeField] float climbSpeedDOWN = -3f;

    void Awake()
    {
        rb2D = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
        capsuleCollider2D = GetComponent<CapsuleCollider2D>();

        ladderLogicScript = FindObjectOfType<LadderLogic>();
       

        gravityStartScale = rb2D.gravityScale;
    }


    void Update()
    {
        Run();
        FlipSprite();
        NotClimbingLadder();
        
    }

    void OnMove(InputValue value)
    {
        moveInput = value.Get<Vector2>();
        //Debug.Log(moveInput);
    }

     void OnJump(InputValue value)
    {
        if(!capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")))
        {
           
            
            return;
            
        }

        
        /*if(rb2D.gravityScale == 0)
        {
            
            return;

        }
        */

         if(rb2D.gravityScale == 0 && capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")))
        {
            
            rb2D.gravityScale = gravityStartScale;
            animator.SetBool("IsClimbing", false);

        }
        

        
        if(capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")))
        {
           
            rb2D.gravityScale = gravityStartScale;
            
            if (value.isPressed)
            {
                rb2D.velocity += new Vector2 (0f, jumpHeight);
            }
            
        }



        
    }

    void Run()
    {
        Vector2 playerVelocity = new Vector2(moveInput.x * moveSpeed, rb2D.velocity.y);
        rb2D.velocity = playerVelocity;

        if (Mathf.Abs(rb2D.velocity.x) > Mathf.Epsilon)
        {
            animator.SetBool("IsRunning", true);
        }

        else
        {
            animator.SetBool("IsRunning", false);
        }
        
    }

    void FlipSprite()
    {
        bool playerHasHorizontalSpeed = Mathf.Abs(rb2D.velocity.x) > Mathf.Epsilon;

        if (playerHasHorizontalSpeed)
        {
        transform.localScale = new Vector2 (Mathf.Sign(rb2D.velocity.x), 1f);
        }
        
    }
        
    void NotClimbingLadder()
    {

       

         if(!capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ladder")))
        {
            rb2D.gravityScale = gravityStartScale;
            animator.SetBool("IsClimbing", false);
            //Debug.Log("NotTouchingLadder");
            return;
        }

        if(Mathf.Abs(rb2D.velocity.y) == 0 && capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")) && capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ladder")))
        {
            rb2D.gravityScale = gravityStartScale;
            animator.SetBool("IsClimbing", false);
    
           
        }

        /*if(capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")))
        {
            rb2D.gravityScale = gravityStartScale;
        }
        */

       /*if(capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")) && capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ladder")))
            {
                animator.SetBool("IsClimbing", false);
                
                Debug.Log("Touching Ground");
            }
            */
            
    }


    
    void OnClimbingUP(InputValue value)
        {
            if(capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ladder")))
            {
            
            Vector2 climbVelocity = new Vector2(rb2D.velocity.x, moveInput.y * climbSpeed);
            rb2D.velocity = climbVelocity;
            rb2D.gravityScale = 0f;

            bool playerHasVerticalSpeed = Mathf.Abs(rb2D.velocity.y) > Mathf.Epsilon;
            animator.SetBool("IsClimbing", playerHasVerticalSpeed);

            Debug.Log("ClimbingUP");
            }
        }

    void OnClimbingDOWN(InputValue value)
    {
        
        
        if(capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ladder")))
            {
            
            Vector2 climbVelocityDOWN = new Vector2(rb2D.velocity.x, moveInput.y * climbSpeedDOWN * -1);
            rb2D.velocity = climbVelocityDOWN;
            rb2D.gravityScale = 0f;

            bool playerHasVerticalSpeed = Mathf.Abs(rb2D.velocity.y) > Mathf.Epsilon;
            animator.SetBool("IsClimbing", playerHasVerticalSpeed);
             Debug.Log("ClimbingDOWN");
            }

        

        
    }
    


}

Actually, Rick solved this problem in the videos. I don’t know, though, if it is in this one. However, since you implemented climbSpeedDOWN, it might be that this is causing the problem. Or something else. Does NotClimbingLadder() get called while the player is on the ladder?

I assume that OnClimbingDOWN/OnClimbingUP get executed when you press a key. The respective velocity values get set in the methods. What happens if you release the key but if you are on the ladder? Since the gravityScale is set to 0f, the current velocity (either 5f or -3f) might still be the same.

In the Update method, log rb2D.velocity into your console to see if the returned values match your climbing values. If they do, you need code that detects if the player is on the ladder but not climbing. And in that case, you have to set the velocity to 0f.

If that’s too complicated*, I would suggest to not set the velocity in the climbing methods. Leave it at 0f. Instead, use transform.Translate or rb2D.position to move the player on the ladder but without the velocity.


* By “too complicated”, I am not referring to your skills but to the solution for your new idea. If the solution for your new problem makes the already existing code overly complicated, it is often a good idea to revise the existing solution to see if there is a simpler or different way which allows you to implement your new ideas as well. The current solution solves Rick’s problems, not necessarily yours.

The velocity log in the Update method isn’t matching the players velocity. When the player is on the ground running in the console it says its 0 on Y but on the player it says either + or - 1.825678e. maybe thats the bug. And then when the ladder bug is happening the console is saying 0,0 but of course the players Y velocity isn’t.

That’s indeed odd. Try to figure out where (0, 0) comes from. Is something setting the y-velocity to 0?

In your video, the console also logs 3. Where does that value come from? Since your climbSpeedDOWN value in your code is -3, I’m wondering what values are set in the PlayerMovement component in the Inspector.

“+ or - 1.825678e” is basically 0. See the “e” behind the value. It is fairly common that you do not get exactly 0, so the question is indeed: What is the y-velocity always (basically) 0 even if the player is moving fast on the y-axis?

image
the -3 and 3 are the climb speeds

At the 0:10 mark in your video, when climbing down, the player’s velocity in the Inspector is -3. According to your last screenshot, that’s expected. The player is sliding down because nothing sets the velocity back to 0f after the key was released. This means that the velocity remains -3 until something else overrides the velocity.

The first if-block in NotClimbingLadder gets called if the player is not touching the ladder anymore. Theoretically, you also need a solution for the case when the player is on the ladder but not moving.

Is this line not checking if the player is on the ladder but not moving?

 if(Mathf.Abs(rb2D.velocity.y) == 0 && capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")) && capsuleCollider2D.IsTouchingLayers(LayerMask.GetMask("Ladder")))
        {
            rb2D.gravityScale = gravityStartScale;
            animator.SetBool("IsClimbing", false);
    
           
        }

It seems so. However, if you press, for example, the down key, the player’s y-velocity becomes -3. When you release the key, the y-velocity is still -3.

You need a condition which detects if the player is not supposed to move. By “not moving”, I mean y = 0. The y-velocity has to be set to 0 if the player is not supposed to move. And the question is: In which case?

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.

Privacy & Terms