i cant understand why my player keep bumping on slopes

i followed a tutorial showing how to fix slopes on your game, i saw that the tutorial used projectonplane
to it’s vector3 would be perpendicular to the slope. but i keep getting small bumps

dik0de

this was the tutorial by the way

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

public class PlayerMovement : MonoBehaviour
{


    // jump button UI event
    public JumpButtonEvent jumpBtn;

    // player game object components
    public AudioSource ballBounceSFX;
    public Rigidbody playerRb;
    public Collider playerCollider;

    // camera
    public Transform gameCamera;

    // movement properties
    public Vector3 playerVector;
    public float movementSpeed;
    public float jumpSpeed;
    public float jumpForce = 50f;
    public bool isJumping = false;
    public bool isMoving = false;
    public FixedJoystick joystickMove;
    public float x;
    public float y;   
    public float z;
    public float gravity = 2f;


    //overlap sphere colliders

    public float sphereRadiusNew;
    public Collider[] overlapSphereColliders;

    // raycast

    public bool isGrounded = false;
    RaycastHit hitInfo;
    RaycastHit slopeHit;
    Vector3 raycastDirection;   
    public LayerMask raycastLayers;
    public float sphereRadius = 0.1f;   
    public float castDistance = 0.01f;
    public float slopeCastDistance = 1f;
    public float slopeSpeed = 1f;   
    Vector3 slopeMoveDirection;

    Vector3[] surfaceNormal;

    private void Awake()
    {       
        raycastDirection = Vector3.down;       
    }

    // Start is called before the first frame update
    void Start()
    {
       
    }

     public void MovementAndJump()
      {
        Quaternion cameraRot = Quaternion.Euler(0, gameCamera.eulerAngles.y, 0); // convers camera quaternion to euler, to be able to rotate the camera in euler angles (rotation axis from inspector)



          x = joystickMove.Horizontal;
         z = joystickMove.Vertical;

         playerVector = cameraRot * new Vector3(x, 0, z) * movementSpeed; // the playervector input will have the x and z values. y is added later
        


        if(IsGrounded() == true && isMoving == true)
        {
            playerRb.drag = 15f;
        }

       

       if (isMoving == false && IsGrounded() == true)
        {           
            playerRb.velocity = Vector3.zero;
            playerRb.drag = 0f;
        }

       if(OnSlope() == true)
        {
            playerRb.drag = 0f;
        }

        if (isJumping == false && jumpBtn.jumpBtnClicked == true && IsGrounded() == true)
         {
           
            Vector3 jumpVector = new Vector3(0, jumpForce, 0);
            playerRb.AddForce(jumpVector, ForceMode.Impulse);           
            isJumping = true;           
         }

       if(isJumping == true)
        {
            playerRb.drag = 0f;
        }

         if (isJumping == true && IsGrounded() == false)
         {           
            playerVector.y = playerVector.y - gravity; // if player is mid-air (jumping) the vertical movement will be subtracted to the gravity, making the gravity pushing the player to the ground           
         }

         if(isJumping == true && isMoving == true)
        {           
            playerRb.velocity = new Vector3(playerVector.x * jumpSpeed, playerRb.velocity.y, playerVector.z * jumpSpeed); // when jumping will create a new vector that will move according to the value on playerVector.x and playerVector.z multiplying by a moving speed on jump
        }

        


         if (joystickMove.Horizontal == 0 && joystickMove.Vertical == 0 /*&& Input.GetAxis("Horizontal") == 0 && Input.GetAxis("Vertical") == 0*/)
         {
             isMoving = false;           
        }

         else
         {
             isMoving = true;
           
         }

        // moving rigidbody (player)
        playerRb.AddForce(playerVector, ForceMode.VelocityChange);




    }

    // Update is called once per frame
    void Update()
    {
       
       
       
    }

    private void FixedUpdate()
    {
        OnSlope();
        IsGrounded();
        MovementAndJump();      


    }



   

