- Home /
Question closed. This shouldn't have been resurrected to begin with.
Limiting rigidbody velocity
When working with non-kinematic rigidbodies (especially bouncy ones), there can be situations where collisions with static colliders and other rigidbodies result in large increases in velocity. This can lead to undesirable effects, such as objects suddenly "teleporting" to random parts of the screen or breaking through static collider scenery.
What's the best way to limit the velocity of a non-kinematic rigidbody?
Could someone take a look at my post and let me know if this thread is really one and the same issue? You only mention collisions with known objects in this thread... in my scenario I have no collisions with known objects except, if any, the terrain itself... and also do see in my post that it happens while vehicle is at complete idle. http://answers.unity3d.com/questions/20456/terrain-unexpected-collisions-loopidy-loops
Answer by duck · Jan 11, 2010 at 04:40 PM
I can think of two methods of doing this, one of them is recommended against by UT though.
First, check the magnitude of your rigidbody.velocity][1].
If it's under the speed limit, take no action. If it's over the speed limit you can do one of two things:
The 'proper' way would be to apply a force in the opposite direction of the rigidbody's velocity. The amount of force should be proportional to the extent to which the rigidbody is exceeding its speed limit.
The naughty, non-recommended way would be to take the current velocity vector, and if its magnitude exceeds the speed limit, normalize the vector3, multiply it by the speed limit, and directly reassign the velocity vector.
I'm not entirely sure whether this second method comes recommended against just because of "non realism", or whether there could be more serious simulation-breaking consequences.
Thanks, Duck. $$anonymous$$y current approach is to gradually increase drag as the velocity approaches the limit, and then use the second approach (normalize/multiply) to clamp it. I've noticed that the velocity can exceed the "speed limit" (instantaneously, in some cases) in FixedUpdate, OnCollisionEnter, or OnCollisionExit, so I'm checking it all three places. But this feels a bit heavy-handed and overly complex, not to mention sub-optimal from a performance perspective. Also, as you mention, I'm concerned I might be unintentionally creating some undesirable side-effects.
While this works (and I don't think directly changing the velocity here should pose a problem really), if you do this on a lot of objects, and in many places, consider checking against the sqr$$anonymous$$agnitude of the velocity ins$$anonymous$$d, as that is faster. $$anonymous$$ay not make much of a difference here, but it's always good practice.
Wouldnt the $$anonymous$$ethod Vector2.Clamp$$anonymous$$agnitude(Vector2, float) or the Vector3 equivalent be an interesting alternative?
rigidbody.velocity = Vector3.Clamp$$anonymous$$agnitude(rigidbody.velocity, 10f);
How would you deter$$anonymous$$e the magnitude "speed limit" of a rigidbody? I am having difficulties with a ball that will break through colliders, and I can't deter$$anonymous$$e the speed at which it is doing so. I understand how to figure the magnitude of vectors, so that is not the problem. Simply deter$$anonymous$$ing the rigid body's maximum speed (the velocity at which it breaks through the colliders) is the difficulty.
Answer by Ehren · Feb 02, 2010 at 05:31 PM
I just posted a couple scripts for limiting velocity, along with an example project, to my blog. Here is the script for Duck's proposed solution.
#pragma strict
// This MonoBehaviour uses hard clamping to limit the velocity of a rigidbody.
// The maximum allowed velocity. The velocity will be clamped to keep // it from exceeding this value. var maxVelocity : float;
// The cached rigidbody reference. private var rb : Rigidbody; // A cached copy of the squared max velocity. Used in FixedUpdate. private var sqrMaxVelocity : float;
// Awake is a built-in unity function that is called called only once during the lifetime of the script instance. // It is called after all objects are initialized. // For more info, see: // http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.Awake.html function Awake() { rb = rigidbody; SetMaxVelocity(maxVelocity); }
// Sets the max velocity and calculates the squared max velocity for use in FixedUpdate. // Outside callers who wish to modify the max velocity should use this function. Otherwise, // the cached squared velocity will not be recalculated. function SetMaxVelocity(maxVelocity : float){ this.maxVelocity = maxVelocity; sqrMaxVelocity = maxVelocity * maxVelocity; }
// FixedUpdate is a built-in unity function that is called every fixed framerate frame. // We use FixedUpdate instead of Update here because the docs recommend doing so when // dealing with rigidbodies. // For more info, see: // http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.FixedUpdate.html function FixedUpdate() { var v = rb.velocity; // Clamp the velocity, if necessary // Use sqrMagnitude instead of magnitude for performance reasons. if(v.sqrMagnitude > sqrMaxVelocity){ // Equivalent to: rigidbody.velocity.magnitude > maxVelocity, but faster. // Vector3.normalized returns this vector with a magnitude // of 1. This ensures that we're not messing with the // direction of the vector, only its magnitude. rb.velocity = v.normalized * maxVelocity; }
}
// Require a Rigidbody component to be attached to the same GameObject. @script RequireComponent(Rigidbody)
Answer by A Square Fish · Dec 06, 2014 at 01:49 PM
The problem with doing the dirty example is defining the velocity of an object is against the physics system. It is like stopping the object from moving and sending it moving again.
Also cherub got us started on doing that every single processing frame, which is damage by your program to the physics engine! You would find yourself a lot better off using rigidbody.drag somehow, though I can't say that 100% is a good thing.
Here is my "definitive" answer to braking an object to a maximum speed:
float speed = Vector3.Magnitude (rigidbody.velocity); // test current object speed
if (speed > maximumSpeed)
{
float brakeSpeed = speed - maximumSpeed; // calculate the speed decrease
Vector3 normalisedVelocity = rigidbody.velocity.normalized;
Vector3 brakeVelocity = normalisedVelocity * brakeSpeed; // make the brake Vector3 value
rigidbody.AddForce(-brakeVelocity); // apply opposing brake force
}
Sorry Ehren, but I find your answer very unreadable on this page!
Can you please help with translate to vector2 for a 2d game or would this work for a 2d game
Hi bracciata.
$$anonymous$$y answer I've checked over and is not a fully working code in most circumstances. However it's close to a solution.
You may have noticed some are modifying rigidbody.velocity directly, which is known to stress the physics system and can slow down/affect badly the calculation processes. I am very against that! I think it is stated not to do this in the Unity reference?
To your question, you can convert all to Vector2 quite easily in this example, or use only Vector3 (x, 0.0f, z); if using a fixed Y plane. If using Z plane use only Vector3 (x, y, 0.0f)
There are other ways to cast out the 2 axis (2d) rather than 3 axis (3d). Simple?
Vector3 position3d = new Vector3(1.0f, 1,0f, 0.0f); // A position 1,1 on the Z axis
Vector2 position2d = position(position3d.x, position3d.y); // A conversion to Vector2
At least I hope that is a good advice for you.
the problem is that this approach doesn't take the mass into account.
Answer by cherub · Apr 04, 2014 at 05:07 AM
i found that doing this was pretty simple and worked:
if(rigidbody.velocity.sqrMagnitude > maxVelocity)
{
//smoothness of the slowdown is controlled by the 0.99f,
//0.5f is less smooth, 0.9999f is more smooth
rigidbody.velocity *= 0.99f;
}
wow, nice approach, just this works for me now. thanks, man!
O$$anonymous$$G... This was simple and works. In Cherub we trust! Thank you for such an elegant solution.
0.99 will still drop rigidbodies like meteorites, but between 0.5 and 0.999 u can definitely find a a sweet spot.
Answer by Spiff McShizly · Jan 14, 2013 at 09:59 PM
here's how I did it quick & dirty:
// clamp velocity:
Vector3 newVelocity = rigidbody.velocity.normalized;
newVelocity *= m_MaximumVelocity;
rigidbody.velocity = newVelocity;
This was the best answer for me, only slightly modified (my game is 2d / c#).
if($$anonymous$$athf.Abs(rigidbody.velocity.x) > maxSpeed || $$anonymous$$athf.Abs(rigidbody.velocity.y) > maxSpeed)
{
// clamp velocity:
Vector3 newVelocity = rigidbody.velocity.normalized;
newVelocity *= maxSpeed;
rigidbody.velocity = newVelocity;
}
Follow this Question
Related Questions
Why does this MeshCollider think it's half as thick? 2 Answers
Any way to have a rigidbody not be affected by forces, but still collide with other objects? 2 Answers
Physics gravity appears very weak 2 Answers
Rigidbody Moving around a tower 0 Answers
Turning a rigidbody controller into a character controller (almost) 1 Answer