I am following one of the Unity Junior Programmer lessons, in which we are creating a prototype with a spherical player game object that can be controlled by adding Rigidbody forces. I noticed that my player moved much faster than the one showed in the lesson, even though I had used the same values, which led me to believe that it was my higher-framerate monitor that was causing the difference. However, I thought that when using the Rigidbody .AddForce() function, you didn’t need to multiply the value by Time.deltaTime. Was I mistaken? Or is there a different way I should go about making physic forces framerate-independant?
Here’s a snippet of my code:
void Update()
{
float forwardInput = Input.GetAxis("Vertical");
//move the player foward and backward in the direction of the focal point
playerRb.AddForce(focalPoint.transform.forward * forwardInput * speed);
}
For this, it is recommended to use FixedUpdate instead of Update. Even though delta time might help, you’ll end up using the wrong units.
I’d recommend reading this → documentation “ForceMode.Force: Interprets the input as force (measured in Newtons), and changes the velocity by the value of force * DT / mass. The effect depends on the simulation step length and the mass of the body.”
This means that the body will apply a velocity change (delta velocity) of: dv = F (dt / m) … (F = m * a)
F is the argument you pass in, which is a force of course (Forcemode = force).
For instance, if you want to add 3 Newtons forward, then the code could be as simple as this:
rb.AddForce(transform.forward * 3f);
Now, If you want to make the rb move at a certain target velocity (i’m ignoring drag/friction), then you need to find the force required for that using the formula from above.
For example, the following code moves the body forward at a speed = MoveSpeed. Notice how all different modes do the exact same thing.
public class AddForceExample : MonoBehaviour
{
public float MoveSpeed = 6f;
public ForceMode ForceMode;
Rigidbody rb;
void Awake() => rb = GetComponent<Rigidbody>();
void FixedUpdate()
{
// this will force the script to recalculate deltaVelocity every frame
// Otherwise, delta velocity will be zero once the speed is reached
rb.velocity = Vector3.zero;
Vector3 targetVelocity = MoveSpeed * transform.forward;
Vector3 dv = targetVelocity - rb.velocity // Velocity change required
float dt = Time.fixedDeltaTime;
// force = rb.mass * (dv / dt);
switch (ForceMode)
{
case ForceMode.Force: // f = m * (dv/dt)
rb.AddForce(rb.mass * (dv / dt), ForceMode.Force);
break;
case ForceMode.Acceleration: // a = dv/dt
rb.AddForce(dv / dt, ForceMode.Acceleration);
break;
case ForceMode.Impulse: // imp = m * dv
rb.AddForce(rb.mass * dv, ForceMode.Impulse);
break;
case ForceMode.VelocityChange: // dv
rb.AddForce(dv, ForceMode.VelocityChange);
break;
}
}
}