1
\$\begingroup\$

Problem

I have a wall made with a Tilemap and a Tilemap Collider 2D. Sometimes, when the player jumps against the walls, it seems to get stuck. You do not need to be pressing the directional button, when pressing jump, for this to happen. Just being pressed against the wall, and then pressing the jump button alone, reproduces the error.

Demo

Demo

What I have tried

I applied a Physics collider to the Walls with friction set to 0. It didnt solve the issue.

Physics material

 Material applied to tilemap

Info that might be relevant to solve this

This is the player controller for the movement. Notice the FixedUpdate method, to see how I control the velocity of the Rigidbody2D.

using UnityEngine;
using UnityEngine.InputSystem;

namespace Notan
{
    public enum Direction3 { Left, Right, Still }

    [RequireComponent(typeof(Rigidbody2D))]
    public class PlayerMovement : MonoBehaviour
    {
        [SerializeField, Range(0f, 100f)] float speed = 10f;
        [SerializeField, Range(1f, 20f)] float jumpForce = 3f;

        Rigidbody2D body;
        Direction3 direction;
        bool jumpScheduled;

        void Awake()
        {
            body = GetComponent<Rigidbody2D>();
        }

        void Update()
        {
            UpdateDirection();
            UpdateJump();
        }

        void FixedUpdate()
        {
            UpdateVelocity();
        }

        bool LeftPressed() => Keyboard.current.leftArrowKey.isPressed;

        bool RightPressed() => Keyboard.current.rightArrowKey.isPressed;

        bool SpacePressed() => Keyboard.current.spaceKey.wasPressedThisFrame;

        void UpdateDirection()
        {
            direction = LeftPressed() ? Direction3.Left : RightPressed() ? Direction3.Right : Direction3.Still;
        }

        void UpdateJump()
        {
            if (SpacePressed()) jumpScheduled = true;
        }

        // Left is -1
        // Right is 1
        // Still is 0
        int GetHorizontalDirection() => direction == Direction3.Left ? -1 : direction == Direction3.Right ? 1 : 0;

        void UpdateVelocity()
        {
            var velocity = body.velocity;
            velocity.x = GetHorizontalDirection() * speed;
            if (jumpScheduled)
            {
                velocity.y = jumpForce;
                jumpScheduled = false;
            }

            body.velocity = velocity;
        }
    }
}

This is the configuration of the players Rigidbody2D

enter image description here

Unity version

I am using Unity 2019.3.9f1.

\$\endgroup\$
4
\$\begingroup\$

This is a common physics engine artifact caused by considering each tile's collider separately. Bennett Foddy illustrates why it happens in this GDC talk. It means your falling object can catch on the lip of the next tile down and be stopped from falling, before the tile to the side pushes it back out sideways, just due to bad luck in the order the collisions were evaluated.

We can fix it by adding a CompositeCollider2D component to the tilemap, and ticking the "used by composite" box on the TileMapCollider2D.

What this does is combine all the physics shapes of all the connected tiles into one big polygon, without internal edges to get snagged on. Since collision with the whole shape is considered at once, you don't run into the same ordering artifacts.

There's a cost to this, which is why Unity doesn't apply it by default. Not every tilemap needs it, but if you want to smoothly slide along continuous walls/floors then it's worthwhile to add.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ That was an AMAZING video! I loved it! \$\endgroup\$ – Enrique Moreno Tent Apr 24 at 13:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.