Game Development Community

RotateTo bug

by Michael Woerister · in Torque Game Builder · 03/27/2006 (1:35 pm) · 5 replies

Hi,
the t2dSceneObject::rotateTo() does not work. I set "autoStop" and "snap" to true but the sprites keeps rotating. It looks like some floating point accuracy problem or the check whether the target rotation is reached misses a certain case because 70% of the time it works. The rotation target is 0.0 (to be accurate it is -0.0 but that should not make a difference, or does it?)

I spent some time looking at the updateRotationTarget() method in t2dPhysics.cc and rewrote it but that didn't help. Maybe I just overlooked something or it is the wrong place to look at.

#1
03/27/2006 (2:10 pm)
What is your snap distance set to? If you set it to 1 (rather than 0.1 for instance) does it work?
#2
03/27/2006 (2:22 pm)
I think tried with default and with 10 and got the same results. But that should not matter anyway or do I understand something wrong here. When a function is called rotateTo() then I suppose it does exactly that: rotate to the specified target.
#3
03/27/2006 (3:56 pm)
The problem is that float will most likely never reach a certain value. So if you don't give it an "error range", it will jump over the targeted value back and forth.
#4
03/27/2006 (11:22 pm)
I just took another look at it and discovered a copy and paste error in my modified version of updateRotationTarget(). I corrected it and now it seems to work fine. Here it is:
void t2dPhysics::updateRotationTarget( const F32 angularVelocity, const F32 elapsedTime )
{
    // Ignore if Rotation Target is inactive or being updated.
    if ( !getRotationTargetActive() || mUpdatingRotationTarget ) return;

    // Set Updating Rotation Target.
    mUpdatingRotationTarget = true;

    // Any Sweeping?
    if ( mIsZero(elapsedTime) || mIsZero(angularVelocity) )
    {
        // No, so just do a distance calculation.  Within specified distance?
        if ( mLessThanOrEqual( mFabs(getRotation()-getRotationTarget()), getRotationTargetMargin() ) )
        {
            // Yes, so process rotation target.
            processRotationTarget();
        }

        // Reset Updating Rotation Target.
        mUpdatingRotationTarget = false;
        // No rotation-integration so finish here.
        return;
    }

    // Fetch From/To Rotations.
    const F32 rotFrom = getRotation();
    const F32 sweep = angularVelocity * elapsedTime;
    const F32 rotTo = rotFrom + sweep;  

    // Fetch Rotation Target.
    F32 rotTarget = getRotationTarget();

    setRotation(rotTo);

    if( mGreaterThanOrEqual( mFabs(sweep + getRotationTargetMargin()),360.0f) )
    {
       processRotationTarget();
    }
    else
    if( mLessThanZero(rotTo) )
    {
       if( mLessThanOrEqual(rotTarget, rotFrom + getRotationTargetMargin() ) || mGreaterThanOrEqual(rotTarget, (rotTo - getRotationTargetMargin()) + 360.0f) )
          processRotationTarget();
    }
    else
    if( mGreaterThan(rotTo,360.0f) )
    {
       if( mGreaterThanOrEqual(rotTarget, rotFrom - getRotationTargetMargin() ) || mLessThanOrEqual(rotTarget, rotTo + getRotationTargetMargin() - 360.0f) )
          processRotationTarget();       
    }
    else
    {
       F32 rotMin, rotMax;      

       mGetMinMax(rotFrom,rotTo,rotMin,rotMax);
   
       if( mGreaterThanOrEqual(rotTarget, rotMin - getRotationTargetMargin()) && mLessThanOrEqual(rotTarget, rotMax + getRotationTargetMargin()))
          processRotationTarget();
    }

    // Reset Updating Rotation Target.
    mUpdatingRotationTarget = false;
}

It should be bullet proof now.
#5
04/13/2006 (11:39 am)
Michael,

Thanks a bunch for this fix, I've integrated it into our repository and it will be included in the next release!

Cheers,
-Justin