2
\$\begingroup\$

I'm trying to implement a type of movement where the object gradually faces the target. The problem I've run into is figuring out which turning direction is faster. The following code works until the object's orientation crosses the -PI or PI threshold, at which point it will start turning into the opposite direction

void moveToPoint(sf::Vector2f destination) {
    if (destination == position) return;

    auto distance = distanceBetweenPoints(position, destination);
    auto direction = angleBetweenPoints(position, destination);

    /// Decides whether incrementing or decrementing orientation is faster
    /// the next line is the problem
    if (atan2(sin(direction - rotation), cos(direction - rotation)) > 0 ) {
        /// Increment rotation
        rotation += rotation_speed;
    } else {
        /// Decrement rotation
        rotation -= rotation_speed;
    }

    if (distance < movement_speed) {
        position = destination;
    } else {
        position.x = position.x + movement_speed*cos(rotation);
        position.y = position.y + movement_speed*sin(rotation);
    }
    updateGraphics();
}

'rotation' and 'rotation_speed' are implemented as custom data type for radians which cannot have values lower than -PI and greater than PI. Any excess or deficit "wraps around". For example, -3.2 becomes ~3.08.

\$\endgroup\$
2

2 Answers 2

3
\$\begingroup\$

Assuming direction is the desired rotation angle to turn toward, just subtract direction - rotation and wrap the result into the [-pi, pi] range. Then its sign should indicate the correct direction to turn. There's no need to munge it through any trigonometric functions.

\$\endgroup\$
3
  • \$\begingroup\$ Yes, direction is the desired rotation. What you're suggesting doesn't work any better than what I had before though. \$\endgroup\$
    – A.B.
    Commented Jun 28, 2013 at 20:00
  • \$\begingroup\$ I think what he is saying is that you do not need atan2 there since you already have the desired direction. From there I usually check to see if the difference is greater than pi or less than -pi and subtract or add 2pi to ensure that it turns to the shortest distance. \$\endgroup\$ Commented Jun 28, 2013 at 20:43
  • \$\begingroup\$ I have to correct myself. It works - there was a problem with the [-PI, PI] that wasn't apparent. \$\endgroup\$
    – A.B.
    Commented Jun 28, 2013 at 20:57
0
\$\begingroup\$

This is faster because it does not have to calculate the atan. It just determines if your angle is greater or lesser than Path.PI.

/**
* Gets the angle that is in the range [-2*PI, 2*PI] and returns the equivalent angle
* that is in the (-PI, PI] range.
*/
void function normalizeAngle(a:Number):Number {
    if (a > Math.PI) {
        return a - 2 * Math.PI;
    } else if (a <= -Math.PI) {
        return a + 2 * Math.PI;
    }
    return a;
}

// usage example:
var rotationDifference:Number = normalizeAngle(targetRotation - originalRotation);

On each update you rotate a portion of the rotationDifference.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Just change the if in while to make it work for all angles. Of course, get rid of the else :) \$\endgroup\$ Commented Jun 28, 2013 at 22:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .