Search Unity

Question rb.AddForce applies different amount when compiled.

Discussion in 'Physics' started by bigmonmulgrew, Apr 17, 2023.

  1. bigmonmulgrew

    bigmonmulgrew

    Joined:
    May 13, 2016
    Posts:
    5
    Had a weird issue when compiling, first to webGL and then to windows. AddForce seems to apply less force when compile.

    Took me a whole an dsome trial and error to figure out what it was.

    I am floating a baloon

    in void Update
    if (Input.GetKey(KeyCode.Space))
    {
    playerRb.AddForce(Vector3.up * 5);
    }

    super simple. Works fine in Unity in play mode. But when compiled it doesnt work, or I thought it didnt work at first. After some trial and error, and printing values to a text field I figured out that changing the 5 to a much larger number makes it work.

    So ultimately how do I make a it consistent when its compiled
     
  2. Turtlehellmax

    Turtlehellmax

    Joined:
    Nov 26, 2020
    Posts:
    5
    Update() is called every frame, meaning that if you have a different framerate in the editor than your build, you'll get different amounts of force. This is easily combatted using Time.deltaTime in framerate-dependent code. Time.deltaTime is basically just 1 / by your frame time, making any value multiplied by it equivalent to itself after 1 second. This means your solution would be:

    Code (CSharp):
    1. void Update
    2. {
    3.     if (Input.GetKey(KeyCode.Space))
    4.     {
    5.         playerRb.AddForce(Vector3.up * 5 * Time.deltaTime);
    6.     }
    7. }
    Keep in mind that, despite popular belief, this will NOT work in other update calls, such as FixedUpdate, as those have different frame times. For FixedUpdate(), you instead use Time.fixedDeltaTime. You can read more about the Time in the docs here: https://docs.unity3d.com/ScriptReference/Time.html.

    Edit: After rereading your question, I realized this may not be the answer, let me know tho lol.
     
    bigmonmulgrew likes this.
  3. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,087
    Your editor might be running at an unconstrained framerate, ie as fast as it can run (frames per second) it is running. In a simple scene, this might mean that it's running at 400 to even as much as a 1000 frames per second, so the physics is calculated a LOT, since this force is added per frame in the "Update()" function, each time there's a new frame "drawn".

    To ensure you see, in Editor, what you'll see in the Build, add the force during FixedUpdate, which is distributed at the division of fixedUpdates (Project Settings > Time). Change this value to 1 / desired frame rate. It defaults to 0.02 seconds, which is ridiculous.
     
    Awufumana and bigmonmulgrew like this.
  4. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,510
    Just move that code unmodified to FixedUpdate and it will work consistently in all platforms.

    The effect will be probably different, so just modify that 5 in the code until you get the same behavior that you had before. Then it will be the same behavior in builds and in any platform.
     
    Awufumana likes this.
  5. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,510
    Using Time.deltaTime in the calculation of a force is incorrect. A force is a time-independent magnitude. It gets integrated along time internally by the physics solver. While this solution might appear to fix the issue in this case, it may easily be the source of other issues and inconsistencies.
     
  6. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,087
    Can you explain this like I'm 5? Sorry to bother you, but this is bugging me.
     
  7. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,929
    Velocity is change in position over time. So if you've got the current position of an object and want to update it using a velocity, you do:

    newPosition = oldPosition + velocity * time;

    Similarly, if you've got the current velocity of an object and want to update it using an acceleration, you do:

    newVelocity = oldVelocity + acceleration * time;

    A force is just a mass-weighted acceleration:

    Force = mass * acceleration.

    So, when you apply a force to an object, this is what Unity does internally to update the position of the object:

    newVelocity = oldVelocity + force / mass * time;
    newPosition = oldPosition + newVelocity * time;

    As you can see time is already accounted for when you use AddForce(), no need to multiply your forces by the time passed since the last frame. In other words, the unit used to express forces is time-independant.
     
    bigmonmulgrew, Unifikation and Edy like this.
  8. Unifikation

    Unifikation

    Joined:
    Jan 4, 2023
    Posts:
    1,087
    This is the magic phrase that revealed what's going on, to me. THANK YOU!!!
     
  9. bigmonmulgrew

    bigmonmulgrew

    Joined:
    May 13, 2016
    Posts:
    5
    So reporting back

    I found this when googling initially and it really threw me off. This is what made me think I didnt need to use Time.DeltaTime. I do understand that velocity is a factor of time.

    However, applying an amount of force 700+ times per second adds up to a much larger number than that amount of force applied 60 times per second.

    So as for the solutions, I tried both the suggested solutions here, multiplying th eforce addded by Time.DeltaTime worked. I had to increase the speed value from 5 to around 1000 but it worked and was consistent accross platforms and compiled vs editor

    Moving the code to FixedUpdate() also fixed the issue, other than the fact that my new speed value is around 100 it produces the same result.

    Thank you for the help guys and appreciate the explanations