Player Thrown Off Ladder When Climbing from the Left Side

throw off bug
I’m working on a ladder climbing mechanic, and I want the player to always snap to the middle of the ladder. I have a script attached to the ladder’s Tilemap to handle this behavior:

using UnityEngine;
using UnityEngine.Tilemaps;

public class ExampleClass : MonoBehaviour
{
    private Tilemap tilemap;
    [SerializeField]private PlayerMovement mov;
    bool _isLadderPositionSet = false; //Make sure to set player postion of collided ladder tile position only once 

    void Start()
    { 
        tilemap = transform.GetComponent<Tilemap>();  
    }


    void OnTriggerEnter2D(Collider2D other)
    {  
        if(other.gameObject.tag == "Player" && mov.IsClimbing)
        {  
            Vector3 cellPosition = GetPostionOfCollidedTile(other);
            Debug.Log("ladder postion: " + cellPosition);
            other.gameObject.transform.position = new Vector3(cellPosition.x + 0.5f, cellPosition.y + 0.5f, cellPosition.z);           
        }
    }

    void OnTriggerStay2D(Collider2D other)
    {
        if(!_isLadderPositionSet && other.gameObject.tag == "Player" && mov.IsClimbing)
        {  
            _isLadderPositionSet = true;
            Vector3 cellPosition = GetPostionOfCollidedTile(other);
            Debug.Log("ladder postion: " + cellPosition);
            other.gameObject.transform.position = new Vector3(cellPosition.x + 0.5f, other.gameObject.transform.position.y, other.gameObject.transform.position.z);           
        }
        if(_isLadderPositionSet && other.gameObject.tag == "Player" && !mov.IsClimbing)
        {
           _isLadderPositionSet = false; 
        }
    }
    void OnTriggerExit2D(Collider2D other)
    {
        if(_isLadderPositionSet && other.gameObject.tag == "Player")
        {  
            _isLadderPositionSet = false;
        }
    }

    Vector3 GetPostionOfCollidedTile(Collider2D other)
    {
        for (int n = tilemap.cellBounds.xMin; n < tilemap.cellBounds.xMax; n++)
        {
            for (int p = tilemap.cellBounds.yMin; p < tilemap.cellBounds.yMax; p++)
            {
                Vector3Int localPlace = new Vector3Int(n, p, (int)tilemap.transform.position.y);
                Bounds tileBounds = new Bounds(tilemap.CellToWorld(localPlace) + tilemap.cellSize / 2, tilemap.cellSize);
                if (other.bounds.Intersects(tileBounds))
                {
                    Vector3 place = tilemap.CellToWorld(localPlace);
                    return place;
                }
            }
        }
        
        return Vector3.zero;
    }
    
}

It mostly works, and the player successfully snaps to the middle of the ladder. However, I’ve encountered a bug: when the player climbs the ladder from the left side, he is thrown off the ladder, and I can’t figure out why this is happening.

Below is a fragment of the related climbing code in the PlayerMovement script:

public bool IsClimbing { get; private set; }
private bool _onLadder;

void Update()
{
	//On ladder check
	if(Physics2D.OverlapBox(_groundCheckPoint.position, _groundCheckSize, 0, _climbingLayer))
        {
        	_onLadder = true;
        }
        else
        {
                _onLadder = false; 
                IsClimbing = false;
        }

        if(IsClimbing)
        {
            Climb();

        }

        if(_moveInput.y != 0 && _onLadder)
        {
            Climb();
        } 
}

    private void Climb()
    {
        IsClimbing = true;
        
        LastOnGroundTime = Data.coyoteTime;
        Debug.Log("Calculating climb velocity..");
        Debug.Log("Y:" + _moveInput.y);
        Vector2 climbVelocity = new Vector2(RB.velocity.x, _moveInput.y * Data.climbSpeed);
        RB.velocity = climbVelocity; 

        if(LastPressedJumpTime > 0)
        {
            IsClimbing = false;
            return;
        }

    }

This is the player’s collider, and the one below it is used to check for ground and ladder layers:

Thanks in advance!

That’s why they invented debugging!

Your description sounds like you wrote a bug… and that means… time to start debugging!

By debugging you can find out exactly what your program is doing so you can fix it.

Use the above techniques to get the information you need in order to reason about what the problem is.

You can also use Debug.Log(...); statements to find out if any of your code is even running. Don’t assume it is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

Remember with Unity the code is only a tiny fraction of the problem space. Everything asset- and scene- wise must also be set up correctly to match the associated code and its assumptions.

1 Like

I fixed the issue. The problem was that I was getting the positions of all the tiles on the tilemap instead of only the ones with ladder tiles.

1 Like

Just simple Tilemap.HasTile() check helped