Why is Rigidbody controller unrealistically launching into the air upon traversing a steep slope?

UPDATE: I figured out it’s because I’m clamping X and Z velocity but not Y velocity, so I’m moving slowly forward but my Y velocity is allowed to just go insane. That being said, I don’t know an elegant solution of clamping Y velocity while still allowing Gravity to act ‘naturally’ on my Player rigidbody.


ORIGINAL POST:

Desired behavior: Controller gets slower upon hitting steep slope and/or isn’t able to move up it because it’s too steep

Current behavior: Controller can just run up a ramp and go completely airborne. Feels very physically unnatural. Gif of this happening:

delightfulmediumanteater

Why might this be happening? How might this board suggest altering the code to make the slope movement more natural?

Current code below…

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

public class Movement : MonoBehaviour
{
    Rigidbody r;
    public CapsuleCollider capsule;
    public Transform cameraTransform;

    //Base Movement
    public float horizontalInput;
    public float verticalInput;
    public Vector3 moveDirection;
    public Vector3 moveDirectionRaw;
    public int rotDegPerSecond = 720;
    public float speed;
    public float maxSpeed;

    //GroundChecking
    public LayerMask groundLayerMask;
    public Transform groundCheckTransform;
    public bool isGrounded;
    public float groundCheckRadius = 0.25f;
    public float distanceToGround;


    void Awake()
    {
        r = GetComponent<Rigidbody>();
        capsule = GetComponent<CapsuleCollider>();
    }

    void Update()
    {
        horizontalInput = Input.GetAxis("Horizontal");
        verticalInput = Input.GetAxis("Vertical");
    }

    private void FixedUpdate()
    {
        moveDirection = new Vector3(horizontalInput, 0.0f, verticalInput).normalized;
        moveDirection = (Quaternion.AngleAxis(cameraTransform.rotation.eulerAngles.y, Vector3.up) * moveDirection).normalized;
        moveDirectionRaw = new Vector3(Input.GetAxisRaw("Horizontal"), 0.0f, Input.GetAxisRaw("Vertical")).normalized;
        moveDirectionRaw = (Quaternion.AngleAxis(cameraTransform.rotation.eulerAngles.y, Vector3.up) * moveDirectionRaw).normalized;

        if (moveDirectionRaw != Vector3.zero && moveDirection != Vector3.zero)
        {
            Quaternion targetRotation = Quaternion.LookRotation(moveDirection); //or moveDirectionRaw
            targetRotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotDegPerSecond * Time.deltaTime);
            r.MoveRotation(targetRotation);
        }

        Vector3 force = moveDirection * speed;
        r.AddForce(force, ForceMode.Force);
        }     

        Vector3 velocityH = new Vector3(r.velocity.x, 0, r.velocity.z);
        Vector3 velocityV = new Vector3(0, r.velocity.y, 0);
        r.velocity = Vector3.ClampMagnitude(velocityH, 5) + velocityV;
        print(r.velocity.x + " " + r.velocity.y + " " + r.velocity.z);

        GroundStopSlide();
        GroundCheck();
    }

    void GroundStopSlide()
    {
        if (moveDirectionRaw == Vector3.zero)
        {
            Vector3 zeroMe = new Vector3(0, r.velocity.y, 0);
            r.velocity = zeroMe;
        }
    }

    public void GroundCheck()
    {
        isGrounded = Physics.CheckSphere(groundCheckTransform.position, groundCheckRadius, groundLayerMask);

    }


  
}

Most likely is about the code modifying the velocity of the rigidbody. Doing so overrides the calculations of the physics solver, which may result in unexpected effects. Removing any modification to r.velocity will cause a realistic behavior.

You may try modifying the velocity using AddForce with ForceMode.VelocityChange instead of changing r.velocity. If the issue persists, then the issue is in your calculations for the velocity.

You can modify the velocity of the rigidbody with AddForce like this:

rigidbody.AddForce(wantedVelocity - r.velocity, ForceMode.VelocityChange);
1 Like