Categories
Development Unity

Dash against slopes using physics in Unity 2D

I’m working on a 2D project in Unity.

The character controller is physics based, so I use rigidbody to move the player. Everything is working fine except when I try to apply a high speed movement to the character, like a dash.

This is how the code looks like.

I just check if the player is dashing, so I increase the Vector2 movement in a certain amount.

    private void DashMovement() {
        if (isDashing) {
            movement.x *= dashFactor;
        }
    }

I’m also calculating the ground angle, so I set the movement vector to follow the ground inclination.

     private void OnSlopeMovement() {
        if (isGrounded && !isJumping) {
            float moveDistance = Mathf.Abs(movement.x);
            float horizontalOnSlope = Mathf.Cos(groundAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(movement.x);
            float verticalOnSlope = Mathf.Sin(groundAngle * Mathf.Deg2Rad) * moveDistance;

            if (horizontalOnSlope != 0)
                movement.x = horizontalOnSlope;
            if (isGrounded && verticalOnSlope != 0)
                movement.y = verticalOnSlope;
        }

        SetMaxFallVelocity();
    }

So I set the rigidbody velocity for making it move.

    private void Move() {
        movement.x *= Time.fixedDeltaTime;
        if(isGrounded && !isJumping) movement.y *= Time.fixedDeltaTime;
        Vector3 targetVelocity = new Vector2(movement.x, movement.y);

        PlayerController.rb2d.velocity = Vector3.SmoothDamp(PlayerController.rb2d.velocity, targetVelocity, ref velocity, movementSmoothing);
    }

The problem appears when I apply a speed high enough. I understand this issue is because of physics.
I think the ray that checks the ground and is used to calculate the groundAngle doesn’t work fast enough to keep track of that movement, so I can not keep the player fixed on the ground.

I would like to find a solution without making the player kinematic, or stopping the dash on slopes.

This is how it looks ingame.

And this is how the rigidbody movement remain right over the ground, following the slopes angle.

EDIT:

This is how I get the ground angle:

private void GroundAngle() {
        Vector2 rayOrigin = feetCollider.bounds.center;
        rayOrigin.y += 0.1f;
        Vector2 rayDirection = (Input.GetAxisRaw("Horizontal") == 0) ? Vector2.right : new Vector2(Input.GetAxisRaw("Horizontal"), 0);

        int groundCollisions = Physics2D.RaycastNonAlloc(rayOrigin, Vector2.down, groundResults, Mathf.Infinity, groundMask);
        if (groundCollisions > 0) {
            groundAngle = Vector2.Angle(groundResults[0].normal, rayDirection) - 90f;
            //Debug.DrawRay(rayOrigin, Vector2.down, Color.green);
            if (groundAngle > 0 && !isDashing) {
                rayOrigin.x += Input.GetAxisRaw("Horizontal") * .125f;
                Physics2D.RaycastNonAlloc(rayOrigin, Vector2.down, groundResults, Mathf.Infinity, groundMask);
                groundAngle = Vector2.Angle(groundResults[0].normal, rayDirection) - 90f;
                //Debug.DrawRay(rayOrigin, Vector2.down, Color.blue);
            }
        } 
    }

Leave a Reply

Your email address will not be published. Required fields are marked *