Character movement on slopes and detecting ground with raycast.

Hello i need a help how to set this up.

My problem is i have a player that can walk,jump and run but when he runs/walks down the slopes he jumps.

I have been trying for days trying to fix this and i found the best way of fixing this is with raycast but i have no idea how to make it so when the raycast hits the ground it will make the player stick to the ground while walking down the slopes and allowing him to jump,run and walk.

      public float walkSpeed = 10f;
        public float runSpeed = 20f;
  
        public Camera cameraPlayer;
        private float mouseSensitivity = 2.0f;
        public Vector2 LookRange = new Vector2(-60f, 60f);
        float mouseX;
        float mouseY;
  
        CharacterController charController;
  
        public float gravity = -12f;
        public float jumpHeight = 1f;
        float velocityY;
  
        float currentSpeed;
  
        public float turnSmoothTime = 0.2f;
        float turnSmoothVelocity;
        public float speedSmoothTime = 0.1f;
        float speedSmoothVelocity;
  
        public float rayDistance = 0.5f;
        bool grounded;
  
        private void Start()
        {
            charController = GetComponent<CharacterController>();
          
        }
        private void Update()
        {
            Vector3 input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
            Vector3 directionInput = input.normalized;
            bool running = Input.GetKey(KeyCode.LeftShift);
  
            //transform.Translate(moveAmount);
            transform.Rotate(0, mouseX, 0);
  
            mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
            mouseY -= Input.GetAxis("Mouse Y") * mouseSensitivity;
            mouseY = Mathf.Clamp(mouseY, LookRange.x, LookRange.y);
            cameraPlayer.transform.localRotation = Quaternion.Euler(mouseY, 0, 0);
  
            if (Input.GetKeyDown(KeyCode.Space))
            {
                Jump();
            }
            MoveThePlayer(directionInput,running);
  
        }
      
  
    void MoveThePlayer(Vector3 directionInput,bool running)
        {
            Vector3 moveAmount = directionInput;      
  
            moveAmount = transform.TransformDirection(moveAmount);
  
            float targetSpeed = ((running) ? runSpeed : walkSpeed) * directionInput.magnitude;
  
            currentSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed, ref speedSmoothVelocity, GetModifiedSmoothTime(speedSmoothTime));
          
            Vector3 velocityMovement = moveAmount * currentSpeed + Vector3.up * velocityY;
  
            charController.Move(velocityMovement * Time.deltaTime);
  
            velocityY += Time.deltaTime * gravity;
            currentSpeed = new Vector2(charController.velocity.x, charController.velocity.z).magnitude;
            if (charController.isGrounded)
            {
                velocityY = 0;
            }
  
  
            Ray ray = new Ray(transform.position, -transform.up);
            RaycastHit hitInfo;
  
            if(Physics.Raycast(ray,out hitInfo, rayDistance))
            {
                transform.position = hitInfo.point;
                Debug.DrawLine(ray.origin, ray.origin * rayDistance, Color.green);
            }
  
          
  
        }
  
        void Jump()
        {
            if (charController.isGrounded)
            {
                float jumpVelocity = Mathf.Sqrt(-2 * gravity * jumpHeight);
                velocityY = jumpVelocity;
            }
        }
        float GetModifiedSmoothTime(float smoothTime)
        {
            if (charController.isGrounded)
            {
                return smoothTime;
            }
            return smoothTime;
        }
    }

When you say the character jumps, do you mean just leaves the ground?
You could try this: Unity - Scripting API: Vector3.ProjectOnPlane

When you raycast, take a small amount up (into your collider, in other words), and then raycast down a small amount (but bigger than up, obviously).
When you get the hit.normal from the ground, you use that in project on plane.

I’ve only used this a little bit, and never with a character controller… but it was something I had planned on adding (back into) my character’s movement script.:slight_smile:

1 Like

I have never thought about it.Thank you i will try that.

No problem. That’s what the default 3rd person rigidbody char. uses from Standard assets :slight_smile:

1 Like

Ok so i have managed to fix this not by using raycast but by using CollisionFlags.

Here is the working code with jumping,moving and moving down the slopes.
Feel free to use it

    Ok so i have managed to fix this not by using raycast but by using CollisionFlags.

    Here is the working code with jumping,moving and moving down the slopes.
    Feel free to use it

    Code (CSharp):

        
            //Movement variables//
            public float walkSpeed = 6f;
            public float runSpeed = 12f;
        
            //Camera variables//
            public Camera cameraPlayer;
            private float mouseSensitivity = 2.0f;
            public Vector2 LookRange = new Vector2(-60f, 60f);
            float mouseX;
            float mouseY;
        
            //Gravity and gravity helper variables//
            public float gravity = -12f;
            public float jumpHeight = 1f;
            float velocityY;
        
            //Helper variables//
            public float turnSmoothTime = 0.2f;
            float turnSmoothVelocity;
            public float speedSmoothTime = 0.1f;
            float speedSmoothVelocity;
            float currentSpeed;
            bool GROUNDED;
        
            //Componenents and script access//
            CharacterController charController;
        
            private void Start()
            {
                charController = GetComponent<CharacterController>();
        
        
                Cursor.lockState = CursorLockMode.Locked;
                Cursor.visible = false;
                  
            }
            private void Update()
            {
                //Getting controlls//
        
                //MOVMENT//
                Vector3 input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
                Vector3 directionInput = input.normalized;
                bool running = Input.GetKey(KeyCode.LeftShift);
        
                //CAMERA//
                mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
                mouseY -= Input.GetAxis("Mouse Y") * mouseSensitivity;
        
                transform.Rotate(0, mouseX, 0);     
                mouseY = Mathf.Clamp(mouseY, LookRange.x, LookRange.y);
                cameraPlayer.transform.localRotation = Quaternion.Euler(mouseY, 0, 0);
        
                if (GROUNDED)
                {
                    if (Input.GetKey(KeyCode.Space))
                    {
                        Jump();
                    }
                }
                else
                {
                    velocityY += Time.deltaTime * gravity;
                }
        
                Vector3 moveAmount = directionInput;
        
                moveAmount = transform.TransformDirection(moveAmount);
        
                float targetSpeed = ((running) ? runSpeed : walkSpeed) * directionInput.magnitude;
                currentSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed, ref speedSmoothVelocity, GetModifiedSmoothTime(speedSmoothTime));
        
                Vector3 velocityMovement = moveAmount * currentSpeed + Vector3.up * velocityY; 
                currentSpeed = new Vector3(charController.velocity.x,0 ,charController.velocity.z).magnitude;
        
                CollisionFlags flags = charController.Move(velocityMovement * Time.deltaTime);
                GROUNDED = ((flags & CollisionFlags.Below) != 0);
            }
        
            float GetModifiedSmoothTime(float smoothTime)
            {
                if (charController.isGrounded)
                {
                    return smoothTime;
                }
                return smoothTime;
            }
        
            void Jump()
            {
                float jumpVelocity = Mathf.Sqrt(-2 * gravity * jumpHeight);
                velocityY = jumpVelocity;
            }
        }

Cool :slight_smile: Glad ya got it working.

1 Like