I'm confused about these two methods in the Unity framework. Both make the player object move, stop, change direction, etc. When should one be used over the other and when is one appropriate?
Although there's already an accepted answer, I think there are some additional details worth covering.
When you set velocity, you're overriding absolutely everything else that might affect that object's movement. In some situations this is desirable, such as setting the initial velocity of a bullet once at the moment it's fired, as in trojanfoe's example. Just be wary, because when used in the wrong situations it can cause issues:
If multiple sources/scripts try to modify the same Rigidbody's velocity by setting it directly (ie.
body.velocity = foo), then whichever one runs last wins, and the others have zero effect. This can lead to order of update bugs, in particular causing entities to hover or fall slowly (because downward acceleration due to gravity gets overridden before it can accumulate)
If you're setting velocity every frame, collisions with other objects can be a bit weird. It's as though your object is being propelled by an engine with infinite torque - no matter how much velocity it loses on an impact, it's back up to top speed on the very next physics step, and its velocity isn't deflected away from the impact. This can lead to launching objects you collide with, or small objects being able to push huge ones much more easily than it seems like they should, or objects sliding slowly along static barriers instead of deflecting away/along them.
Both of these effects can be desired sometimes. For example, when I'm making Kinect games and I want the player's virtual avatar's limbs to be able to interact with the physics scene, I usually move those bodies using direct velocity setting. Because the player's actual hand is in a known place and didn't slow down from collision with that virtual object, their virtual hand needs to do the same to stay in alignment, so in this case we actually want to override all other physics effects to get it there.
AddForce and Friends
AddForce and similar helper functions, by contrast, are made to cooperate with everything else going on in the physics world. If multiple sources/scripts AddForce to a Rigidbody, all of those effects get added together to create a net change in the object's movement (which, depending on how it's calculated, may also be order-independent). This helps avoid one script completely stomping some other physics effect.
AddForce comes in four flavours by specifying the optional ForceMode parameter, which are useful for different things:
ForceMode | Use
Force (default) | Accelerate an object over 1 time step, based on its mass.
| Units: Newtons = kg * m/s^2
Acceleration | Accelerate an object over 1 time step, ignoring its mass. (like gravity)
| Units: m/s^2
Impulse | Instantaneously propel an object, based on its mass
| Units: N * s = kg * m/s
VelocityChange | Instantaneously propel an object, ignoring its mass
| (like body.velocity = foo, except multiple scripts can stack)
| Units: m/s
If you're trying to model a continuous push over time (eg. something you're applying every FixedUpdate), like a car driving or a rocket burning or a gravity well pulling, you want Force or Acceleration. (Depending on whether you want heavy objects to accelerate slower)
If you're modelling a sudden, sharp change in motion, like firing a bullet, recoiling from an explosion, or bouncing off a barrier, then you more likely want Impulse or VelocityChange.
Using AddForce helps you achieve more physical realism, but it can also require that you spend more time thinking through the physics of your behaviour. For instance, if you want your body to have a finite acceleration up to a target speed, so that it reacts more realistically to collisions than setting the velocity every frame, you'll probably want a calculation similar to this helper function:
public static void AccelerateTo(this Rigidbody body, Vector3 targetVelocity, float maxAccel)
Vector3 deltaV = targetVelocity - body.velocity;
Vector3 accel = deltaV/Time.deltaTime;
if(accel.sqrMagnitude > maxAccel * maxAccel)
accel = accel.normalized * maxAccel;
The reason I call all of these "helper functions" is that technically you could achieve all the same ends with:
body.velocity += suitablyCalculatedDeltaV;
(I think. It's possible Unity's PhysX/Box2D-based physics solvers buffer changes through AddForce separately, but I haven't seen obvious consequences of this)
So at the end of the day, what these functions really get us is clarity of intent. When I want to apply a gradual force, I don't need to remember to multiply my deltaV by Time.deltaTime and divide by mass, I just say I want ForceMode.Force and it's handled in a correct & consistent way. And when I or someone else comes to iterate on my code later, it's immediately clear what I meant, without needing to decode the time and mass calculations to figure it out.
In addition to trojanfoe's answer, Angry Birds vs Car Racing. Two major and different examples of these methods (
velocity respectively). For example, in Angry Birds use of velocity is little more difficult as you would have to set Projectile trajectory by your self, like,
When I use AddForce in Angry Birds, I would use,
While when I use velocity then I would handle trajectory using
x = v*t*Cos(theta)
y = v*t*Sin(theta) - 0.5 * g * t *t
Or something like this.
While in Car Racing game you would have to control speed all the time, not like Angry Birds i.e. Shoot and all. So in that scenario handle
velocity is more useful than
Hope you understand. At least little bit.
Rigidbody Velocity and Rigidbody Addforce are two confusing functions in Unity 3D and often beginners fail to understand their difference. In This Article, we are going to discuss the difference between RigidBody.velocity and RigidBody.addforce.
In both cases, whether it is Addforce or velocity function we are going to use the term force to explain them.
When we are using Rigidbody.velocity , then, in that case, we are adding force to our object but this force will only move the object unless and until we keep applying force.
body.velocity= new Vector3(0,0,5);
Let say you have added 5f in z position and that force will be added when you'll press W key. So When you will press W key the object will instantly start at the speed of 5. It's like the same if you are adding force using this function on a car, that car will start at the speed of 5.
body.velocity= new Vector3(0,0,200);
And if you let say change the value to 200 and then after saving press W. Car will start running at the speed of 200 from starting which is not possible in real world.
Now If you talk about Rigidbody.addforce
By Continuing our Car example. if you add the force of 200 to car
The Car will not start moving at the speed of 200 if we press W but it starts from slow and then increases its speeds and stops according to the value of Drag.
Rigidbody.addforce starts slow and then speed up, just like you are dragging a heavy table, first you will start pushing that table, the table will just move a little bit from its position but if you keep pushing that table it will starting moving & if you leave that table it will cover some distance depending on surface and that's the same rigidbody.addforce do.
You can use Rigidbody.velocity where you just want to move your object to react instantly like player jump & the result of that force will vanish just after the jump and you can use Rigidbody.addforce where you need slow start and then the continuous movement like a rocket. If you use Rigidbody.addforce in jump , Player/Object will remain in space for a while and then will come back to ground .
Adding to existing answers. From what I tested, it seem
AddForce is buffered PER script. Meaning doing :
r.velocity = Vector3.zero;
In the same script, will stop your rigidbody as you expect it to.
But if you do the same, each line in a different script, making sure they run in the correct order using Script execution order panel of Unity. It will keep moving.
AddForce by his equivalent:
float v = (force / rigidbody.mass) * Time.fixedDeltaTime;
rigidbody.velocity += v;
Make it behave as expected.
I don't know if I missed something, because this is a quite strange behavior.