Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

CharacterController Jumping/Gravity

Discussion in 'Scripting' started by Setrilo, Jul 19, 2015.

  1. Setrilo

    Setrilo

    Joined:
    Jul 19, 2015
    Posts:
    14
    This code is for a simple CharacterController which has the ability to move forward, backward, left, and right at various speeds. It is also supposed to have the ability to jump and be affected by gravity.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [RequireComponent(typeof(CharacterController))]
    5.  
    6. public class Controller : MonoBehaviour {
    7.  
    8.     public float moveSpeed;
    9.     public float backSpeed;
    10.     public float sideSpeed;
    11.     private float currentSpeed = 0;
    12.     public float jumpHeight;
    13.  
    14.     protected Vector3 move = Vector3.zero;
    15.     protected Vector3 gravity = Vector3.zero;
    16.     protected bool jump = false;
    17.  
    18.     CharacterController cc;
    19.  
    20.     // Use this for initialization
    21.     void Start()
    22.     {
    23.         cc = GetComponent<CharacterController>();
    24.     }
    25.  
    26.     // Update is called once per frame
    27.     void Update()
    28.     {
    29.         if (!cc.isGrounded)
    30.         {
    31.             gravity += Physics.gravity * Time.deltaTime;
    32.         }
    33.         else
    34.         {
    35.             gravity = Vector3.zero;
    36.  
    37.             if (Input.GetKeyDown(KeyCode.Space))
    38.             {
    39.                 jump = true;
    40.             }
    41.  
    42.             if (jump)
    43.             {
    44.                 gravity.y = jumpHeight;
    45.                 jump = false;
    46.             }
    47.         }
    48.  
    49.         if (Input.GetAxis ("Vertical") > 0)
    50.         {
    51.             currentSpeed = moveSpeed;
    52.         }
    53.         else
    54.         {
    55.             currentSpeed = backSpeed;
    56.         }
    57.  
    58.         var tempMove = Vector3.zero;
    59.         tempMove.y = Input.GetAxis("Vertical") * currentSpeed;
    60.         tempMove.x = -Input.GetAxis("Horizontal") * sideSpeed;
    61.         tempMove.z = gravity.y;
    62.  
    63.         move = transform.TransformDirection(tempMove);
    64.  
    65.         cc.Move(move * Time.deltaTime);
    66.     }
    67. }
    Any inefficient coding aside, there are basically three issues I've been running into:
    • Gravity gets more and more powerful the more times the character falls. When the character becomes ungrounded, his falling speed accelerates until he becomes grounded again. Once becoming ungrounded a second time, he will continue at the same accelerated pace from before, getting even faster the more times he falls.
    • The character does not jump when the spacebar is pressed.
    • The character walks faster when walking diagonally (up key and left/right key depressed) than forward (up key depressed).
    Everything else works perfectly. The character moves forward/backward and side to side just fine. I read somewhere that to fix the diagonal issue I should be normalizing the horizontal and vertical floats but I can't figure out where, and wouldn't that mess up the jumping/gravity (if either of those even worked properly)?
     
    Last edited: Jul 19, 2015
  2. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
    Have you set a value for jumpHeight in the inspector?
    You could try getting the axis values without the speed multiplier & find the velocity. If it is >1 then normalise it. Then multiply the x, y & z values by the speeds.
     
  3. Woodlauncher

    Woodlauncher

    Joined:
    Nov 23, 2012
    Posts:
    173
    the += expanded means this:
    Code (CSharp):
    1.  
    2. gravity = gravity + Physics.gravity * Time.deltaTime;
    3.  
     
  4. Setrilo

    Setrilo

    Joined:
    Jul 19, 2015
    Posts:
    14
    Thanks! I think since the directional values can be negative, Normalize(); wouldn't work for all four diagonal directions, so I ended up going with something like this:

    Code (CSharp):
    1.         var tempMove = Vector3.zero;
    2.         tempMove.y = Input.GetAxis("Vertical");
    3.         tempMove.x = -Input.GetAxis("Horizontal");
    4.         if (tempMove.y == 1 && tempMove.x == -1)
    5.         {
    6.             tempMove.y = 0.7071f;
    7.             tempMove.x = -0.7071f;
    8.         }
    9.         else if (tempMove.y == -1 && tempMove.x == -1)
    10.         {
    11.             tempMove.y = -0.7071f;
    12.             tempMove.x = -0.7071f;
    13.         }
    14.         else if (tempMove.y == 1 && tempMove.x == 1)
    15.         {
    16.            tempMove.y = 0.7071f;
    17.            tempMove.x = 0.7071f;
    18.         }
    19.         else if (tempMove.y == -1 && tempMove.x == 1)
    20.         {
    21.            tempMove.y = -0.7071f;
    22.            tempMove.x = 0.7071f;
    23.         }
    24.  
    25.         tempMove.y *= moveSpeed;
    26.         tempMove.x *= sideSpeed;
    27.         tempMove.z = gravity.y;

    It doesn't look pretty, but at least the diagonal problem is fixed. Also, jumpHeight is defined in the inspector at a very noticeable value.

    As far as the gravity/jumping situation, I have new insight. It appears to be that isGrounded is never becoming true, even when the character is clearly touching a plane. This would explain why everything is going wrong; the player can't jump and gravity will never reset unless he is grounded. What kinds of things could be causing isGrounded not to be true?
     
    Last edited: Jul 19, 2015
  5. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
    As a test out a tag on the ground. On the character put an OnTriggerEnter that checks if they are on The ground & sets the bool to true with an OnTriggerExit check that sets it to false. Not the most efficient way but it should help you check if the jumping then works. Just check your jumpHeight because if you've put it up massively high previously you may leave the game area once you get isGrounded working.
     
  6. Setrilo

    Setrilo

    Joined:
    Jul 19, 2015
    Posts:
    14
    OnTriggerEnter/OnTriggerExit fixed the issue with jumping and confirmed that the only problem is that isGrounded is never being reached.

    The ground in my world is a plane with a default mesh collider. Shouldn't this be making contact with the CharacterController and causing isGrounded to turn true? Is there maybe some alternate solution than setting all my floors to triggers with a "ground" tag?
     
  7. Setrilo

    Setrilo

    Joined:
    Jul 19, 2015
    Posts:
    14
    I think I figured out what the issue is. I believe isGrounded is never reaching true because there is no downward movement at that exact moment where I check the value of isGrounded. I tried adding the same check during a LateUpdate, as well as another Move call, and finally my character was able to jump.

    This is what I used:
    Code (CSharp):
    1. void LateUpdate()
    2.     {
    3.         if (cc.isGrounded)
    4.         {
    5.             gravity = Vector3.zero;
    6.            
    7.             if (Input.GetKeyDown(KeyCode.Space))
    8.             {
    9.                 jump = true;
    10.             }
    11.            
    12.             if (jump)
    13.             {
    14.                 gravity.y = jumpHeight;
    15.                 jump = false;
    16.             }
    17.         }
    18.         cc.Move(move * Time.deltaTime);
    19.     }
    The only problem is, doing this duplicates all the movements that my character performs. How could I reorganize my code so maybe I wouldn't have to use a LateUpdate and my movements aren't duplicated?
     
  8. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
    when you first start the game try setting isGrounded either to true or false because your gravity is being applied manually dependent upon the bool setting so if you start the game with the bool not being set it may not know what to do.
     
  9. Setrilo

    Setrilo

    Joined:
    Jul 19, 2015
    Posts:
    14
    Sweet, I just got it all to work. Thank you so much so your help!!
     
  10. Tobi_Chan

    Tobi_Chan

    Joined:
    Mar 16, 2022
    Posts:
    3
    Idk why, but my Character Controller has built in gravity, why is this?