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. Dismiss Notice

Question How would I keep a "Player's" momentum when jumping?

Discussion in 'Scripting' started by unity_43AD8A073163DE97E656, May 12, 2023.

  1. unity_43AD8A073163DE97E656

    unity_43AD8A073163DE97E656

    Joined:
    Jun 21, 2022
    Posts:
    1
    Hello. I am currently using an ever-so-slightly modified version of Brackey's unity First Person Character Controller, with edits such as normalizing the movement and adding a basic sprint function. I am working on jumping, and want the player character to keep their momentum with NO in-air control whilst in the air. I have tried to simply set player's walking speed to 0 if they are not grounded, which made the player completely stop before jumping. I have also tried saving the player's current momentum, and setting the velocity TO that momentum + what the jump power is. This made it work somewhat well (Although the movement itself, such as walking, was delayed slightly) and the player, upon contact with the ground, just kept that initial momentum. You had to jump again to change that momentum. Any help would be appreciated.
    Code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerMovement : MonoBehaviour
    6. {
    7.     public CharacterController controller;
    8.  
    9.     private float speed;
    10.     public float gravity = -9.81f;
    11.     public float jumpHeight = 2f;
    12.     Vector3 currentMomentum;
    13.  
    14.     public Transform groundCheck;
    15.     public float groundDistance = 0.4f;
    16.     public LayerMask groundMask;
    17.  
    18.     Vector3 velocity;
    19.     bool isGrounded;
    20.  
    21.     public float runSpeed = 20f;
    22.     public float walkSpeed = 12f;
    23.  
    24.    
    25.  
    26. // Update is called once per frame
    27. void Update()
    28.     {
    29.         isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
    30.  
    31.         if (isGrounded && velocity.y < 0)
    32.         {
    33.             velocity.y = -2f;
    34.         }
    35.  
    36.         float x = Input.GetAxis("Horizontal");
    37.         float z = Input.GetAxis("Vertical");
    38. if (Input.GetKey(KeyCode.LeftShift))
    39.         {
    40.             speed = runSpeed;
    41.         }
    42.         else
    43.         {
    44.             speed = walkSpeed;
    45.         }
    46.        
    47.         Vector3 move = transform.right * x + transform.forward * z;
    48.  
    49.         //Vector3 move = new Vector3(x, 0, z * transform.forward).normalized;
    50.         //if (isGrounded)
    51.         //{
    52.         controller.Move(move.normalized * speed * Time.deltaTime);
    53.         //}
    54.        
    55.  
    56.         if(Input.GetButtonDown("Jump") && isGrounded)
    57.         {
    58.             currentMomentum = controller.velocity;
    59.             velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
    60.         }
    61.  
    62.         velocity.y += gravity * Time.deltaTime;
    63.  
    64.         controller.Move(velocity * Time.deltaTime);
    65.     }
    66. }
    Sorry if I made some basic mistakes in formatting the post, this is my first one.
     
  2. SamRiot232

    SamRiot232

    Joined:
    Sep 15, 2022
    Posts:
    4
    Hi, I hope this helps.


    1. Create a player character object or use an existing one. Make sure it has a Rigidbody component.

    2. Create a script to control the player's movement and jumping behavior.

    3. In the script, declare variables to hold references to the player's Rigidbody component and a bool to check if the player is currently jumping. Add the following code:
    using UnityEngine;
    public class PlayerController : MonoBehaviour
    {
    private Rigidbody rb;
    private bool isJumping = false;
    void Start()
    {
    rb = GetComponent<Rigidbody>();
    }
    void Update()
    {
    if (Input.GetKeyDown(KeyCode.Space) && !isJumping)
    {
    Jump();
    }
    }
    void Jump()
    {
    float jumpForce = 5f; // Adjust this value to control the jump force
    rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
    isJumping = true;
    }
    void OnCollisionEnter(Collision collision)
    {
    if (collision.gameObject.CompareTag("Ground"))
    {
    isJumping = false;
    }
    }
    }

    4. Create a ground object or use an existing one, but make sure it has a collider component.
     
  3. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,588
    Brackeys is someone giving out free fish. Small code examples that do something and make people feel happy, without necessarily teaching them anything useful along the way. Instead i would recommend a tutorial that's actually trying to teach you how to fish by explaining exactly what's going on.

    For that purpose i usually recommend video of Sebastian Lague, if he covers a given topic. He has a brilliant beginner series on game development in general, which i would recommend you if you are just getting started:


    More on-topic, he also made a series about controlling a character. It covers quite a lot and starts in blender, actually modelling and animating the character. The scripting part for general movement, third person camera and jumping and collisions is covered in episodes 7, 8 and 9. The controller he develops there allows to adjust the percentage in which you can control movement while mid-air, so in your case, you'd then simply want to set it to 0.


    If you are just interrested in a quick overview of your problem, i would approach this by managing my own velocity vector. Your script contains one aswell, but i have no idea which parts come from brackeys and which you stitched in. So generally speaking i would do something like the below for a normal controller where you can still change directions in the air:
    1. Collect X-Z Inputs
    2. Adjust your own velocity vector to contain the new desired X-Z values
    3. Collect Jump Input
    4. If Grounded and Jump: Adjust your own velocity vector to contain the new desired Y value
    5. Apply your own gravity
    6. Call CharacterController.Move with your own velocity vector (times Time.deltaTime)
    Important to note: Move() is only supposed to be called once per frame, so you want to apply it all at once. In the above setup the only thing you should have to do to prevent movement in the air is to only adjust the X-Z values of your velocity vector while grounded aswell. As the velocity vector is a class variable, the values will persist into the next frame. You do still apply this velocity when you call Move(), and the only thing changing is gravity adjusting the .y component, until eventually you are brought back to ground and are in control again.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Throw it away. Just throw it away. The code you posted is clearly derived from defective Unity example code.

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

    If you call .Move() twice in one single frame, the grounded check may fail.

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

    https://docs.unity3d.com/ScriptReference/CharacterController.Move.html

    Here is a work-around:

    https://forum.unity.com/threads/how...racter-movement-in-unity.981939/#post-6379746

    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):

    https://forum.unity.com/threads/a-basic-first-person-character-controller-for-prototyping.1169491/

    That one has run, walk, jump, slide, crouch... it's crazy-nutty!!
     
    Yoreki likes this.