Search Unity

Calculating Velocity from AddForce and mass

Discussion in 'Scripting' started by Elryk, Jan 17, 2013.

  1. Elryk

    Elryk

    Joined:
    Jan 2, 2013
    Posts:
    82
    Does anyone know how to calculate the velocity of an object of a given, constant mass after using AddForce? There is no resistance on the rigidbody, and the use gravity box is unchecked (doesn't use gravity from the physics engine).

    Ive tried looking for actual physics formulas, but they seem to all need acceleration or the length of time that the force is applied. The way I understand it, AddForce is an instant, one-time force, and doesn't have a length of time associated with it. If AddForce is actually applied over a length of time, that information will be just as helpful as a formula.

    Thanks
     
    SAMERkab likes this.
  2. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,697
    All I can suggest is use delta position.
     
  3. Elryk

    Elryk

    Joined:
    Jan 2, 2013
    Posts:
    82
    The problem is, I need to calculate what the objects velocity will be, before it starts moving. This rules out calculating its velocity with distance and time.
     
    SAMERkab likes this.
  4. Brian-Stone

    Brian-Stone

    Joined:
    Jun 9, 2012
    Posts:
    222
    The AddForce() function assumes that the force is applied over the fixed timestep duration set by the Unity engine. By default, the fixed timestep is set to 0.02 seconds, but you can change it to almost anything you want in the Time Manager settings which is accessed in the Edit->Project Settings->Time menu. You can also get or set the fixed timestep in code via Time.fixedDeltaTime.

    Deriving the change in velocity is a simple matter of solving F=ma for velocity...

    F = ma
    a = v/t = F/m
    v = at = (F/m)t

    Velocity (v) equals Force (F) divided by mass (m) multiplied by time (t).

    C#
    Code (csharp):
    1.  
    2.    float v = (F/rigidbody.mass)*Time.fixedDeltaTime;
    3.  
     
    Last edited: Jan 17, 2013
    emredesu, jiraphatK, linshnt and 15 others like this.
  5. Elryk

    Elryk

    Joined:
    Jan 2, 2013
    Posts:
    82
    That post goes above and beyond! The fixed timestep told me exactly what I needed, but you took it a couple steps further for me. Thanks!
     
    SAMERkab and NCBDUM005 like this.
  6. Brian-Stone

    Brian-Stone

    Joined:
    Jun 9, 2012
    Posts:
    222
    Code correction. I used Time.fixedTime in the code example, which is incorrect since this is the elapsed time since the program started. You want to use Time.fixedDeltaTime.
     
  7. Elryk

    Elryk

    Joined:
    Jan 2, 2013
    Posts:
    82
    Ok, I re-arranged a few things about how I was applying the formulas and got it coded, but I'm running into another problem that doesn't make sense.
    Some background:
    To setup my project, i have made a to-scale (almost) model of the earth, the sun, and the moon. This was done so that I would have numbers to reference to for my math, to make sure everything is working right
    When I Debug.Log the NeedVel, it shows the correct velocity (29846m/s). The NeedForce value is really high but given the scale and numbers involved, that didnt really seem out of place. Now I'm starting to wonder becuase the earth and moon go shooting off in the direction the starting force is applied and reach scientific notation values in the transform.position almost instantly. I have included the 2 scripts involved. Is this a code problem, math problem, or typo problem?

    Pull.js:
    Code (csharp):
    1.  
    2. #pragma strict
    3. //**************************************************
    4. //This script goes on the object with the most mass.
    5. //**************************************************
    6. //Set Gravational Constant. use this for time scaling.
    7. static var Gcons : float = 0.000000000067;
    8. function Start () {
    9.  
    10. }  
    11.  
    12. function Update () {
    13.     var obj1 : GameObject;
    14.     var obj2 : GameObject;
    15.     var SolarBody : GameObject[] = GameObject.FindGameObjectsWithTag ("Solar");
    16.     var dist : float;
    17.     var gforce : Vector3;
    18.     var i : int;
    19.     var j : int;
    20.     for (j=0;j<SolarBody.length;j++){
    21.         for (i=j+1;i<SolarBody.length;i++) {
    22.             //Assign objects to be gravitized.
    23.             obj1=SolarBody[j];
    24.             obj2=SolarBody[i];
    25.             //Get distance between objects
    26.             dist = Vector3.Distance(obj1.transform.position,obj2.transform.position);
    27.             //Calculate force of gravity
    28.             gforce = Vector3.Normalize(obj2.transform.position - obj1.transform.position)*Gcons*obj1.rigidbody.mass*1000000000000000*obj2.rigidbody.mass*1000000000000000/(dist*dist)*Time.deltaTime;
    29.             //Apply Gravity
    30.             obj1.rigidbody.AddForce(gforce);
    31.             obj2.rigidbody.AddForce(-gforce);
    32.         }
    33.     }
    34. }
    35.  
    OrbitStart.js: I'm thinking the problem is line 64
    Code (csharp):
    1.  
    2. #pragma strict
    3.  
    4. //**********************************************
    5. //This script goes on all 'Solar' tagged objects
    6. //except for the object with the highest mass.
    7. //**********************************************
    8.  
    9. function Start () {
    10.     var OrbitTarget : GameObject;
    11.     var obj1 : GameObject;
    12.     var obj2 : GameObject;
    13.     var CentralObject : GameObject;
    14.     var SolarBody : GameObject[] = GameObject.FindGameObjectsWithTag ("Solar");
    15.     var dist : float;
    16.     var gforce : Vector3;
    17.     var gforce1 : Vector3;
    18.     var gforce2 : Vector3;
    19.     var i : int;
    20.     var NeedVel : float;
    21.     var NeedForce : float;
    22.     //Find the object with the highest gforce with this object
    23.     for (i=0;i<SolarBody.length;i++) {
    24.         if (OrbitTarget!=null){
    25.             if(SolarBody[i]!=gameObject){
    26.                 if (OrbitTarget!=SolarBody[i]){
    27.                     obj1=gameObject;
    28.                     obj2=SolarBody[i];
    29.                     dist = Vector3.Distance(obj1.transform.position,obj2.transform.position);
    30.                     gforce1 = Vector3.Normalize(obj2.transform.position - obj1.transform.position)*Pull.Gcons*obj1.rigidbody.mass*1000000000000000*obj2.rigidbody.mass*1000000000000000/(dist*dist)/2*Time.deltaTime;
    31.                     dist = Vector3.Distance(obj1.transform.position,OrbitTarget.transform.position);
    32.                     gforce2 = Vector3.Normalize(OrbitTarget.transform.position - obj1.transform.position)*Pull.Gcons*obj1.rigidbody.mass*1000000000000000*OrbitTarget.rigidbody.mass*1000000000000000/(dist*dist)/2*Time.deltaTime;                    
    33.                     if (gforce1.magnitude>gforce2.magnitude){
    34.                         OrbitTarget=SolarBody[i];
    35.                     }
    36.                 }
    37.             }
    38.         }else{
    39.             OrbitTarget=SolarBody[i];
    40.             if(SolarBody[i]!=gameObject){
    41.                 if (OrbitTarget!=SolarBody[i]){
    42.                     obj1=gameObject;
    43.                     obj2=SolarBody[i];
    44.                     dist = Vector3.Distance(obj1.transform.position,obj2.transform.position);
    45.                     gforce1 = Vector3.Normalize(obj2.transform.position - obj1.transform.position)*Pull.Gcons*obj1.rigidbody.mass*1000000000000000*obj2.rigidbody.mass*1000000000000000/(dist*dist)/2*Time.deltaTime;
    46.                     dist = Vector3.Distance(obj1.transform.position,OrbitTarget.transform.position);
    47.                     gforce2 = Vector3.Normalize(OrbitTarget.transform.position - obj1.transform.position)*Pull.Gcons*obj1.rigidbody.mass*1000000000000000*OrbitTarget.rigidbody.mass*1000000000000000/(dist*dist)/2*Time.deltaTime;                    
    48.                     if (gforce1.magnitude>gforce2.magnitude){
    49.                         OrbitTarget=SolarBody[i];
    50.                     }
    51.                 }
    52.             }
    53.         }
    54.     }
    55.     //Assign objects to be started.
    56.     obj1=gameObject;
    57.     obj2=OrbitTarget;
    58.     //Get distance between objects
    59.     dist = Vector3.Distance(obj1.transform.position,obj2.transform.position);
    60.     //Determine the velocity needed for orbit.
    61.     Debug.Log(obj1.name);
    62.     NeedVel = Mathf.Sqrt(obj2.rigidbody.mass*1000000000000000*Pull.Gcons/dist);
    63.     Debug.Log(NeedVel);
    64.     //Determine Force needed to reach that velocity
    65.     NeedForce = obj1.rigidbody.mass*1000000000000000*(NeedVel/Time.fixedDeltaTime);
    66.     Debug.Log(NeedForce);
    67.     //Get the direction of gravity's force
    68.     gforce=Vector3.Normalize(obj2.transform.position - obj1.transform.position);
    69.     //Apply the Needed force perpendicular to gravity's force
    70.     rigidbody.AddForce(Vector3(gforce.z,gforce.y,gforce.x)*NeedForce);
    71. }
    72.  
    73. function Update () {
    74.  
    75. }
    76.  
    EDIT: While it shouldn't effect the calculations (as demonstrated by the accurate NeedVel value), the "*1000000000000000" might need some clarification as to why its there. That is the ratio of the scale of distance and mass. If you use the same scale for both, no matter the scale, something ends up out of the bounds of the numbers Unity can handle.
     
    Last edited: Jan 18, 2013
  8. Elryk

    Elryk

    Joined:
    Jan 2, 2013
    Posts:
    82
    Slight bump and an update.

    Man, the action of this code keeps getting stranger and stranger. Changing Gcons does the opposite of what you would expect for some reason. Increasing it SHOULD increase the amount of force from:
    Code (csharp):
    1.  
    2.             gforce = Vector3.Normalize(obj2.transform.position - obj1.transform.position)*Gcons*obj1.rigidbody.mass*1000000000000000*obj2.rigidbody.mass*1000000000000000/(dist*dist)*Time.deltaTime;
    3. [/CODE}
    4. Obvious right? Its on the top of the fraction, thus, an increase in it should increase the overall value, but in fact, it does the opposite. What is going on with these scripts? Something is SERIOUSLY wrong. My eyes and the unity error checking/reporting system both come up empty, No errors, and the formulas seem correct.
    5.  
    6. I am using the following formulas, on the respective lines:
    7.  
    8. Pull:27 - F=(G*M1*M2)/d^2  <Force of gravity between 2 objects>
    9. F=Force of gravity
    10. G=Gravitational Constant
    11. M1 and M2= Mass of the 2 objects
    12. d=Distance between objects
    13.  
    14. OrbitStart:61 - V=sqrt(MG/d) <Orbital Velocity of an object when the masses are significantly different>
    15. V = Velocity
    16. M = Mass of the heavier object
    17. G = Gravitational Constant
    18. d = Distance between objects
    19.  
    20. OrbitStart:64 - F=MA=M(V/t) <Basic Force equation>
    21. F = Force
    22. M = Mass
    23. A = Accelleration
    24. V = Velocity
    25. t = time
    26.  
    27. Anyone have any ideas?
     
  9. rawmantick

    rawmantick

    Joined:
    Apr 8, 2013
    Posts:
    1
    Hey folks. My first post.

    I've recently ran into the very same problem.
    I had to "imitate" Unity physics in manual (isKinematic = true) mode.

    AddForce(..., ForceMode.Force) is advertised as an "immediate" action.
    However we do know, that in order to really change velocity of a rigid body a certain force needs to work for some time. It's not even physics, but simple math where acceleration (and thus force) is a derivative function of velocity taken by time:

    F(t) = m * a(t) = m * V'(t)

    Force as a velocity changer does not make any sense without time. It needs time. Force applied instantly (kind of "for zero point zero seconds") will not have any effect over velocity at all. End of story.

    So knowing this, and (partially) agreeing with Brian Stone we do guess, that there needs to be some time to be taken into account. What would one use to perform an immediate physical action? Well, the assumption is logical and simple, it's Time.fixedDeltaTime. However I've ran some "scientific poke with calculator" tests by removing all the side effects like drag (for God's sake, Unity developers, why didn't you call it air friction or something?) and gravity, and it appears, that velocity is calculated as if the fixed time delta was either not taken into account at all or simply was equal to 1 SECOND (this is where I allow myself to not agree with Brian Stone). On purpose have I played with different fixed time deltas and result stays the same.

    So, to imitate the AddForce(..., ForceMode.Force) behaviour yourself, one should do this:

    Code (csharp):
    1. Vector3 force = new Vector3(1.0f, 0.0f, 0.0f);
    2.  
    3. gameObject.rigidbody.isKinematic = true;
    4. gameObject.rigidbody.velocity = 1.0f * force / gameObject.rigidbody.mass; // Where 1.0f is 1 second
     
    Last edited: Aug 21, 2013
  10. Partel-Lang

    Partel-Lang

    Joined:
    Jan 2, 2013
    Posts:
    2,556
    The reason why you have reached 1.0 conclusion in your tests is that time is not being used in AddForce at all. It is not real world physics where you indeed need time for any force to take effect, remember that it is only a simplified simulation. You can change the velocity immediatelly, because you are only changing the value of a single vector in the simulation, not actually taking time to push an object.
     
  11. Rodolinc

    Rodolinc

    Joined:
    Sep 23, 2013
    Posts:
    63
    thank's a lot for the example! I was trying to use corroutines, weird algorithms using time... the formula above is the deal, I just didnt realize how to translate the formula into Unity.
     
  12. Martin Dachev

    Martin Dachev

    Joined:
    Mar 22, 2015
    Posts:
    2
    Hello,
    you have some problems because of some misconceptions about Force, Acceleration and Velocity.

    Let's start with Force. What is a force? It's a push or pull. Simple as that :). If ONLY one force is applied ONCE (only one time, for a really small moment) to an object with
    NO FORCES acting on it, this object gets pushed or pulled. The force, when applied, gives it velocity. Now, it has velocity, and no forces are acting on it - because
    we applied ONLY ONE FORCE ONLY ONCE (for a tiny moment). At the moment we applied the force, the object gained some velocity, it had acceleration in that moment - from 0 to v (where "v" is the current velocity).
    Now it does not have any acceleration.

    When there are no forces acting on an object, there is no acceleration or deacceleration - and the object won't change it's velocity.
    There is nothing stopping it from moving, and there is nothing accelerating it. It will move with it's velocity forever.
    It will ONLY stop when we apply a counteracting force on it (in the opposite direction of the moving object).

    But what will happen if we apply a force continuously to it? Well, it will have acceleration. Why?
    OK, we apply force for the first time to the object that is NOT MOVING (doesn't have velocity) and NO FORCES are acting on it. It is pushed by the force, so it get's some
    velocity. But now we apply the force again (we are applying it continuously). The object has some velocity, and when we apply the same force again, it gets pushed again, so it gains more velocity.
    When we continue to apply the same force it gains more and more velocity - it has acceleration.


    That's why the formula is
    F = m*a,
    where "F" is force, "m" is mass and "a" is acceleration.

    The WRONG formula is
    F = m*v,
    where "v" is velocity, because it can have velocity when no forces are currently applied to it.

    If we have NO ACCELERATION, we aren't applying any force, and it doesn't matter if it HAS or HAS NOT velocity.

    In your case, you want to calculate what force is needed to accelerate a stopped object to a given velocity. So,

    F = m*a
    a = dv/dt, where "dv" is deltaVelocity.
    dv = (v - v0), where "v0" is the velocity in the beginning (in our case v0 = 0, because the object is not moving), "v" is the end velocity (in our case the desired velocity).

    So,

    a = (v-v0) / dt, where "dt" is the time it took the velocity to change from v0 to v (in fact, dt = t - t0, t = end time, t0 = starting time. For example, if the change
    happened in the timeframe between 2 seconds and 3 seconds, dt will be t - t0 = 3 - 2 = 1 second).

    In our case, t0 = 0s, because it's from the start => so our formula now is
    a = (v - v0) / (t-t0)
    a = (v - 0) / (t - 0)
    a = v/t (this is ONLY BECAUSE v0 = 0 and t0 = 0)
    F = m*(v/t)

    Now, as Brian Stone said,
    The AddForce() function assumes that the force is applied over the fixed timestep duration set by the Unity engine.
    By default, the fixed timestep is set to 0.02 seconds, but you can change it to almost anything you want in the Time Manager settings
    which is accessed in the Edit->Project Settings->Time menu. You can also get or set the fixed timestep in code via Time.fixedDeltaTime.
    Well, then "t" from the formula is the fixed timestep duration set by the Unity engine in our case,
    t = Time.fixedDeltaTime.

    So, finally

    F = m * (v/t), where "m" is the mass of the object, "v" is the desired velocity and t = Time.fixedDeltaTime.

    I hope this helped you reader, I hope I explained it as simple as it can be.
     
  13. carllllllll

    carllllllll

    Joined:
    Feb 28, 2021
    Posts:
    1
    Yall seem like the people to ask about acceleration and deceleration. I am trying to make a top down 2d soccer game with a ball that will continue to roll after the player stops. I can't seem to figure out the phisics without having gravity. I don't need anything fancy, I just need slowed deceleration with collision. Thanks