Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am working on some movement AI where there are no obstacles and movement is restricted to the XY plane. I am calculating two vectors, v, the facing direction of ship 1, and w, the vector pointing from the position of ship 1 to ship 2.

I am then calculating the angle between these two vectors using the formula

arccos((v · w) / (|v| · |w|))

The problem I'm having is that arccos only returns values between 0° and 180°. This makes it impossible to determine whether I should turn left or right to face the other ship.

Is there a better way to do this?

share|improve this question
    
If you're using Unity, check out Mathf.DeltaAngle(). –  Russell Borogove Jul 14 at 17:21

4 Answers 4

up vote 20 down vote accepted

It's much faster to use a 2d cross-product. No costly trig function involved.

b2Vec2 target( ... );
b2Vec2 heading( ... );

float cross = b2Cross( target, heading );

if( cross == -0.0f )
   // turn around

if( cross == 0.0f )
  // already traveling the right direction

if( cross < 0.0f)
  // turn left

if( cross > 0.0f)
  // turn right

If you still need the actual angles I recommend using atan2. atan2 will give you the absolute angle of any vector. To get the relative angle between any to vectors, calcuate their absolute angles and use simple subtraction.

b2Vec2 A(...);
b2Vec2 B(...);

float angle_A = std::atan2(A.y,A.x);
float angle_B = B.GetAngle(); // Box2D already figured this out for you.

float angle_from_A_to_B = angle_B-angle_A;
float angle_from_B_to_A = angle_A-angle_B;
share|improve this answer
1  
After reading @Tetrad's answer I suppose you could combine a cross product and an arccos. This way you'll only use one trig function, but still have the actual angle. However I recommend against this optimization until you're sure you AI angle tracking is making a noticeable impact on your game's performance. –  deft_code Jan 7 '11 at 16:09
    
the magnitude of the cross product vector gives you the sin of the angle between them, not the cos. So you need to use arcsin. –  Tetrad Jan 7 '11 at 19:29
2  
Yes, when converting between vectors and angles, atan2() is most definitely your friend. –  bluescrn Jan 7 '11 at 23:30
1  
Thanks! I've found that I actually don't really need the angle, grabbing the 2D cross product is simple enough for my needs. –  Error 454 Jan 8 '11 at 2:59
1  
Also your if( cross == -0.0f ) vs if( cross == 0.0f ) check looks extremely fragile. –  bobobobo Nov 25 '12 at 21:42

Use arcsin of the 2D cross product (i.e the z component of the cross product vector). That'll give you -90 to 90 which will let you know whether to go left or right.

Be careful because A cross B is not the same as B cross A.

Another strategy (but probably not as straight forward) is to calculate the "heading" of the two vectors using atan2 and then figuring out whether A pointing at X degrees needs to go left or right to go to B pointing at y degrees.

share|improve this answer
    
Thank you for the response. To be clear for future browsers, taking the inverse sine of the magnitude of the 2d cross product would yield values between 0 and 90. Taking the sine of the z-component of the 2d cross product yields the desired results. –  Error 454 Jan 8 '11 at 2:58
    
@Error 454, you're absolutely right, fixed my post. –  Tetrad Jan 8 '11 at 4:11

Use vectors to redirect the ship. This is how "steering behaviors" work -- you never need to calculate the angle, just use the vectors you have. This is computationally much cheaper.

The vector w (vector from Ship 1 to Ship 2) is all the information you need. Modify either ship 1's velocity vector or ship 1's acceleration vector (or even the heading vector directly) using a weighted version of w.

enter image description here

The magnitude of how far off ship 1 is off course (how badly v does not match up with w) can be found by using ( 1 - dot(v,w) )

  • (dot(v,w) is maximized when v and w line up exactly)
  • (1 - dot(v,w)) gives 0 when v and w are completely lined up, provided v and w are normalized)
share|improve this answer

There is a simple way to find the absolute angle of a vector through normal geometry.

for example vector V = 2i - 3j;

absolute value of x coefficient = 2;

absolute value of y coefficient = 3;

angle = atan( 2 / 3 ); [ angle will be in between 0 to 90 ]

Based on quadrant angle will be changed.

if ( x coefficient < 0 and y coefficient > 0 ) then angle = 180-angle;

if ( x coefficient < 0 and y coefficient < 0 ) then angle = 180+angle;

if ( x coefficient > 0 and y coefficient < 0 ) then angle = 360-angle;

if ( x coefficient > 0 and y coefficient > 0 ) then angle = angle;

after finding angle of first and second vectors, just subtract first vector angle from second vector. Then you will get absolute angle between two vectors.

share|improve this answer
5  
This is exactly what the atan2() function implements for you. :) –  Nathan Reed Sep 30 '11 at 18:59

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.