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?

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.

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)

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;
}

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!

1 Like

here’s how I did it quick & dirty:

// clamp velocity:
Vector3 newVelocity = rigidbody.velocity.normalized;
newVelocity *= m_MaximumVelocity;
rigidbody.velocity = newVelocity;

the best way to keep velocity constant i have found is:

    void FixedUpdate () {
    		if (thisRigid.velocity.magnitude > maxVelocityMagnitude) {
                float x = thisRigid.velocity.magnitude / maxVelocityMagnitude; 
    			thisRigid.velocity /= x;
    		}
    	}

First, see how much has the velocity increased compared to maxVelocity.
Then divide the actual vector velocity by this number to get back instantly to maxVelocity.

Note: the relation between velocity and rigidbody2D.velocity.magnitude is 1/50 (magnit = vel/50).

I down-voted the last comment.

Rigidbody travelling at a Vector3 velocity

const float max floatVelocity;
Vector3 vector3Velocity;

Usually you look at the rigidBody in question to see why the velocity’s maximum is set very high. Does it need a limit function, or velocity maximum?

If this limit function is required, use Unity Behaviour as a helper.

if (NormalisedToFloat (vector3Velocity) > maxfloatVelocity)
   rigidbody.drag = dragAmount;

For anyone looking for something simple and that works (thanks ChatGPT):

public float maxSpeed = 40;
private Rigidbody rigidbody;

void Awake()
{
    rigidbody = GetComponent<Rigidbody>();
}

void FixedUpdate() {
    if (rigidbody.velocity.magnitude > maxSpeed)
        rigidbody.velocity = rigidbody.velocity.normalized * maxSpeed;
}