Search Unity

Inconsistent jump height... and I've tried it all

Discussion in 'Scripting' started by Nicris, Sep 25, 2017.

  1. Nicris

    Nicris

    Joined:
    May 12, 2014
    Posts:
    21
    I'm having a very tough time with what I thought would be very easy... jumping for a 2D platformer.

    Almost every time I jump, I get the height I want. But like 1 time out of every 10, it randomly will go like 1/5th the height it should go:

    Code (CSharp):
    1.     public Rigidbody2D theRigidbody;
    2.     public float speed;
    3.     public float jumpPower;
    4.  
    5.     void Start () {
    6.         theRigidbody = GetComponent<Rigidbody2D>();
    7.     }
    8.  
    9.     void Update () {
    10.  
    11.         if(Input.GetKeyDown(KeyCode.W) && Game.playerGrounded == true)
    12.         {
    13.             //Vector3 jumpForce = new Vector2(theRigidbody.velocity.x, jumpPower);
    14.             theRigidbody.velocity = new Vector2(theRigidbody.velocity.x, jumpPower);
    15.             //theRigidbody.AddForce(jumpForce, ForceMode2D.Impulse);
    16.             Debug.Log("Jumped at velocity" + theRigidbody.velocity);
    17.         }
    18.  
    19.         if(Input.GetAxis("Horizontal") > 0)
    20.         {
    21.             theRigidbody.velocity = new Vector2(speed * Time.deltaTime, theRigidbody.velocity.y);
    22.         }
    23.         else if(Input.GetAxis("Horizontal") < 0)
    24.         {
    25.             theRigidbody.velocity = new Vector2(-speed * Time.deltaTime, theRigidbody.velocity.y);
    26.         }
    27.         else
    28.         {
    29.             theRigidbody.velocity = new Vector2(0,theRigidbody.velocity.y);
    30.         }
    31.  
    32.     } // end Update
    The console's output for "Jumped at velocity" + the rigidbody's velocity, weirdly enough, ALWAYS shows a consistent number for the Y velocity (25.0), even when the jump height is way lower. It's like the velocity's being set consistently, but then instantly slowing down?... Here's what it looks like:

    upload_2017-9-24_23-3-33.png

    I've looked up countless threads and QnA's and tried using AddForce with mode Impulse, tried putting the Input command in FixedUpdate instead of Update, messed with Iteration Counts... none of it has worked. Putting it in FixedUpdate seemed to help with height consistency, but then it would miss some of my keystrokes, and others said it needs to be in Update for that reason.

    Thank you in advance for any help!
     
  2. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    I think you may have conflicting results because you have two "if's" and then start with if/else, so a horizontal will negate the jump vector if they coincide. I'm not sure if that's the case, but it might be better to collect the velocities and only make one new vector at the end of all the clauses.
     
    Last edited: Sep 25, 2017
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    Your code should be good. Usually you should work with rigidbodies in FixedUpdate for consistency, but since you're setting the velocity directly, it won't matter.

    Game.playerGrounded seems suspicious. You're checking in a different, global script if the player is on the ground. Maybe Game is editing the velocity?
     
  4. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    From the first glance it makes perfect sense. Once you press the jump input key, you set the velocity value directly and right afterwards log the velocity value... nothing has changed the value in the meantime, because physics have not run at this point - Update is still in progress and both execute on the same thread (main thread).
    If you logged the velocity value frequently in Update (i.e. outside of your input part of the code) you should see a changing value over time.

    That's because FixedUpdate and Update do not run in a ratio of 1:1 and the Input will be resetted at some point in each update cycle. There may be 0, 1 or multiple physics updates after one Update has completed, because it sometimes needs to catch up (depending on the time the update logic has taken and the fixed time step set in the settings).

    Thus input should always be queried in a function that is related to Update and should be avoided in FixedUpdate and other physics-related callbacks of the engine, as well as in methods you call from these, naturally.

    However, you can wait for input in Update, store the information in a variable and process it in FixedUpdate.
     
  5. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    So one thing you haven't tried is ditching the physics engine entirely (or, at least for your player character). The physics engine is great for making Angry Birds type games with lots of blocks you can knock over, but it's lousy for giving you fine control or consistent results. See here for how I handle running and jumping.
     
  6. Nicris

    Nicris

    Joined:
    May 12, 2014
    Posts:
    21
    Can't tell you guys how relieved I am to see these answers - thank you all!

    To the problem at hand - still not there, but we're getting closer. For further clarity, my problem is happening when spam-jumping to test how durable the controls are.

    Correct, different global script. Script is stored in a Game Manager object with a script that declares playerGrounded. In that blue object (the Ground Checker), I had this script:
    Code (CSharp):
    1.     void OnTriggerEnter2D()
    2.     {
    3.         Game.playerGrounded = true;
    4.     }
    5.     void OnTriggerExit2D()
    6.     {
    7.             Game.playerGrounded = false;
    8.     }
    To confirm anyway, I know it's not editing the velocity, because I did a test by removing the condition that playerGrounded be true in order to jump. And in that process, I discovered something - this odd inconsistent jump height became clearly consistent! Whenever I jumped in mid-air, the jump height was lower depending on how fast it was falling downward.

    To make it obvious, I set this up:

    upload_2017-9-25_20-44-12.png

    Whenever I jump while sitting on the ground, the top of the cube reaches that yellow line. But if I jump while falling towards the ground, I get a lower-than-should-be jump height, like not even halfway to that line, with seemingly lower height depending on how fast it's falling. If I jump while moving upward, I get the height I should get, every time! But why would this happen if I'm directly changing the velocity component, which should set Y velocity to 25, no matter what it already is?...

    You are 100% right, I debugged the velocity and it did show different values when looked at over frames over time. A "good" jump gave values like 25 for the first frame, 12, for the second, then 11.5, 11.0, etc. A "bad" jump that wasn't even halfway as high was like 25, 6.2, 6.2, 5.7, 5.2 The higher I put my player via continuous jumping, let it fall and then jump, the lower the velocity value dropped. First value was always 25, though.

    I also tried putting the jump command in FixedUpdate and triggering it via variable, like below, but I was getting lots of missed button presses... and even then, same problem :/
    Code (CSharp):
    1.          public Rigidbody2D theRigidbody;
    2.     public float speed;
    3.     public float jumpPower;
    4.     public bool inputJump;
    5.  
    6.     void Start () {
    7.         theRigidbody = GetComponent<Rigidbody2D>();
    8.     }
    9.  
    10. void Update ()
    11.     {
    12.  
    13.         if(Input.GetKeyDown(KeyCode.W))
    14.         {
    15.  
    16.             inputJump = true;
    17.  
    18.             //Vector3 jumpForce = new Vector2(theRigidbody.velocity.x, jumpPower);
    19.             //theRigidbody.velocity = new Vector2(theRigidbody.velocity.x, jumpPower);
    20.             //theRigidbody.AddForce(jumpForce, ForceMode2D.Impulse);
    21.  
    22.         }
    23.         else
    24.         {
    25.             inputJump = false;
    26.         }
    27.  
    28.     } // end Update
    29.  
    30.  
    31.     void FixedUpdate()
    32.     {
    33.  
    34.         if(inputJump)
    35.         {
    36.             theRigidbody.velocity = new Vector2(theRigidbody.velocity.x, jumpPower);
    37.         }
    38.     }
    @fire7side, just to be exhaustive, I tried removing the code for left and right movement entirely, same results, unfortunately
    @JoeStrout, thank you for the link! Since I'm still beginner-intermediate-ish in Unity, I'd rather learn things the easiest/simplest way possible first to help cement my understanding of the core functionality. At least for now. And it frustrates me highly when I can't get seemingly basic stuff to work o_O
     
    Last edited: Sep 26, 2017
  7. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    I'm guessing the "lower than expected" jump value happens if you try to jump before you actually hit the ground. I'm not entirely sure how the trigger boxes are set up, but this sounds like you're hitting the trigger box before hitting the ground? So if you tried to jump in between these two events, you'll get that lower than expected jump.

    I don't play around with rigidbodies much (I prefer to use my own solution) but I'm guessing that something gets cleared in the rigidbody when it comes into contact with the ground. Possibly zeroing out the accumulated force, acceleration, or something... so if you haven't hit the ground yet, you could still have the accumulated force being applied to the jump, giving you that lower than expected height.

    I'd dig deeper into the rigidbody properties to try to identify what should be cleared or zeroed out when you hit the jump button.
     
    JoeStrout likes this.
  8. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I'm with BlackPete. I don't eschew the physics system because I like to do things the hard way... I eschew it because it usually is the hard way. Oh sure, it's quick to get started, but sooner or later, I always find myself wrestling with things very much like this, where the physics engine has a mind of its own and won't simply do what I want it to do.

    On the other hand, if you stick with it, you probably will be able to beat it into submission sooner or later (at least, until the next weird behavior). Good luck!
     
  9. Nicris

    Nicris

    Joined:
    May 12, 2014
    Posts:
    21
    I FOUND THE PROBLEM!!

    @BlackPete, when you mentioned the trigger box, I started poking around. The trigger box detection actually didn't make an impact, because for the sake of testing I had turned off the code that asked if the trigger box had touched the ground at all or not. BUT... I decided to just re-produce the Unity docs' code for jumping, verbatim, with just a single sprite and the ground, nothing else. It worked perfectly. Started eliminating differences between that setup and mine... the difference was that stupid ground checker. What was wrong with it exactly? The rigidbody's unassuming mass of 1! I needed a rigidbody on it for detecting trigger collisions. It was connected to my player sprite via a fixed joint. Set the mass of the ground checker's rigidbody to 0.000001 and all was well!

    What I've learned: if you directly change the velocity of object A connected via joint to object B, object B's inertia will be affected, but the remaining inertia will still impact object A.

    Thank you guys for your help!

    EDIT: I know what you mean @JoeStrout, I was really thinking this one was an oddity of how Unity handles something and was getting ready to rage for being unable to pull of the simplest of simple... turned out Unity was following the rules for physics better than I was! :D
     
    Last edited: Sep 26, 2017
    BlackPete and JoeStrout like this.