Game Development Community

Solid angle calculation

by Luis Anton · in Torque Game Engine · 03/31/2005 (7:56 am) · 11 replies

Ok, it's enough... I've been some hours trying to do something I though was easy, knowing some maths, but I think I'm missing something.

I need to rotate the player towards some point. I just need a rotation on the z axis. Say we have x,y for the player, and tx, ty for the target object, I've tried with tangents, cosines and dot products, but I never get the proper angle, or it won't work in some quadrants.

For example:

angle = 180 * ( aCos((tx-x) / length(tx-x, ty-y) ) / 3.141592;
if (ty-y) < 0
angle = angle + 180;

No way, but I think that's right!

There must be a solid way to find the right angle from a player to a point, so I can use it like

$player.setTransform($player.getPosition() SPC "0 0 1" SPC %angle);

and get the player facing the proper direction.

Help please :)

#1
03/31/2005 (10:46 am)
Angle = atan(tx-x, ty-y)

Might be the other way around (x-ty), but Atan is what you want.
#2
03/31/2005 (11:21 am)
I'm sorry, but atan(tx-x,ty-y) is not a solution. Shoudln't it deal with quadrants? atan returns values from -PI to PI, or 0 to PI/2 if it's atan2. Using just atan like that won't work.

I'm trying again with the dot product...
#3
03/31/2005 (11:40 am)
I'm sorry, but atan(tx-x,ty-y) is not a solution. Shoudln't it deal with quadrants? atan returns values from -PI to PI, or 0 to PI/2 if it's atan2. Using just atan like that won't work.

I'm trying again with the dot product...
#4
03/31/2005 (11:45 am)
Another solution I've found is this one. It still needs some adjustements, because it does not always seem to work properly.

%bpos = VectorNormalize(%bot.getPosition());
   %x2 = getWord(%bpos, 0);
   %y2 = getWord(%bpos, 1);

   %ppos = VectorNormalize($player.getPosition());
   %x1 = getWord(%ppos, 0);
   %y1 = getWord(%ppos, 1);
   
   %ang = 0;
   %v1 = %x1 SPC %y1;   // player
   %v2 = %x2 SPC %y2;   // bot

   %d = %x1*%x2 + %y1*%y2;  // dot product
   %ang = mAcos(%d / (VectorLen(%v1)*VectorLen(%v2)));  //get the angle
   %ang = %ang * 180 / 3.141595;
   
   echo(%x2 - %x1);
   echo(%y2 - %y1);
   if ((%x2-%x1 < 0))      // quick fix. Shouldn't it be %y2-%y1?? 
      %ang = %ang + 180;
   
   $player.setTransform($player.getPosition() SPC "0 0 1" SPC %ang);

There seems to be some loss of precision when the player is too close to it's target. I'll try not normalizing positions. Anyway, it doesn't work properly...
#5
03/31/2005 (12:28 pm)
The function manoel gave you will work. Why not just try it instead of so much grief? It works because if you notice, it takes two arguments unlike the usual arctan function in math. It uses the sign of each of these two arguments to come up with the quadrant, so it spits out the correct angle.
#6
03/31/2005 (12:40 pm)
If your player is at px,py and the target is at tx, ty,
to find the angle from P to T:

dx = tx-px.
dy = ty-py.

tan(theta) = dy/dx

theta = atan(dy/dx).

you have to do some fooling around with the sign of dx & dy
to correct the sign of theta, but it's pretty simple.
atan2 may do that for you. (Actually i just checked,
and yes, it does do it for you).

Since i love writing this kind of stuff,
here's working javascript code to do it.
function oxe_DoAngleMath(px, py, tx, ty)
  {
  var dx;
  var dy;

  dx = tx - px;
  dy = ty - py;
  dy = -dy;  // to convert from screen-space to proper mathematical space.

  if (dx == 0)
    {
    theta = 0.0;
    }
  else
    {
    theta = Math.atan(dy/dx);
    theta = theta * 360 * 0.5 / 3.14159265359;

    if (dx < 0)
      {
      if (dy > 0)
        theta += 180.0;
      else
        theta -= 180.0;
      }
    }

  document.f1.i1.value = dx;
  document.f1.i2.value = dy;
  document.f1.i3.value = theta;
  }

implemented at www.elenzil.com/orion/esoterica/angle
#7
03/31/2005 (1:07 pm)
Luis,

Not to ignore all the responses, but your problem might be that you are converting the angle to degrees when setTransform uses radians. It was a hard conversion for me, but thinking in radians does become easier with time. Just remember that 360 degrees is 2PI or ~6.2832.

Try:

totalX = tx-x;
totalY = ty-y;
angle = mAtan(totalX, totalY);
if (totalX < 0) { angle += 3.141592; }

$player.setTransform($player.getPosition() SPC "0 0 1" SPC %angle);

Thanks
#8
04/01/2005 (12:24 am)
Agh, Derk, you were right. SetTransform uses radians. No problem thinking in radians or degrees, but the mission editor confused me, because in the 'rotation' field it uses degrees!!!

Finally, this is the code:
[code]
%dx = %tx - %px;
%dy = %ty - %py;

%theta = mAtan(%dx , %dy);
[\code]

Manoel was right, but anyway, the problem was the radian thing. There goes a whole afternoon :(

Thanks everyone.
#9
05/05/2006 (8:51 am)
I have been trying to do something almost the same all day long now, I want a angle from the PLAYER object to the STATIC in-game object on the level but the precision is completly off and 0 degrees always seem to start in a 45 degree area...

anyone else that has the same kind of problem with TGE 1.4?
#10
05/05/2006 (9:23 am)
Still, the general case of this problem isn't as simple as it seems when you actually get to using it. I found that out and wrote a resource with the code that resulted from the experience. Maybe it will prove useful in the long run.

www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=9480

My point being that the "gimbal lock"/axis swapping issues will come up when you try to rotate a shape to certain angles. The above resource takes this into account.
#11
05/05/2006 (10:07 am)
It's a general math issue, not a problem with TGE... I rememeber when I needed this data, I took the _vector_ between the two points and converted that into rotation coordinates. I just don't have the code, nor remember how to convert a vector to rotation anymore...