- Home /
Force to Velocity scaling?
I am using rigidbody.AddForce() to move my player in FixedUpdate(), and I have noticed that "force added" -> "object velocity" doesn't scale linearly. So when I add a force of, let's say 10, to the Z-axis, it will reach a velocity of 4 units/second after some time, but when I add half the force it doesn't move at half the velocity, instead it moves at a speed much much slower.
I would like to be able to find the correct force to apply in order to accurately scale my speed up or down. I know an alternative is to use rididbody.velocity to execute movement or to clamp speed to a limit, but I would much rather be able to find the correct force to apply. So does anyone happen to know the correct formula necessary to achieve this, or maybe know of a way to make the force to velocity scale in a way I can accurately control it?
Thanks!
Edit: I am using Drag of 1 which is causing the scaling to not be linear, and I would prefer not to disable the drag because it makes sure my object doesn't keep accelerating. Are there any formulas that include drag? I think that might be what I need.
Unity uses standard physics, so you should be able to use the standard physics calculations you will find many places on the net. If you want to control velocity precisely, simply assign directly to Rigidbody.velocity.
I'm unable to find the formula/answer anywhere on the internet, and I wrote that I knew about rigidbody.velocity but would prefer not to use it.
That formula doesn't work in this case, if it did then "force added" -> "object velocity" would scale linearly, and I wrote that that it didn't.
Is it possible that you have a drag value setup on your rigidbody? The drag force will increase the faster you move. That means if you use only half the force to drive your rigidbody you don't have enough power to fight against the drag.
Theoretically if there's no drag at all you will accelerate linearly and your velocity will grow infinitely.
Answer by Bunny83 · Oct 28, 2014 at 07:58 PM
You might want to read my answer over here
edit
In addition to my answer about how AddForce actually works, here's how the drag is applied (at least in version 4.5.4f1):
velocity *= Mathf.Clamp01(1f - drag * Time.fixedDeltaTime);
You might want to read my post on the forum where i explain it a bit more in detail.
second edit
If you want to use Unity's drag system, here are 6 helper methods to calculate:
the final velocity you might reach for a given acceleration / velocityChange and drag value.
the drag value required for a given acceleration / velocityChange to reach the desired velocity.
the acceleration / velocityChange required to reach the desired velocity with a given drag value
You could extend each pair of methods to work with an actual force / impulse value. Keep in mind those methods only work for an acceperation / velocity change applied each FixedUpdate. One-time changes are pointless since you will have the final velocity at the moment you apply the force / acceleration / change. The drag will simply pull it back to 0.
//C#
float GetFinalVelocity(float aVelocityChange, float aDrag)
{
return aVelocityChange * (1 / Mathf.Clamp01(aDrag * Time.fixedDeltaTime) - 1);
}
float GetFinalVelocityFromAcceleration(float aAcceleration, float aDrag)
{
return GetFinalVelocity(aAcceleration * Time.fixedDeltaTime, aDrag);
}
float GetDrag(float aVelocityChange, float aFinalVelocity)
{
return aVelocityChange / ((aFinalVelocity + aVelocityChange) * Time.fixedDeltaTime);
}
float GetDragFromAcceleration(float aAcceleration, float aFinalVelocity)
{
return GetDrag(aAcceleration * Time.fixedDeltaTime, aFinalVelocity);
}
float GetRequiredVelocityChange(float aFinalSpeed, float aDrag)
{
float m = Mathf.Clamp01(aDrag * Time.fixedDeltaTime);
return aFinalSpeed * m / (1 - m);
}
float GetRequiredAcceleraton(float aFinalSpeed, float aDrag)
{
return GetRequiredVelocityChange(aFinalSpeed, aDrag) / Time.fixedDeltaTime;
}
Final note: In case a constant force is applied with a drag value > 0, the velocity will slowly get closer to the final velocity but won't actually reach it. However due to floating point precision the remaining difference will usually be "rounded away" within seconds.
Also keep in mind that in case your drag value is greater than the fixed framerate, functions like GetRequiredAcceleraton will return infinity as there is no acceleration to reach the given speed.
Thanks, I know how the forcemodes work though and they are not part of the solution. Your comment on my post got me realizing that I might need a formula which includes drag and how it affects the velocity.
@platf2: I made a few tests and it seems the drag is calculated in a very strage way. I've updated my answer.
Sorry, I didn't check this post after my last replies because I thought nothing more would come. I just saw your edits though and your methods look very interesting. I've tried using them but I can't get them to work for me. Could you possibly tell me which one of them I'd have to use with what parameters in order to find the force I need to apply in rigidbody.AddForce() in order to reach a certain final velocity?
@platf2: In this case you need GetRequiredAcceleraton. You have to pass your target velocity and the drag value of your rigidbody. $$anonymous$$eep in $$anonymous$$d that this will calulate the required acceleration. So when using AddForce you would have to use Force$$anonymous$$ode.Acceleration. If you want to use Force$$anonymous$$ode.Force (which is the default when you omit the parameter) you have to multiply the returned value with the mass of your rigidbody. Two examples:
float targetVelocity = 20.0f;
Vector3 dir; // the direction you want to move.
Vector3 requiredAcc = dir.normalized * GetRequiredAcceleraton(targetVelocity, rigidbody.drag);
// inside FixedUpdate
// either use
rigidbody.AddForce(requiredAcc, Force$$anonymous$$ode.Acceleration);
// or
rigidbody.AddForce(requiredAcc * rigidbody.mass);
Answer by Kiwasi · Oct 28, 2014 at 07:20 PM
There's this guy called Newton? Maybe you've heard of him.
Anyway the correct formula is force = mass * acceleration.
There are lots of other formulas to try. Google Newtonian physics. Or classical physics.
$$anonymous$$omentum and energy are two other terms that might be worth googling.
Basically everything you would find in a high school physics text book applies in Unity.
I know of that formula, but I don't think I can apply it to this scenario. It doesn't include Drag, which is what causes the Force and Velocity not to scale linearly, so I think I need a formula which includes it.
Also, how would I go around finding the acceleration of my object?
Acceleration = change in velocity / time
So to accelerate a 1 kg object to 1 m/s in 1 s you need a force of 1 N. Double the force and you get double the acceleration. Hence double the speed in the same time.
Drag can be considered a force in the opposite direction to velocity with a magnitude proportional to velocity squared. Hence your observed non linearity.
Using drag to control the maximum speed of your objects is not a good idea. (Unless you are dealing with free fall through the atmosphere or movement inside a viscous liquid). By using high drag you are basically saying all of your objects are moving at ter$$anonymous$$al velocity. This is not overly realistic.
However if you want the formula:
Ter$$anonymous$$al velocity is proportional to the square root of ( 2 * mass * Force / drag )
The proportionality constant depends on how PhysX has implemented drag. I'm pretty sure it will be one.
Edit: I hate typing formulas on I$$anonymous$$ The wiki pages for the various concepts I've described have proper looking formulas.
Thanks Bored$$anonymous$$ormon, I learned a lot from that post. What I really would like to do though is leave the Drag at 1, not change it, but find a formula which takes drag in account when finding the force necessary to reach a certain velocity.