Strange Rotation bug?

Topics: User Forum
Dec 3, 2008 at 11:10 PM
I'm in the prototyping stages of a game idea and as part of this idea while I need the player to respond to certain collisions other things, such as moving from a fixed Y location, are being controlled by myself and setup before the update loop.

While playing around I noticed a strange bug; after the first simulation update for each new body the rotation for the various bodies in the world is always '6.28318548', even the ones which couldn't possibly have had any collisions occur yet.

Has anyone else seen this before? or am I just going insane?
Coordinator
Dec 4, 2008 at 8:25 AM
The current version returns 2xPI when the rotation is 0. I've made a note to change that in 2.1.
Dec 4, 2008 at 12:55 PM
Edited Dec 4, 2008 at 3:49 PM
@bobvodka: Well if you don't like it, I think you just have to change:

// File: body.cs
class Body
{
    // ...
    public float Rotation
    {
        // ...
        set
        {
            // ...
            while (rotation > MathHelper.TwoPi)
            {
                rotation -= MathHelper.TwoPi;
                ++_revolutions;
            }
            while (rotation <= 0)
            {
                rotation += MathHelper.TwoPi;
                --_revolutions;
            }
            // ...
        }
        // ...
}

To:
// File: body.cs
class Body
{
    // ...
    public float Rotation
    {
        // ...
        set
        {
            // ...
            while (rotation >= MathHelper.TwoPi)
            {
                rotation -= MathHelper.TwoPi;
                ++_revolutions;
            }
            while (rotation < 0)
            {
                rotation += MathHelper.TwoPi;
                --_revolutions;
            }
            // ...
        }
        // ...
}

and the same in Body.internal void IntegratePosition(float dt).
If I'm not totaly wrong this is enough... maybe genbox knows more...

@genbox: I tried to optimize the loops with:

// Calculate floating point remainder
int z = (int)(rotation / MathHelper.TwoPi);
if (rotation < 0)
    z--;
float remainder = (rotation - (float)z * MathHelper.TwoPi);

// Calculate revolutions
_revolutions += (int)((rotation - remainder) / MathHelper.TwoPi);
rotation = remainder;*/

This works good with normal objects but lets fixed-angle joints with targetAngle 0° spring around, thus I assume there is a bug in my _revolutions calculation. Maybe you could although need this algo. ;-)

cheers
Coordinator
Dec 4, 2008 at 7:50 PM
@SunDiver: Thanks. I will take a look at it.
Dec 5, 2008 at 9:54 AM
Edited Dec 5, 2008 at 10:02 AM
Hi genbox, just had another look at the algorithm and found the bug. The working version is:

// Calculate floating point remainder of rotation
int z = (int)(rotation / MathHelper.TwoPi);
if (rotation < 0)
    z--;
rotation = (rotation - (float)z * MathHelper.TwoPi);

_revolutions += z;

I think this was the better choice than the 2 loops, because it's much more accurate and has a constant time consumption.
Hope this can help ;-)
Coordinator
Dec 5, 2008 at 3:12 PM
@sunDiver: Thanks for the update. The accuracy being in that it returns 0 instead of twopi when no rotation is applied?
I have written it down on the 2.1 todo list to take a look at your code
Dec 5, 2008 at 3:41 PM
Edited Dec 9, 2008 at 9:04 AM
@genbox: Yes it returns 0 instead of twopi, but with accuracy I mean that the values for _revolutions and rotations are more close to the actual values they should be, because of the floating-point precision. And here a little example (assuming that the loops leave 0 to be 0):

With
rotation = MathHelper.TwoPi;
everything is fine, both algorithm return the same values. rotation=0; _revolutions=1;

But with
rotation = MathHelper.TwoPi * 4;
the "horror" begins...
the loops return rotations=6.28318453f; and _revolutions=3;
but the remainder calculation returns rotations=0f; and _revolutions=4;

Of course, the values are close, but the higher the values the more inaccurate the loops are.
Additionally if rotation becomes to large the loops becomes to an infinityloop because subtracting TwoPi doesn't change the value (float has an accuracy of 6 relevant digits, but you know that already I think), this will happen on values above 268435456 which normaly shouldn't appear, thus it's not a real problem ^^ (nevertheless I had it a couple of times *g*, but I think the trigger is somewhere in my code, by the way when I changed the loop code I had somewhere else a NAN instead of the infinity loop *g*... just to say it ;-) ).
Dec 7, 2008 at 5:54 PM
Thanks for the replies guys, I'll probably modify my local copy for now to react how I expect and await the 2.1 update :)
Dec 7, 2008 at 5:54 PM
Thanks for the replies guys, I'll probably modify my local copy for now to react how I expect and await the 2.1 update :)
Coordinator
Dec 19, 2008 at 4:04 PM
This has been fixed in 2.0.1.

Thanks to sunDiver for his 0-based rotation implementation.