Ora

How do you make a character controller jump in unity?

Published in Character Movement 6 mins read

To make a character jump in Unity, you apply an upward force or adjust the vertical component of the character's movement vector when a jump input is detected, ensuring the character is grounded beforehand. This process varies slightly depending on whether you're using Unity's built-in CharacterController component or a Rigidbody for physics-based movement.

Understanding the Core Jump Mechanics

At its foundation, a jump is the application of an upward velocity to a character. In Unity, this typically means manipulating the y component of the character's velocity vector.

  • Jump Power/Height: You'll define a variable, often called jumpPower or jumpHeight, which dictates the strength or height of the jump.
  • Velocity Adjustment: When the jump action is triggered, the character's current vertical velocity is set or incremented by this jump value. For instance, you might directly set velocity.y to your jumpPower or calculate an initial velocity based on a desired jumpHeight to counteract gravity.

Implementing a Jump with Unity's CharacterController

Unity's CharacterController is designed for first and third-person player movement that is not entirely physics-driven, but still interacts with collisions. It provides robust collision detection without applying actual physics forces like momentum or torque.

1. Script and Component Setup

  1. Attach Components:

    • Add a CharacterController component to your character GameObject.
    • Create a new C# script (e.g., PlayerMovementController) and attach it to the same GameObject.
  2. Declare Variables: In your script, define variables for movement speed, jump strength, and gravity.

    using UnityEngine;
    using UnityEngine.InputSystem; // For the new Input System
    
    [RequireComponent(typeof(CharacterController))]
    public class PlayerMovementController : MonoBehaviour
    {
        private CharacterController controller;
        private Vector3 playerVelocity; // Stores the character's current velocity
        private bool isGrounded; // Checks if the character is on the ground
    
        public float playerSpeed = 5.0f;
        public float jumpHeight = 1.2f; // How high the character jumps
        public float gravity = -9.81f; // Standard gravity
    
        // For the new Input System (assign in Inspector)
        public PlayerInput playerInput;
        private InputAction jumpAction;
        // ... (other actions like 'Move')

2. Initialize and Grounded Check

In the Awake or Start method, get a reference to the CharacterController. The Update method is where you'll handle gravity and check if the character is touching the ground.

    void Awake()
    {
        controller = GetComponent<CharacterController>();
        if (playerInput != null)
        {
            jumpAction = playerInput.actions["Jump"]; // Replace "Jump" with your actual action name
            // ... (initialize other actions)
        }
    }

    void OnEnable()
    {
        jumpAction?.Enable();
        jumpAction?.performed += OnJump; // Subscribe to the jump action event
    }

    void OnDisable()
    {
        jumpAction?.performed -= OnJump; // Unsubscribe
        jumpAction?.Disable();
    }

    void Update()
    {
        isGrounded = controller.isGrounded; // Use CharacterController's built-in ground check
        if (isGrounded && playerVelocity.y < 0)
        {
            playerVelocity.y = -2f; // Apply a small downward force to keep grounded
        }

        // Apply gravity constantly
        playerVelocity.y += gravity * Time.deltaTime;

        // Apply the total movement, including vertical velocity from gravity/jump
        controller.Move(playerVelocity * Time.deltaTime);
    }

For more information, refer to the Unity CharacterController Documentation.

3. Jump Input and Application

You need to detect when the player initiates a jump and, if the character is grounded, apply the upward velocity.

  • Old Input Manager (Input.GetButtonDown):

    // Inside Update()
    if (Input.GetButtonDown("Jump") && isGrounded)
    {
        // Set the upward velocity directly
        playerVelocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
        // This is equivalent to applying 'jump power' to the vertical velocity.
    }
  • New Unity Input System: This system provides a more flexible and event-driven approach. You connect your jump action to a method that will be called when the input is performed.

    // This method is called when the "Jump" action is performed
    private void OnJump(InputAction.CallbackContext context)
    {
        if (isGrounded)
        {
            // Apply upward velocity: this effectively means 'velocity += jump power'
            // Calculate initial velocity required to reach 'jumpHeight' against 'gravity'
            playerVelocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
        }
    }

    To set up input actions:

    1. Click on your Player Input object in the Hierarchy.
    2. In the Inspector, locate the Events section and then the Gameplay section (or your custom Action Map).
    3. Ensure your Jump action is configured, and its performed event can be subscribed to programmatically as shown above.
      You can learn more about the new Input System in the Unity Input System Documentation.

Implementing a Jump with Rigidbody

For characters that require full physics interactions (e.g., being pushed by explosions, realistic collisions), a Rigidbody component is used.

  1. Setup:

    • Add a Rigidbody component to your character (uncheck Is Kinematic).
    • Add a Collider component (e.g., CapsuleCollider).
    • Create and attach a C# script (e.g., PlayerRigidbodyMovement).
  2. Declare Variables:

    using UnityEngine;
    
    public class PlayerRigidbodyMovement : MonoBehaviour
    {
        private Rigidbody rb;
        public float jumpForce = 8f; // The force applied for a jump
        private bool isGrounded;
        public Transform groundCheck; // An empty GameObject at the feet for ground checking
        public LayerMask groundLayer;
        public float groundCheckRadius = 0.2f;
  3. Initialization and Grounded Check: For Rigidbody, gravity is often handled automatically. A custom ground check is typically needed. Physics updates should occur in FixedUpdate.

    void Awake()
    {
        rb = GetComponent<Rigidbody>();
    }
    
    void FixedUpdate() // Use FixedUpdate for physics operations
    {
        // Custom ground check using a sphere overlap
        isGrounded = Physics.CheckSphere(groundCheck.position, groundCheckRadius, groundLayer);
    }

    For ground checking, refer to Unity Physics.CheckSphere Documentation.

  4. Jump Input and Application:

    void Update() // Input detection usually in Update
    {
        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
        }
    }
    • ForceMode.Impulse applies an instant force, suitable for jumps.

For more details on physics-based movement, consult the Unity Rigidbody Documentation.

Comparing CharacterController and Rigidbody for Jumping

Feature CharacterController Rigidbody
Physics Manages collisions but does not directly use physics forces for movement. Fully physics-driven, responds to gravity, forces, torque.
Movement Control Achieved via controller.Move(), you manage velocity. Controlled via rb.velocity or rb.AddForce().
Gravity Must be manually applied in your script. Handled automatically by Unity's physics engine.
Jumping Method Direct manipulation of playerVelocity.y. rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
Grounded Check Built-in controller.isGrounded property, or custom. Requires a custom implementation (e.g., Physics.CheckSphere).
Best For Player characters needing precise, non-physics-based movement. Physics-based characters or objects requiring realistic interactions.

Key Considerations and Best Practices

To enhance your character's jump behavior:

  • Reliable Ground Check: Ensure your grounded check is accurate and prevents "mid-air jumps" while allowing jumps when barely touching the ground.
  • Variable Jump Height: Allow the player to hold the jump button longer for a higher jump. This can be done by applying a continuous upward force for a short duration while the button is pressed, or by progressively reducing gravity after the initial jump impulse.
  • Coyote Time: Implement a brief window after leaving a platform where the character can still jump. This makes platforming feel more forgiving.
  • Jump Buffer: Store jump input for a short duration, so if the player presses jump just before landing, the jump executes immediately upon touching the ground.
  • Jump Cooldown: Prevent "jump spamming" by adding a short delay between jumps.
  • Animations: Integrate jump animations (start, mid-air, landing) to provide visual feedback and improve player experience.