Is it okay to use ForceMode.VelocityChange in Update()?

I’m making a 3D platformer in which the player is a rigidbody controlled primarily through AddForce (velocity, ForceMode.VelocityChange) methods. Since it’s important for the character to respond immediately to inputs, especially for things like jumping, where the initial force is applied on the button press but can be cancelled by releasing the button before the jump reaches its apex, I was considering applying the forces in Update(). I’ve read that one should do physics updates in FixedUpdate (), but I’ve also seen people say that only really matters for continuous forces. Since ForceMode.Velocity is an instantaneous force, I want to know: is using it in Update() kosher?

No, that may cause inconsistencies. Update and FixedUpdate may be considered two different execution loops:

  • Several Update calls may happen between two FixedUpdate calls (Example: 100 Hz screen and/or vsync disabled, while FixedUpdate runs at fixed 50 Hz).
  • Several FixedUpdate calls may happen between two Update calls (Example: temporary frame rate drops below 50 fps because of cpu load).

Calling AddForce from Update won’t have any effect until the physics update is reached, that is after the next FixedUpdate occurs. Calling AddForce multiple times consecutively accumulates the effect that will reach the physics update. So calling AddForce from Update may have these effects:

  • If AddForce is called in two Update calls before a FixedUpdate happens, this will *double* the velocity change applied to your rigidbody. Or even multiplied further, if that happens during multiple consecutive Update cycles. Note that this is a somewhat common glitch in commercial games. If you're used to watch speedruns, this kind of glitch is exploited where possible to gain extra velocity.
  • If several consecutive FixedUpdate calls occur due to frame drops (= Update call drops), you may then miss some user inputs in these situations.

That said, the best solution to handle all user inputs as fast as possible while keeping consistency is:

  1. Detect the user input in both Update and FixedUpdate. Raise some flag if user input is detected.
  2. Check for the flag at the end of FixedUpdate. If it's raised, call AddForce once and clear the flag.