- Home /
Rigidbody set velocity on 1 axis without changing the others.
What I basically want is to modify the transform.forward velocity if something. I want to keep the down velocity resulting from gravity and a side velocity resulting from wind. All i need is to set the forward velocity.
The script below however resets the whole velocity, so gravity no longer works.
void FixedUpdate() {
r.velocity = transform.forward * targetSpeed;
}
To put it into context, I have a fighter jet which accelerates and decelerates. I control the target speed and I don't wish to rely on addforce()
.
Is there a way by which I can update the forward velocity every fixed update, but also keep the up and right velocities?
Answer by rutter · Sep 26, 2015 at 12:10 AM
If "forward" is always pointing along the z-axis, then it's pretty straightforward to grab the velocity and change that one axis:
Vector3 vel = rigidbody.velocity;
vel.z = 0f;
rigidbody.velocity = vel;
If "forward" can be any direction, then you may need to apply a concept called vector projection. The jet's total velocity can be divided into three components, all based on the jet's local axes.
//get the jet's velocity, break it into three parts
//each part represents the jet's world-space velocity in terms of its local axes
Vector3 vel = rigidbody.velocity;
Vector3 jetUp = Vector3.Project(vel, transform.up);
Vector3 jetRight = Vector3.Project(vel, transform.right);
Vector3 jetFwd = Vector3.Project(vel, transform.forward);
//separate the direction and speed
Vector3 fwdDir = jetFwd.normalized;
float fwdSpeed = jetFwd.magnitude;
//let's say we want to cap the jet's forward speed between 1 and 5
fwdSpeed = Mathf.Clamp(fwdSpeed, 1f, 5f);
//recombine direction and speed
jetFwd = fwdDir * fwdSpeed;
//recombine the three component vectors
vel = jetUp + jetRight + jetFwd;
rigidbody.velocity = vel;
The above code is effectively doing the same thing as the first example, with some added math to remove the assumption that you're traveling straight down the z-axis.
Wrong.
Your solution still cancels the other axis' forces.
Answer by Glurth · Sep 26, 2015 at 12:34 AM
Why not do it the way nature does, and apply air resistance, in the opposite direction of movement? The strength of the air-resistance force, increases based upon the speed squared.
(When this force is equal to the force of gravity/ or your engines, you have reached terminal velocity: your speed will not increase because the forces negate each other, and thus your air resistance force will not increase either.)
Something like this:
float air_reistance_strength= r.velocity.magnitudeSquared * some_constant_like_air_viscosity;
r.AddForce(r.velocity.normalized * -1.0f * air_reistance_strength);
Answer by Arycama · Sep 28, 2015 at 06:16 AM
An easy way to do this would be to get the world velocity of the object, convert it into local velocity, modify the Z component of the local velocity (Which would be the forward axis of the object), convert the modified local velocity back to world velocity, and then set that as the new velocity of the object. Something like:
Vector3 localVelocity = transform.InverseTransformDirection(rigidbody.velocity);
localVelocity.z = targetSpeed;
rigidbody.velocity = transform.TransformDirection(localVelocity);
This worked for me perfectly. I think this is the answer everyone's been looking for. Thanks man
Answer by Addyarb · Sep 25, 2015 at 10:18 PM
I'm pretty sure AddForce accepts a Vector3 as a parameter, so why not try something like:
void FixedUpdate() {
Vector3 ForwardForce = new Vector3 (0,0,targetSpeed);
rb.AddForce(ForwardForce);
}
Right...
FFS - Everyone knows how to add force in one direction!!!
The question is, HOW DO YOU DO IT WITHOUT SETTING THE OTHER AXIS TO ZERO LI$$anonymous$$E YOU SO OBTUSELY DID?!
@LukeNukem44 You need to calm the F down, because you obviously don't understand how AddForce works. He did NOT set the other two axes to zero. It's in the name, man... ADD... force.
Answer by Ady_M · Jan 06, 2019 at 02:01 AM
@Arycama's answer should be the accepted one.
Here's a Quaternion version of it that does not depend on Transform's methods in case you need to work with vectors that do not directly belong to a Transform, Rigidbody, etc:
Vector3 localVelocity = Quaternion.Inverse (transform.rotation) * rigidbody.velocity;
localVelocity.z = 0; // Whatever forward value you want
rigidbody.velocity = transform.rotation * localVelocity;