Search Unity

Force and Velocity problem

Discussion in 'Scripting' started by Khena_B, Aug 5, 2016.

  1. Khena_B

    Khena_B

    Joined:
    Aug 21, 2014
    Posts:
    273
    Hey,

    Just started learning C# to port my 2D UE4 game to Unity, so far i'm learning quickly but while coding a jumping mechanic i'm encountering a weird issue that some of you might be able to explain.

    Here's the code

    Code (CSharp):
    1.  
    2.          //If on the ground and pressing jump, throw player in the air
    3.          if (grounded && Input.GetButtonDown ("Jump"))
    4.          {
    5.              isJumping = true;
    6.              body.AddForce (new Vector2 (0, jumpForce));
    7.          }
    8.          //If jumping, going up and releasing jump button, stop his upward velocity
    9.          if (Input.GetButtonUp ("Jump") && isJumping && body.velocity.y >= 0)
    10.          {
    11.              isJumping = false;
    12.              body.velocity = (new Vector2 (0, 0));
    13.          }
    Everything works perfectly, however when i tap and release the jump button extremely quickly, the player jumps at full height ignoring the second if statement's velocity change.

    I have used Debug.Log after every if statements and both get executed in the proper order.

    So why isn't it setting the velocity to 0 when the button is being pressed and released very very quickly?

    It's as if the AddForce takes more time to kick in, therefore when pressed extremely quickly the velocity gets changed before, it makes no sense to me.

    Here's another example of what i don't understand

    By adding these lines to the Start function:

    Code (CSharp):
    1. void Start ()
    2.      {
    3.          body.AddForce (new Vector2 (0, 500));
    4.          body.velocity = (new Vector2 (0,0));
    5.      }
    I don't understand why the character is being thrown in the air, since i'm setting it's velocity to be zero right after i have added some force

    Some help would be very appreciated!
     
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    by any chance is that code in FixedUpdate?

    generally if you want fast responsive input but want to use physics you need to check for input in Update (runs every frame) and pass/reference/cache/whatEverYouWantToCallIt the data so you can use it in the FixedUpdate (runs at a default 50fps, so not every frame) function to perform the physics movement. If you use Input in fixedupdate you can get into the situation where the input is missed (i.e. the down frame was detected but the up frame was missed)
     
  3. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    is the collider clipping through anything?
     
  4. Khena_B

    Khena_B

    Joined:
    Aug 21, 2014
    Posts:
    273
    I should have mentioned it but the code is in Update, not FixedUpdate
     
  5. Khena_B

    Khena_B

    Joined:
    Aug 21, 2014
    Posts:
    273
    I don't understand because the AddForce is being completely stopped by setting the velocity to 0 even if the press and release is happening very fast, but when done even faster (nearly at the same time with a flick of the finger on the button) , the set velocity doesn't have any effect, it's as if it's setting the velocity so fast that it happens before the AddForce had time to push the player up, so it ignores the set velocity and proceeds to push the player up

    Is there a simple way around that?
     
  6. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    it's the same thing just the other way around. You are passing several updates to the rigidbody between the fixedupdate calls. The FixedUpdate is called immediately before each physics "tick", nothing happens with forces outside of those ticks.

    https://docs.unity3d.com/ScriptReference/Rigidbody.html
     
  7. Khena_B

    Khena_B

    Joined:
    Aug 21, 2014
    Posts:
    273
    I'm not sure i understand as i do not use the FixedUpdate for my jump since i'm only adding force for a single frame at the push of a button and not over a period of time, as i said it happens in Update

    Can someone explain the second example that i posted with the Start function, that would help me understand my issue

    Code (CSharp):
    1.     void Start ()
    2.          {
    3.              body.AddForce (new Vector2 (0, 500));
    4.              body.velocity = (new Vector2 (0,0));
    5.          }
    6.  
    I want to know why setting the velocity isn't stopping the AddForce, i'm sure it would if there was a slight delay between them
     
    Last edited: Aug 6, 2016
  8. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    I don't know the answer for sure, but I assume that when you add a force in Update or Start, it's essentially queueing the force so that it will be applied when the physics step (FixedUpdate) happens. But setting the velocity happens instantly. So you're basically saying "When physics happens, add a force. Also, right now the velocity is zero."... the force is still queued up, so it's going to happen when the physics step kicks in. Similarly, in your other code, when you set the force, it's getting queued and if you release the button before the physics step happens, it sets the velocity to zero (which it probably already is) before the force has been applied, but then when physics kicks in, the force is still there and gets added. This is all especially true if your rigid body has "interpolate" turned off. The physics timestep happens every .02 seconds, so if you press the button fast enough, it could be down and then back up before the force ever gets applied.

    TLDR: Use either forces OR velocity, don't try to use them both at the same time. You should probably change your jump to something like this:
    Code (csharp):
    1.  
    2.          if (grounded && Input.GetButtonDown ("Jump"))      
    3.          {
    4.              isJumping = true;
    5.              body.velocity = (new Vector2 (0, jumpForce));
    6.          }
    7.  
    8.          //If jumping, going up and releasing jump button, stop his upward velocity
    9.          if (Input.GetButtonUp ("Jump") && isJumping && body.velocity.y >= 0)
    10.          {
    11.              isJumping = false;
    12.              body.velocity = (new Vector2 (0, 0));
    13.          }
    You'll need to have gravity turned on or do some kind of fake gravity, but I assume you have something like that already.
     
    ericbegue and Khena_B like this.
  9. Khena_B

    Khena_B

    Joined:
    Aug 21, 2014
    Posts:
    273
    makeshiftwings, thank you so much, that definitely seems to be what is happening, it makes perfect sense, i was about to lose my mind here.

    I'll give what you suggest a try, i have no doubt it will work

    Thanks again
     
  10. Khena_B

    Khena_B

    Joined:
    Aug 21, 2014
    Posts:
    273
    And it works perfectly!
     
    makeshiftwings likes this.