Search code examples
unity-game-enginegame-physics

How to add torque to a rigidbody until it's angular velocity is 0?


I'm trying to figure out how to stop the rotation of a rigidbody using inertia in Unity 3D. This is how I assumed it should be done, but when I ran it, it crashed Unity and I had to kill the process.

        while(rigidBody.angularVelocity.magnitude != 0) {
            rigidBody.AddTorque(-transform.up * REACTION_WHEEL, ForceMode.Impulse);
        }

So how would I go about adding torque to a rigidbody to bring it from any degrees/second to 0?


Solution

  • Note: I wrote this before looking up the different ForceModes, but all of the advice still stands. Your freeze was because you were asking for too much precision (you're subtracting from velocity by the same amount repeatedly, with no consideration for overstepping (.5 -1 is never 0) or direction (your object may not be spinning around Transform.up)), but I think what you really want follows:

    The problem you're running into is that torque is to angular velocity like acceleration is to normal velocity - you can set your acceleration to billions, but that won't affect your velocity until some time passes. If you want to stop your object this frame, you really just want to set rigidBody.angularVelocity = Vector3.zero;. If you want to slow down your object over time, then AddTorque is what you're looking for, but you want to do it only once per frame.

    If you're looking to make something slow down as if because of friction, then constant torque each frame is the goal, e.g.

    float SlowDownPerSecond = 2f;
    //...each frame:
    if(rigidBody.angularVelocity.maginitude > SlowDownPerSecond * Time.deltaTime){
        rigidBody.AddTorque(-rigidBody.angularVelocity.normalized * SlowDownPerSecond, ForceMode.Force);
    } else {//less than change per frame
        rigidBody.angularVelocity = Vector3.zero;
    }
    

    But you might also be less concerned with the velocity being exactly zero than you are with making it slow down smoothly, in which case you can just do

    rigidBody.AddTorque(rigidBody.angularVelocity * -.05f, ForceMode.Force);
    //or
    rigidBody.AddTorque(rigidBody.angularVelocity * -.05f * Time.deltaTime, ForceMode.Impulse);
    

    each frame. Although if this is what you're looking for, I think you can just up the angular Drag of the object either in the editor or at runtime with rigidbody.angularDrag = .1f, or whatever value you find feels right.