I dont know why, but my character keeps teleporting to the ground when i step off a edge

// I belive it has to do with the raycasting

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

public class PlayerMovement : MonoBehaviour
{

    public CharacterController controller;

    private float speed = 12f;
    public float walkSpeed;
    public float sprintSpeed;
    public float gravity = -18f;
    public float jumpHeight = 3f;


    public MovementState state;

    public enum MovementState
    {
        walking,
        sprinting,
        air
    }

    [Header("Keybinds")]
    public KeyCode sprintKey = KeyCode.LeftShift;
    public KeyCode crouchKey = KeyCode.LeftControl;

    [Header("Crouching")]
    public float crouchSpeed;
    public float crouchYScale;
    private float startYScale;

    [Header("Ground")]
    public Transform groundCheck;
    public float groundDistance = 0.2f;
    public LayerMask groundMask;

    Vector3 velocity;
    bool isGrounded;



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

        velocity = AdjustVelocityToSlope(velocity);

        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        StateHandler();

        if (isGrounded && velocity.y < 0)
        {
            velocity.y += -0.1f;
        }

        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        Vector3 move = transform.right * x + transform.forward * z;


        controller.Move(move * speed * Time.deltaTime);

        // start crouch
        if(Input.GetKeyDown(crouchKey))
        {
            transform.localScale = new Vector3(x = 1f, crouchYScale = 0.5f, z = 1f);
            velocity.y = -8f;

            jumpHeight = 1f;

        }

        // stop crouch
        if(Input.GetKeyUp(crouchKey))
        {
            transform.localScale = new Vector3(x = 1f, crouchYScale = 1f, z = 1f);
            velocity.y =0f;
            jumpHeight = 2f;
        }


        // When to jump
        if(Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
        }

        velocity.y += gravity * Time.deltaTime;

        controller.Move(velocity * Time.deltaTime);
    }

    private void StateHandler()
    {

        //Mode - Sprinting
        if(isGrounded && Input.GetKey(sprintKey))
        {
            state = MovementState.sprinting;
            speed = sprintSpeed;
        }

        //Mode - Walking
        else if (isGrounded)
        {
            state = MovementState.walking;
            speed = walkSpeed;
        }

        //Mode - Air
        else
        {
            state = MovementState.air;
        }

       
    }

    private Vector3 AdjustVelocityToSlope(Vector3 velocity)
    {

        var ray = new Ray(transform.position, Vector3.down);

        if(Physics.Raycast(ray, out RaycastHit hitinfo, 0.2f))
        {
            var slopeRotation = Quaternion.FromToRotation(Vector3.up, hitinfo.normal);
            var adjustedVelocity = slopeRotation * velocity;

            if(adjustedVelocity.y < 0)
            {
                return adjustedVelocity;
            }
        }

        return velocity;
    }

}

You are never zeroing your y velocity except when uncrouching.

I see the above code unfortunately appears to be derived from the faulty Unity example code. This code will always and forever have issues with properly detecting grounded-ness because it calls .Move() twice in the same frame.

I wrote about this before: the Unity example code in the API no longer jumps reliably.

I reported it to Unity via their docs feedback in October 2020. Apparently it is still broken:

Here is a work-around:

I recommend you also go to that same documentation page and ALSO report that the code is broken.

When you report it, you are welcome to link the above workaround. One day the docs might get fixed.

If you would prefer something more full-featured here is a super-basic starter prototype FPS based on Character Controller (BasicFPCC):

That one has run, walk, jump, slide, crouch… it’s crazy-nutty!!

1 Like

what do you mean?

Seems pretty straightforward. You are letting the character build up vertical velocity from gravity always via velocity.y += gravity * Time.deltaTime; So that even while it’s on the ground, it’s accumulating speed. By the time you go over a cliff you have such massive velocity that you appear to “teleport” instantly to the ground.

1 Like

Ok, how do you recomend i fix this?

Impart forces directly on a rigidbody to achieve more realistic movement, or just set your velocity.y to 0 whenever the character isGrounded. Specifically, don’t do what you’re doing on line 93. You’re constantly accelerating the object downward even when it is grounded.