4
\$\begingroup\$

I am making an air combat game, where you can fly a ship in a 3D space. There is an opponent that flies around as well. When the opponent is not on screen, I want to display an arrow pointing in the direction the user should turn, as such:

circle with red arrow at one corner like a radar map pointing the way to the enemy

The arrow will be on the HUD. It will not actually turn to the opponent. I want it to indicate which direction a user should turn to see the enemy ship. This arrow will circle around the cross-hairs (radius 60 pixels).

So, I took the camera location and the opponent location and did this:

double newDirection =
   atan2(activeCamera.location.y-ship_wrap.location.y,
   activeCamera.location.x-ship_wrap.location.x);

After which, I get the position on the circumferance of a circle which surrounds my crosshairs, like such:

trackingArrow.position = point((60*sin(angle)+240),60*cos(angle)+160);

It all works fine, except it's the wrong angle! I assume my calculation for the new direction is incorrect. Can anyone help?

\$\endgroup\$
11
  • 1
    \$\begingroup\$ This is a common question, typically in the form of "How can I make X face Y?" Seen here, here, here, here, here, and more but I'm running out of ch \$\endgroup\$
    – House
    Apr 4, 2012 at 15:39
  • \$\begingroup\$ If you have a 3D game, then what you're doing there with your snippet is not going to work since you need to know where your camera looks at. I assume you're parallel to the ground and want to turn your ship via a rotation (yaw in this case). You absolutely need the camDir vector. What you have to do then is _asin( cross ( _camDir, normalize( shipPos - camPos) ) __ - in a nutshell. cross = cross product of 2 vectors - 2D or 3D. \$\endgroup\$
    – teodron
    Apr 4, 2012 at 15:50
  • \$\begingroup\$ @Byte56: We don't tell people that their question is a duplicate. We close the question as a duplicate. That only only tells people that it is a duplicate, it closes the question. \$\endgroup\$ Apr 4, 2012 at 21:06
  • \$\begingroup\$ @NicolBolas Well, it's not exactly a duplicate, but similar enough that they would be able to figure out what to do based on the other answers. \$\endgroup\$
    – House
    Apr 4, 2012 at 21:24
  • \$\begingroup\$ @Byte56: It's a duplicate. It may be in a different language, but it's all the same. \$\endgroup\$ Apr 4, 2012 at 21:36

3 Answers 3

3
\$\begingroup\$

The big problem that I see is that you don't subtract the camera's angle from the calculated angle. You should have:

double newDirection = atan2(activeCamera.location.y-ship_wrap.location.y, activeCamera.location.x-ship_wrap.location.x)-cameraAngle;

If you don't then when the camera rotates, the direction will remain the same!

I also think you've got the coordinate system wrong somewhere. Here are some diagnostic questions:

  1. Is your Z axis the vertical axis? If it is you're fine. If not, replace .x and .y with the axes forming a flat plane (eg axes parallel to the ground).
  2. Does the coordinate system of the point(x,y) function have (0,0) as the top left pixel?

If it does then I see a problem with this line of code:

point(60*sin(angle)+240,60*cos(angle)+160);

The idea with that line is that when angle=0 you should have the topmost pixel, when angle=90 degrees it should be the leftmost pixel, and when angle=-90 it should be the rightmost pixel. Here, if angle=0 the coordinates are point(240,220) when - if (0,0) is the top left pixel - the value should be (240,100). (the topmost pixel).

Also, when angle=90 the pixel is point(300,160) when it should be (180,160). So you need to negate both:

point(-60*sin(angle)+240,-60*cos(angle)+160);

A similar line of reasoning could be used for other coordinate systems.

\$\endgroup\$
1
  • \$\begingroup\$ +1, you are right since I didn't include an upVector for the ship to take care of the fact that the sine resulting from the cross product is actually always positive: that angle is the least of the two possible rotation angles against the cross product vector, a rotation meant to align the first vector with the second. So, technically, I'd go with your answer. Perhaps specify that cameraAngle = atan2(camDir.y, camDir.x) for other users to understand easier this discussion. Cheers! \$\endgroup\$
    – teodron
    Apr 5, 2012 at 8:27
4
\$\begingroup\$

I've seen the comment of Byte56, but the links there don't provide the exact answer, or aren't graphically detailed for this specific task, so if it's an answer the user wants, why not let him have one. Here goes. enter image description here

Imagine you're flying over the ground (the xy plane) and your ship's orientation is known (the green camDir vector). You want your camDir to coincide with the red vector (from your positions to your opponent's position,i.e. normalize(targetPos - camPos) = targetDir )

To turn in a relevant way for your picture description, you could rotate against the Z axis. To find the amount of rotation, you need to compute the cross product of camDir and targetDir. The cross product tells you the shortest turning orientation because |cross(a,b)| = |a| |b| sin(angle(a,b)) . Note that the angle between the two vectors is less than 180 degrees, in absolute value. Now, you can compute the dot product to find the cosine of the turning angle since dot(a,b) = |a| |b| cos(angle(a,b)).

The nice part is that both camDir and targetDir are unit/normalized vectors, so their cross and dot products provide you with the sine and cosine of the angle you want. Now just apply atan2 on the sine and cosine and retrieve the value of your angle (the dark-red arc in the image, for example). The blue circle around the plane is the same as your "radar" circle. That should be about it. So you need the camera direction, just the position of your ship is not enough - you have to "fire" in a direction, right?

\$\endgroup\$
4
  • \$\begingroup\$ Excellent, thank you! It isn't positioning the ship I was worried about, it is finding the angle in a 3d and then mapping it to a 2d plane. The question isn't concerned with rotating to a position (perhaps I wasn't specific enough, most the the comments above were in reference to that), I can do that easy enough. It is simply an indicator of which direction a user should turn. I already have translation and rotation for both the user and enemy as well as firing. ;) \$\endgroup\$
    – Beaker
    Apr 5, 2012 at 1:37
  • 1
    \$\begingroup\$ You'd have to use the actual value of the cross product, because the length of a vector can't be negative (so if sin(theta) is negative the equation breaks down). Since A and B are on the same 2d plane, AxB has a Z component but an X and Y component of zero. So the Z component is sin(theta) WITH the sign. No length-taking necessary. \$\endgroup\$
    – user10968
    Apr 5, 2012 at 4:05
  • \$\begingroup\$ Sorry to burst your bubble, but this method is 100% equivalent in theory to his method IF you subtract the camera's angle from his result.mathbin.net/91914 \$\endgroup\$
    – user10968
    Apr 5, 2012 at 4:48
  • \$\begingroup\$ No bubble burst, they're equivalent. Both ways of reasoning make use of a very crude assumption: the plane performs only yaw (against the Z, perpendicular to the ground axis). Otherwise that radar scope doesn't make any sense. One thing I should say in my "defense" :P : I don't make use of an extra atan2 to compute the ship's angle, I assume the ship's direction is more useful to him, that's why I gave this solution. By the way, good latex explanation. \$\endgroup\$
    – teodron
    Apr 5, 2012 at 8:19
2
\$\begingroup\$

There's a pretty easy way to do it using the model and viewing matrices, assuming you're in first person.

Just run the opponent's position through the model and viewing matrices, and you'll get his position in view space. Disregard the Z component and normalize 2D vector made from the X and Y components, and presto, you've got a vector on the screen that points to your object. Note that this is already the coordinate of your arrow on-screen. If you also need the angle, it's atan2(y, x).

\$\endgroup\$

You must log in to answer this question.

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