# Finding the smallest turn angle

This topic is 4507 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi., This is for a npc orientation system. Imagine the npc walking around in his path, and then turning into some random direction. I find the turning angle, and i turn it to that direction. However, i'm making a smooth rotation, so i need to find the smallest turn angle. For example, the NPC is walking with angle orientation of 1º, and i find that his new orientation will be -30º. So, i just do: if(angle_to_be > npc->current_orientation ) npc->angle++; if(angle_to_be < npc->current_orientation ) npc->angle--; And i update the npc_angle until he matches the npc_current_orientation. However this has problem., imagine that the npc has a walking angle of 1º, and the new orientation angle will be 330. In this case, he will do a huge rotation over himself, to get from 1 to 330, when it would be simpler to rotate -31º, which would be a much smaller. So, if i do this : if( (angle_to_be < 0) && ( npc->current_angle > 0) )angle_to_be += 360; else if( (npc->current_angle < 0) && (angle_to_be > 0) )angle_to_be -=360; Altough this fixes for 80% or 90% of the cases, its still not working 100%, in the first case for example, angle orientation of 1º, and a new orientation of -30º, it fails again, as he will make a rotation of 329º instead of a -30. I think i'm overcomplicating this..., Anyone can give me a hand here ? thanks

##### Share on other sites
You could probably get this to work with the right combination of conditionals and whatnot, but I'd think it would be easier to take a slightly different approach. Here's what I'd do:

1. Compute the direction vector for the current angle (you probably already have it available)

2. Compute the direction vector for the goal angle

3. Compute the signed angle between them as atan2(perp_dot(a,b), dot(a,b))

This will always give you the angle to the goal orientation with the smallest magnitude. Also, if you don't already have a 'perp dot' function, it's just a.x*b.y-a.y*b.x.

##### Share on other sites
Assuming you have a function that wraps a variable into a specified range you first wrap the desired angle around the desired angle, then you modify the angle, then you wrap the final angle into [180, 180]. So:

// wraps val into the range valMin, valMax by adding/subtracting multiples // of (valMax - valMin). Requires valMax > valMin.template<typename T>inline void Wrap(T &val, const T &valMin, const T &valMax){  assert(valMax > valMin);  while (val > valMax)    val -= (valMax - valMin);  while (val < valMin)    val += (valMax - valMin);}void YourFn(){  //... your stuff  Wrap(angle_to_be, npc->angle-180, npc->angle+180);  if (angle_to_be > npc->angle) ++npc->angle;  else if (angle_to_be < npc->angle) --npc->angle;  Wrap(npc->angle, -180, 180);}

Untested/uncompiled code so apologies for typos, but I hope the idea makes sense :)

##### Share on other sites
Try this C++ func i just wrote to tween between two angles using the shortest distance. Let me know if it doesn't work and I'll try a closer look, I've not tested it.

Not claiming this to be the ideal method, it's just the one I happen to use.
float TweenAngle( float from,float to,float tween ) //tween should be between 0 and 1. 0 = from. 1 = to and inbetween = inbetween.if( from>to ){   float d1,d2;   d1 = from-to;   d2 = 360 - from + to;   if(d1<d2)   {       return from-(d1*tween);   }else   {       return from+(d2*tween);   }}else{  float d1,d2;  d1 = to-from;  d2 = 360 - to +from ;  if(d1<d2)  {     return from+d1*tween;  }else  {     return from-d2*tween;  }}

This will return the correct angle but you might want to do a ang mod 360 to wrap it into a valid 0-360 range if needed.

##### Share on other sites
Try this C++ func i just wrote to tween between two angles using the shortest distance. Let me know if it doesn't work and I'll try a closer look, I've not tested it.

Not claiming this to be the ideal method, it's just the one I happen to use.
float TweenAngle( float from,float to,float tween ) //tween should be between 0 and 1. 0 = from. 1 = to and inbetween = inbetween.if( from>to ){   float d1,d2;   d1 = from-to;   d2 = 360 - from + to;   if(d1<d2)   {       return from-(d1*tween);   }else   {       return from+(d2*tween);   }}else{  float d1,d2;  d1 = to-from;  d2 = 360 - to +from ;  if(d1<d2)  {     return from+d1*tween;  }else  {     return from-d2*tween;  }}

This will return the correct angle but you might want to do a ang mod 360 to wrap it into a valid 0-360 range if needed.

##### Share on other sites
Triple Post. The bugs of the internet are in full force this morning.

##### Share on other sites
This should work:

if (new_angle > current_angle && new_angle - current_angle <= 180) current_angle += new_angle - current_angle;else if (new_angle > current_angle && new_angle - current_angle > 180) current_angle -= 360 - (new_angle - current_angle);else if (new_angle < current_angle && current_angle - new_angle <= 180) current_angle -= current_angle - new_angle;else if (new_angle < current_angle && current_angle - new_angle > 180) current_angle += 360 - (current_angle - new_angle);

1. 1
2. 2
3. 3
Rutin
22
4. 4
5. 5

• 12
• 18
• 14
• 9
• 9
• ### Forum Statistics

• Total Topics
632929
• Total Posts
3009283
• ### Who's Online (See full list)

There are no registered users currently online

×