Make a Dynamic Rigidbody2D slide after it collides with a wall

Hey everyone!

So I’m setting up a Dynamic Rigidbody2D movement system (so Rigidbody2Ds won’t push each other), and I am struggling to figure something out

In the attached screenshot my character is moving to the bottom left, and it is colliding with the wall, but I am trying to figure out how, once the collision is detected, I’d make it move to the left (i.e.: “slide” along the wall)

Here’s my code

    private void FixedUpdate()
    {
        Vector2 moveValue = _playerInputClass.Player.Move.ReadValue<Vector2>();
        if (CheckCollision(moveValue, .25f))
        {
            //For now if I'm colliding I'm simply ignoring the input because, again, I'm trying to figure out how to do it
            moveValue = Vector2.zero;
        }
       
        _rigidbody.MovePosition(_rigidbody.position + moveValue * movementSpeed * Time.fixedDeltaTime);
        if (_playerInputClass.Player.Rotate.phase != InputActionPhase.Waiting)
        {
            Vector2 rotateValue = _playerInputClass.Player.Rotate.ReadValue<Vector2>();
            _rigidbody.rotation = Mathf.Atan2(rotateValue.y, rotateValue.x) * Mathf.Rad2Deg;
        }
    }

    private bool CheckCollision(Vector2 direction, float distance)
    {
        Array.Clear(_collisions, 0, _collisions.Length);
        collider.Cast(direction, _collisions, distance);
        foreach (var v in _collisions)
        {
            if (v.transform && v.transform.CompareTag("Wall"))
            {
                return true;
            }
        }

        return false;
    }

8928611--1223723--screenshot.jpg

I suppose you can bounce a ray off the object you’re against and use the normal from that ray and use either Vector3.forward or Vector3.backward - depending on if the player is to the left or right of the object (and I guess, above or below it) alongside Vector3.Cross() to make a perpendicular direction, which can be the direction to move the player in.

Why would you be using a Dynamic Rigidbody2D which already has collision detection and response? Surely the above is a Kinematic problem?

You can find an example in my repo for Kinematic movement that manually calculates how to slide along a surface here:

https://github.com/Unity-Technologies/PhysicsExamples2D

Note that the critical part of the “slide” is this:

Note that in 2023.1 there’s a new Slide function to do this kind of stuff automatically for you as shown here:

API: Unity - Scripting API: Rigidbody2D.Slide

There’s also overloads for many physics queries so you can perform a query such as “cast” from a specific pose (position/rotation) such as this: Unity - Scripting API: Rigidbody2D.Cast

It is indeed set as Kinematic, my mistake on the post! I’ll check the content you’ve posted. Cheers!

1 Like

So yes, you can modify the movement vector you have with the following dot-product calculation to remove the component of movement in the direction you hit (collision normal):

movementDirection -=  hit.normal * Vector2.Dot(movementDirection, hit.normal);

There are variations of this depending on what you’re doing but the crux of it is the 2D Dot Product.

Thanks again!

Almost there, but now when the player collides with the wall it has that famous 2D jittery behaviour. I always thought that that was because of moving the transform instead of the rigidbody and the render step is fighting with the physics step. But it’s not my case since I’m using Rigidbody2D.MovePosition to move it (I’ve also tried changing the rigidbody speed, but it didn’t worked)… Is it what the if that starts in line 111 of KinematicTopDownController.cs handles?

If you ask to move a kinematic body, it’ll be moved to that position, even if its into overlap but a Kinematic body doesn’t have a collision response so any jittery motion is motion you’ve told it to do.

Brilliant! Got it sorted now, working like a charm :slight_smile:

Thank you so much for your help and the news about 2023!

1 Like