- Home /
How to calculate time it takes for angular velocity to reach 0 w/ angular drag being applied?
Hi there,
So I apply a force to my Image GameObject like:
img.GetComponent<Rigidbody2D>().angularVelocity = Random.Range(-720, -1080);
After this I'd like to calculate the time it takes - in seconds - for the angular drag to stop its rotation. Angular drag is 0.5, mass is 1.0, the object's position is freezed on both the x and y axis.
I tried with:
img.GetComponent<Rigidbody2D> ().angularVelocity * img.GetComponent<Rigidbody2D> ().angularDrag * Time.fixedDeltaTime;
It does give an almost accurate result but I suppose it is more complicated than just dividing or multiplying 2 or 3 variables together. I've also searched Unity's references for physics and (angular) drag but it only describes the definition of it and its damping, coefficient. No formula or method given how it is being calculated.
The usage would be a "Spin the Wheel" kind of feature for my game, where by a button the player gives a random rotation on the Z for the above image gameobject and within an IEnumerator, I use yield return new WaitForSeconds(time it takes to reach 0) and after that, based on its angle an award will be presented to the player.
Any suggestions are welcome, thanks for your time!
Christian
Answer by Bunny83 · Jun 04, 2018 at 05:38 PM
Well, the angular drag is just a percentage slowdown. To get the multipier that the angular velocity is multiplied with every fixed frame you just need to multiply the angularDrag with the fixedDeltaTime which gives you the slowdown percentage. Subtract this from "1" and you get the multiplier that is applied each fixed frame.
Once you have this you have to define an angular velocity that you consider "resting". The sleeping behaviour is not that easy to calculate as it relies on the kinetic energy of the rigidbody and for the angular velocity it depends on the inertia tensor. So it's easier to just say an angular velocity of "0.05" is our goal. Note that you can't go for an velocity of 0 as in theory you would never reach it. If your starting angular velocity is "10" we just calculate the total factor that brings us from 0.05 to 10 (or the other way round). In this case 10 / 0.05 == 200
Now we can use the logarithm to calculate the required steps it would take to reach that goal:
log(200) / log(1-angularDrag*fixedDeltaTime)
This will give us a negative number. However the absolute value should be the exact number of fixed frames until you reach an angular velocity of 0.05 when starting from 10
As a method it would be something like this:
public static float AngularDragTime(float aVelocity, float aTargetVelocity, float aAngularDrag)
{
float d = aVelocity / aTargetVelocity;
float a = 1f - aAngularDrag * Time.fixedDeltaTime;
return -Time.fixedDeltaTime * (Mathf.Floor(Mathf.Log(d) / Mathf.Log(a))-2);
}
This should return the time in seconds until a rigidbody with an angular velocity of "aVelocity" reaches aTargetVelocity when using the "aAngularDrag " and no other forces are applied. The floor and the additional "2" frames seem to work consistently. If i count down the calculated time each fixed frame then the time will reach 0 at the same frame as the velocity drops below our target velocity.
In the past Untiy had a seperate velocityThreshold and angularVelocityThreshold. Now they have combined them into the sleepThreshold which isn't directly based on the velocity but on the kinetic energy. Since the kinetic energy of a rotating body depends on the inertia tensor, a thin rotating pole has a quite high sleeping velocity while a large rotating disk has a rather small sleeping threshold. I did a test: A "0.1 x 0.1" cube with mass 1 has a sleeping angularvelocity of 0.2 which is quite noticeable. A normal "1 x 1" cube with mass 1 had 0.02 and a similar 10x10 cube has 0.002.
So you may need to pick a target velocity that is appropriate for your case. A true wheel of fortune usually has this spring flipper to make it more clear where it actually lands. Though for a cimulated wheel it's usually not necessary.
Answer by Tobychappell · Jun 04, 2018 at 03:58 PM
Have you considered using:
while(!img.GetComponent<Rigidbody2D>().isSleepgng())
{
yield return new WaitForSeconds(0.2f);
}
https://docs.unity3d.com/ScriptReference/Rigidbody2D.IsSleeping.html
Your answer
Follow this Question
Related Questions
Adding More Torque 1 Answer
2D Geometry dash-like ship physics 0 Answers
Dashing with rigidbody2D not working right 2 Answers
How to Maintain Constant Velocity of a Moving GameObject? 0 Answers
Object jitters when the scene starts 0 Answers