26
\$\begingroup\$

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?

\$\endgroup\$
  • 1
    \$\begingroup\$ If you're using Unity, check out Mathf.DeltaAngle(). \$\endgroup\$ – Russell Borogove Jul 14 '14 at 17:21
22
\$\begingroup\$

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;
\$\endgroup\$
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ – deft_code Jan 7 '11 at 16:09
  • 2
    \$\begingroup\$ Yes, when converting between vectors and angles, atan2() is most definitely your friend. \$\endgroup\$ – bluescrn Jan 7 '11 at 23:30
  • 1
    \$\begingroup\$ Thanks! I've found that I actually don't really need the angle, grabbing the 2D cross product is simple enough for my needs. \$\endgroup\$ – Error 454 Jan 8 '11 at 2:59
  • 2
    \$\begingroup\$ Also your if( cross == -0.0f ) vs if( cross == 0.0f ) check looks extremely fragile. \$\endgroup\$ – bobobobo Nov 25 '12 at 21:42
  • 1
    \$\begingroup\$ @bobobobo, with a physics engine it may not be an option to just pick a direction and move. Magically turning can cause physic engines to freak out. Further magically rotating looks terrible for animation as well. So yes, you can solve this without a notion of left or right, but a polished solution often needs these. \$\endgroup\$ – deft_code Nov 26 '12 at 20:36
10
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ 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. \$\endgroup\$ – Error 454 Jan 8 '11 at 2:58
  • \$\begingroup\$ @Error 454, you're absolutely right, fixed my post. \$\endgroup\$ – Tetrad Jan 8 '11 at 4:11
1
\$\begingroup\$

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)
\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
  • 5
    \$\begingroup\$ This is exactly what the atan2() function implements for you. :) \$\endgroup\$ – Nathan Reed Sep 30 '11 at 18:59
  • \$\begingroup\$ @NathanReed, yeah, but couldn't you use this method with a dot product to avoid the trig overhead? \$\endgroup\$ – jdk1.0 May 14 '18 at 20:02
0
\$\begingroup\$

Maybe I should post a slightly different question and answer it myself; this is the closest question I could find to the one I had.

I'm doing 2D work in the html canvas, where I have rotation angles in radians rather than vectors. I needed the "turn angle" (ta) to get from "current heading" (h) to the "target heading" (t).

Here's my solution:

var ta = t - h,
    ata = Math.abs(ta)
;
if (ta > Math.PI) ta = (ta / ata) * (Math.PI - ata)
return ta;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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