   public bool IsGrounded() // cria uma funçao bool que verifica se o player está no chão ou não
    {
        if (Physics.SphereCast(playerCollider.bounds.center, sphereRadius, raycastDirection, out hitInfo, castDistance, raycastLayers))
        {
            Debug.Log(hitInfo.normal);

            if (hitInfo.collider.gameObject.layer == 7 || hitInfo.collider.gameObject.layer == 8) // se o layer do objeto que o raycast bateu for 7(Ground) então retorna um valor TRUE(significando que o play esta no chao)
            {               
                Gizmos.color = Color.green;
                Debug.Log(hitInfo.collider);
                Debug.Log("TOUCHING GROUND!");               
                gameObject.transform.parent = null;
                isJumping = false;              
                return true;
            }

            else if (hitInfo.collider.gameObject.layer == 6)
            {
                Gizmos.color = Color.green;
                Debug.Log(hitInfo.collider);
                Debug.Log("TOUCHING GROUND!");
                gameObject.transform.SetParent(hitInfo.collider.transform, true);
                isJumping = false;               
                return true;
            }

            else if (hitInfo.collider == null) // se o raycast nao detetar qualquer collider, o player nao está no chao
            {
                Gizmos.color = Color.red;
                gameObject.transform.parent = null;
                isJumping = true;               
                return false;
            }

            else // se o raycast nao detetar qualquer collider, o player nao está no chao
            {
                gameObject.transform.parent = null;
                isJumping = true;               
                return false;
            }
        }

       
        gameObject.transform.parent = null;
        isJumping = true;       
       
        return false; // if the player isn't touching the ground he is jumping and not on any platform


    }



    public bool OnSlope()
    {

        if (Physics.Raycast(playerCollider.bounds.center, raycastDirection, out slopeHit, slopeCastDistance))
        {
            Debug.Log(slopeHit.normal);

            if (slopeHit.normal != Vector3.up)
            {
                Debug.Log("I'm on slope");
               
               
                  slopeMoveDirection = Vector3.ProjectOnPlane(playerVector, slopeHit.normal);  // projects a vector3 that is perpendicular to a normal surface
                  playerRb.AddForce(slopeMoveDirection.normalized, ForceMode.VelocityChange); // the velocity will be the playervector + slopemovedirection, which means the vector will move in slope direction
                return true;
            }

        }
        return false;
    }


    private void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawRay(playerCollider.bounds.center, Vector3.down * castDistance);
        Gizmos.DrawSphere(playerCollider.bounds.center, sphereRadius);

        Gizmos.color = Color.yellow;
        Gizmos.DrawRay(playerCollider.bounds.center, Vector3.down * slopeCastDistance);

        Gizmos.color = Color.green;
        Gizmos.DrawSphere(playerCollider.bounds.center, sphereRadiusNew);
    }


    // on collision frame
    private void OnCollisionEnter(Collision collision)
    {
      

        if (collision.gameObject.layer == 6 && IsGrounded() == true || collision.gameObject.layer == 7 && IsGrounded() == true || collision.gameObject.layer == 8 && IsGrounded() == true) // if the player hits one of these layers when colliding with them on colliding frame
        {
            ballBounceSFX.Play(); // play the bouncing ball sfx
        }
    }

}

Note how your player is actually spinning… one possibility is that the spin force is pushing him into the air.

You stop him from spinning when he’s stationary: just set the angularVelocity to Vector3.zero.

i was also wondering why it was always spinning, the angular velocity fixed it
but not for the bumping sadly

Try debugging what vector movement your project on pane is actually using, just print it out with Debug.Log()

Using a known piece of geometry, like a plate at exactly X angle, you can use trig to figure out what that vector should be, compare it to what you’re getting, then make sure that’s exactly what you are using to move.

To supplement that, let me give you my Debug.Log() primer:

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also put in Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

If you are running a mobile device you can also view the console output. Google for how on your particular mobile target.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

#1 tip of debugging I ever got was this : Find a way to get the information you need in order to reason about what the problem is. So simple it sounds almost stupid.

If you’re trying to apply a force in direction of the slope but that’s not happening and you don’t know why, draw a line in the scene from the base of the player in the direction and magnitude of the force you’re applying (scaled up or down to some size that makes sense) to confirm your math.

Debug.DrawLine and Gizmos.DrawLine are you absolute best friends for digging into stuff like this. I’ll often draw out down each force and transformation I’m doing in different colors to try and make sure my understanding of the math aligns what the code I’ve written. Most of the time this is where I’ll see the problem and can then reason about to make my code mirror my brain’s intent.

My brain is rubbish at doing space transformation and visualising complex vector math unaided so I also have an editor only debugging library for drawing arrows, polylines, curves, circles, parabola, meshes etc etc. It’s probably my most used tool when working on physics based gameplay or procedural meshes.

1 Like