Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Resolved My jump physics are acting unpredictable.

Discussion in 'Physics' started by Bl00dyFish, Mar 3, 2024.

  1. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    125
    Hello.
    I've been working on a 3D Infinite Runner for the past week but came to an issue when it came to the physics of my character.

    I'm having a few issues relating to the way my Rigidbody-controlled character jumps:

    1) The jumps are unpredictable
    Whenever my character jumps, it either jumps really low, to the height it's supposed to, above the height it's supposed to, or waaaaaaay above the height it's supposed to and flies off the playing field and never comes back down because it is so high.

    2) The physics act slightly different on different devices
    The next issue comes from the jumps acting differently on different devices. A jump height of 100 gets me a way different jump height in the editor than in the Build. I made sure to use Time.deltaTime, which helped a little, but the difference is still there.

    Here is my player code if it helps:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5.  
    6. public class PlayerMove : MonoBehaviour
    7. {
    8.     private PlayerInput inputActions;
    9.  
    10.     [SerializeField] bool tapped;
    11.    
    12.     [SerializeField] Vector2 touchDelta;
    13.  
    14.     public float speed;
    15.     public float jumpHight;
    16.     public float downForce;
    17.    
    18.     public Rigidbody rb;
    19.     public bool isGrounded;
    20.     bool jump;
    21.  
    22.  
    23.     // Start is called before the first frame update
    24.     void Start()
    25.     {
    26.         inputActions = new PlayerInput();
    27.         inputActions.Enable();
    28.  
    29.         rb = GetComponent<Rigidbody>();
    30.  
    31.  
    32.     }
    33.  
    34.     // Update is called once per frame
    35.     void Update()
    36.     {
    37.         //determine if we are touching the screen
    38.         if(inputActions.Move.InitialTap.phase == InputActionPhase.Performed)
    39.         {
    40.             tapped = true;
    41.         }
    42.         else
    43.         {
    44.             tapped = false;
    45.         }
    46.  
    47.         if(tapped)
    48.         {
    49.            
    50.             touchDelta = inputActions.Move.TouchDelta.ReadValue<Vector2>();
    51.             float clampedX = Mathf.Clamp(transform.position.x, -9, 9);
    52.             transform.position = new Vector3(clampedX, transform.position.y, transform.position.z);
    53.  
    54.  
    55.  
    56.             //Move our player left or right if the absolute value of touchDelta.x value is greater than the absolute value of touchDelta.y
    57.             if(Mathf.Abs(touchDelta.x) > Mathf.Abs(touchDelta.y))
    58.             {
    59.                 rb.AddForce(Vector3.right * touchDelta.x * speed * Time.deltaTime, ForceMode.Impulse);
    60.             }
    61.          
    62.             if (touchDelta.y > touchDelta.x && touchDelta.y > 2.5 && isGrounded)
    63.             {
    64.                 print("jump");
    65.                 jump = true;
    66.             }
    67.             else
    68.             {
    69.                 jump = false;
    70.             }
    71.  
    72.         }
    73.  
    74.  
    75.     }
    76.  
    77.     void FixedUpdate()
    78.     {
    79.         RaycastHit hit;
    80.         Physics.Raycast(transform.position, Vector3.down, out hit, 0.5f);
    81.  
    82.         if(hit.collider != null)
    83.         {
    84.             isGrounded = true;
    85.         }
    86.         else
    87.         {
    88.             isGrounded = false;
    89.         }
    90.  
    91.  
    92.         rb.AddForce(Vector3.down * downForce * Time.deltaTime, ForceMode.Force);
    93.         if (jump)
    94.         {
    95.             rb.AddForce(Vector3.up * jumpHight * Time.deltaTime, ForceMode.Impulse);
    96.         }
    97.  
    98.     }
    99.  
    100.     private void OnCollisionEnter(Collision collision)
    101.     {
    102.         if (collision.gameObject.CompareTag("Obstacle"))
    103.         {
    104.             GameManager.GameOver();
    105.         }
    106.     }
    107. }
    And I'm also attaching a screenshot of the Ridgidbody settings I'm using:
    Screenshot 2024-03-03 121712.png
     
  2. POOKSHANK

    POOKSHANK

    Joined:
    Feb 8, 2022
    Posts:
    384
    first thing i noticed is you're using addforce in update, which is a big no no. only adjust rigidbodies in fixedupdate.

    you're also using .deltaTime which is what fixedupdate is made specifically to not have to use.

    fixedupdate is a set update rate so you're changing things that don't need to be. i don't remember if it returns the deltatime of update or fixedupdate when in fixedupdate, but either way you don't need it EVER in fixedupdate.

    use deltaTime exclusively in update or coroutines mostly
     
  3. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    125
    Ok, I changed every ridgidbody-related thing to fixed updated and removed deltaTime, but it still doesn't work.
    There's still a really weird height variation thing going on.

    Here is the updated code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5.  
    6. public class PlayerMove : MonoBehaviour
    7. {
    8.     private PlayerInput inputActions;
    9.  
    10.     [SerializeField] bool tapped;
    11.    
    12.     [SerializeField] Vector2 touchDelta;
    13.  
    14.     public float speed;
    15.     public float jumpHight;
    16.     public float downForce;
    17.    
    18.     public Rigidbody rb;
    19.     public bool isGrounded;
    20.     bool jump;
    21.  
    22.  
    23.     // Start is called before the first frame update
    24.     void Start()
    25.     {
    26.         inputActions = new PlayerInput();
    27.         inputActions.Enable();
    28.  
    29.         rb = GetComponent<Rigidbody>();
    30.  
    31.  
    32.     }
    33.  
    34.     // Update is called once per frame
    35.     void Update()
    36.     {
    37.         //determine if we are touching the screen
    38.         if(inputActions.Move.InitialTap.phase == InputActionPhase.Performed)
    39.         {
    40.             tapped = true;
    41.         }
    42.         else
    43.         {
    44.             tapped = false;
    45.         }
    46.  
    47.         if(tapped)
    48.         {
    49.            
    50.             touchDelta = inputActions.Move.TouchDelta.ReadValue<Vector2>();
    51.             float clampedX = Mathf.Clamp(transform.position.x, -9, 9);
    52.             transform.position = new Vector3(clampedX, transform.position.y, transform.position.z);
    53.  
    54.  
    55.             if (touchDelta.y > touchDelta.x && touchDelta.y > 2.5 && isGrounded)
    56.             {
    57.                 print("jump");
    58.                 jump = true;
    59.             }
    60.             else
    61.             {
    62.                 jump = false;
    63.             }
    64.  
    65.         }
    66.  
    67.  
    68.     }
    69.  
    70.     void FixedUpdate()
    71.     {
    72.         RaycastHit hit;
    73.         Physics.Raycast(transform.position, Vector3.down, out hit, 0.5f);
    74.  
    75.         if(hit.collider != null)
    76.         {
    77.             isGrounded = true;
    78.         }
    79.         else
    80.         {
    81.             isGrounded = false;
    82.         }
    83.  
    84.         //Move our player left or right if the absolute value of touchDelta.x value is greater than the absolute value of touchDelta.y
    85.         if (Mathf.Abs(touchDelta.x) > Mathf.Abs(touchDelta.y))
    86.         {
    87.             rb.AddForce(Vector3.right * touchDelta.x * speed, ForceMode.Impulse);
    88.         }
    89.        
    90.         rb.AddForce(Vector3.down * downForce, ForceMode.Force);
    91.         if (jump)
    92.         {
    93.             rb.AddForce(Vector3.up * jumpHight, ForceMode.Impulse);
    94.         }
    95.  
    96.     }
    97.  
    98.     private void OnCollisionEnter(Collision collision)
    99.     {
    100.         if (collision.gameObject.CompareTag("Obstacle"))
    101.         {
    102.             GameManager.GameOver();
    103.         }
    104.     }
    105. }
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    8,417
    Only thing I can think of is that your jump is probably executing over multiple FixedUpdate calls.

    Probably want to ensure that your jump code only happens for one FixedUpdate frame. You should reset your jump flag in the actual jump itself, too:
    Code (CSharp):
    1. if (jump)
    2. {
    3.     rb.AddForce(Vector3.up * jumpHight, ForceMode.Impulse);
    4.     jump = false;
    5. }
     
    POOKSHANK likes this.
  5. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    125
    Just tried this. It still doesn't work.
     
  6. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    8,417
    Please put more effort into debugging, rather than just 'tried this, doesn't work'.

    Did you ensure your tap input isn't triggering across multiple frames?
     
  7. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    125
    How would I check for this?
     
  8. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    8,417
    Same way the rest of us debug code, usually by either using Debug.Log to see how their code is executing, or attaching the debugger.

    In this situations, using some calls to Debug.Log will immediately answer this question for you.
     
  9. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    125
    Ok, I added a Debug.log right before the rb.AddForce is called for the jump.
    The number of times it is printed in the console varies from one to four times per jump.
     
  10. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    8,417
    Well there you go. You know now the issue is that your jump input is triggering for more than one frame.

    Now go investigate why that's happening, and fix that.
     
    Bl00dyFish likes this.
  11. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    125
    Alright! Fixed the issue.
    I needed to set isGrounded to false after jump was called just so the conditions for jumping couldnt be met in the few frames that my raycast detected ground.
     
    POOKSHANK and spiney199 like this.