Character controller based movement is not falling properly when hitting ceilings

I have set up a very basic character controller based first person movement script, just walking and jumping, but the jumping is not behaving as expected.

When I jump and the players head hits a ceiling, the player should fall back down, but with my current implementation, that is not happening.

Here is my script for reference, which i smostly based on an old brackeys tutorial:

public float speed = 12, jump = 12;
CharacterController characterController;
public Transform groundCheck;
public LayerMask ground;
Vector3 vel;
public float grav = -9.81f;
bool grounded;
void Start() 
    {
        characterController = GetComponent<CharacterController>();
    }
 private void Update() 
    {
        grounded = Physics.CheckSphere(groundCheck.position, 0.3f, ground);
        Debug.DrawLine(groundCheck.position, groundCheck.position + -Vector3.up*0.3f);

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

        Vector3 move = transform.right * x + transform.forward * z;
        Debug.Log(characterController.velocity.y);
        characterController.Move(move * speed * Time.deltaTime);
        if(!grounded)
        {
            vel.y += grav * Time.deltaTime * 2;
        }
        if(grounded)
        {
            if(Input.GetButtonDown("Jump"))
            {
                vel = Vector3.up * jump * 10;
            }else{
                if(vel.y <= 0)
                {
                vel = Vector3.zero;
                }
            }
        }

        characterController.Move(vel * Time.deltaTime);
    }

Any advice or fixes to my code would be much appreciated.

note that the * 10 in "vel = Vector3.up * jump * 10;" is just for testing purposes, and is not actually part of the problem.

–

2 Answers

2

The problem is you’re setting a jump velocity in your script and never resetting it to Vector3.zero if character controlelr stops moving up when the character isn’t grounded. Which means that if the character controller hits a ceiling, and physically stops moving upwards, your velocity vector in the script will keep trying to set an upwards velocity.

You can keep track of a bool when the player starts jumping:

vel = Vector3.up * jump * 10;
jumping = true;

Then in Update, if the player is jumping, but physically stops moving upwards, set your vel Vector to zero, which will then immediately cause the player to start falling downwards.

characterController.Move (vel * Time.deltaTime);

if (jumping){
  var ccVelocityY = characterController.velocity.y;		
  if (ccVelocityY <= 0f) {
    //CC stopped moving upwards
    vel = Vector3.zero;
    jumping = false;				
  }
}

this should in theory, work but ive tried numerous implementations of this same method and none have really worked out, yours included. thanks for the help though!

–

Why doesn't it work out for your situation? I tested this in a simple setup and it seems to work. Maybe you need to play with the jump and grav values.

–

I ended up just creating a checkshpere from an empty object i placed on the players head, and using that to determine whether they were hitting a ceiling, and that seemed to work.