How to correctly setup 3d Character Movement in Unity?

Welcome!

First, please use code tags: Using code tags properly when you post code.

But secondly, what is weird is that this is the second time recently that I’ve seen this code reported broken.

I went and investigated and what appears to have happened is that Unity’s example used to work back on earlier versions of Unity.

BUT… on more recent Unity versions, I concur with you that it presently does NOT work reliably, at least for jumping.

If I had to guess why, I believe it is their two separate calls to .Move() interfering with ground sensing in some way.

I have fixed the script here, and for me it is now 100% reliable, plus I fixed the jump height calculations, and let you jump reliably coming down ramps. See script below. Let me know if it works for you. You’ll be the second person running it after me. :slight_smile:

I will report it broken on their website, and meanwhile, enclosed is a fully-operational package including a jumpable miniature scene to get you started.

The main fixes I made are:

  • to only call .Move() once per frame, with a fully-fleshed out velocity instead of twice the way you are above (and the way the Unity sample shows)

  • to let “on ground” linger momentarily after you are not on the ground, to facilitate jumping even when you are “stumbling” down a ramp, which the original code failed on.

Meanwhile, ENJOY!

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

// Originally from Unity examples at:
// https://docs.unity3d.com/ScriptReference/CharacterController.Move.html
//
// 3:55 PM 10/3/2020
//
// Reworked by @kurtdekker so that it jumps reliably in modern Unity versions.
//
// To use:
//    - make your player shape about 1x2x1 in size
//    - put this script on the root of it
//
// That's it.

public class UnityExampleCharMover : MonoBehaviour
{
    private CharacterController controller;
    private float verticalVelocity;
    private float groundedTimer;        // to allow jumping when going down ramps
    private float playerSpeed = 2.0f;
    private float jumpHeight = 1.0f;
    private float gravityValue = 9.81f;

    private void Start()
    {
        // always add a controller
        controller = gameObject.AddComponent<CharacterController>();
    }

    void Update()
    {
        bool groundedPlayer = controller.isGrounded;
        if (groundedPlayer)
        {
            // cooldown interval to allow reliable jumping even whem coming down ramps
            groundedTimer = 0.2f;
        }
        if (groundedTimer > 0)
        {
            groundedTimer -= Time.deltaTime;
        }

        // slam into the ground
        if (groundedPlayer && verticalVelocity < 0)
        {
            // hit ground
            verticalVelocity = 0f;
        }

        // apply gravity always, to let us track down ramps properly
        verticalVelocity -= gravityValue * Time.deltaTime;

        // gather lateral input control
        Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));

        // scale by speed
        move *= playerSpeed;

        // only align to motion if we are providing enough input
        if (move.magnitude > 0.05f)
        {
            gameObject.transform.forward = move;
        }

        // allow jump as long as the player is on the ground
        if (Input.GetButtonDown("Jump"))
        {
            // must have been grounded recently to allow jump
            if (groundedTimer > 0)
            {
                // no more until we recontact ground
                groundedTimer = 0;

                // Physics dynamics formula for calculating jump up velocity based on height and gravity
                verticalVelocity += Mathf.Sqrt(jumpHeight * 2 * gravityValue);
            }
        }

        // inject Y velocity before we use it
        move.y = verticalVelocity;

        // call .Move() once only
        controller.Move(move * Time.deltaTime);
    }
}

EDIT: to jump continuously whenever you re-touch the ground (i.e., not have to keep spamming Jump), change line 69 above to GetButton() instead of GetButtonDown()

6379746–710721–UnityExampleCharMover.unitypackage (280 KB)

12 Likes