Skip to main content
GameDev.net gamedev.net
🔒 Locked

Rotation with atan2() problem

Started by Endemoniada Sep 23, 2009 at 1:20 PM 2 replies 11.8k views
Original Post
Endemoniada
Endemoniada
Hi guys, I'm having problems picking the direction (positive/negative) to rotate so I take the shortest way around. I am using atan2() to convert a 2D vector (desired orientation) to an angle, and it's the way it jumps from Pi to -Pi that's mixing me up. Ideally I'd like something like this: targetAngle=atan2(dir.x,dir.z); // desired direction with 0.0 down the z-axis if(targetAngle > currentAngle) currentAngle+=(rotationRate*timespan); // clamp if(currentAngle > targetAngle) currentAngle=targetAngle; } else if(targetAngle < currentAngle){ currentAngle-=(rotationRate*timespan); // clamp if(currentAngle < targetAngle) currentAngle=targetAngle; } That method work alright but sometimes it ends up "taking the long way around". I can't figure out a nice way fix it. Thanks.
enigmatix
enigmatix
This is just off the top of my head, but maybe you can give it a try...

targetAngle = atan2(dir.x,dir.z);if (targetAngle < 0) targetAngle += 2pi; //We want the full 2pi radians.//Check for either direction...int cw;int ccw;//Two possible cases for each direction...if(currentAngle > targetAngle){ccw = 2pi - currentAngle + targetAngle;cw = currentAngle - targetAngle;}else if(currentAngle < targetAngle){ccw = targetAngle - currentAngle;cw = 2pi - targetAngle + currentAngle;}if (cw > ccw) //turn ccw...else if (cw == ccw) //randomize?else //turn cw...


So basically, I offset the -pi...pi angle to 0...2pi for easier checking. And then i check to see which angle is greater, depending on that result, we can determine the distance in each direction, taking into account the wrapping of 0 and 2pi. Hope this is helps.
grhodes_at_work
grhodes_at_work
If the result from atan2 is negative, just add 2pi to it, which is periodically the same angle. Leave positive results from atan2 untouched. That'll put you back in the 0 to 2pi range and will avoid the discontinuity you mentioned.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Zakwayda
Zakwayda
Another option would be to use relative angles (or even not to use angles at all). This way you'd be able to bypass the problem of periodicity completely.

An example using relative angles:
vector2 diff = target - position;float angle = atan2(perp_dot(forward, diff), dot(forward, diff));if (angle < 0) {    // Turn one direction...} else if (angle  > 0) {    // Turn the other direction...}
If you're just going to turn by a fixed rate, you don't even need to compute the angle:
float dot = perp_dot(forward, target - position);if (dot < 0) {    // Turn one direction...} else if (dot > 0) {    // Turn the other direction...}
In practice you may want to compare to a tolerance or epsilon so that the agent doesn't 'jitter' while trying to stay aligned with the target.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.