Game Development Community

Finding the angle between the player and an object

by Neil Marshall · in Torque Game Engine · 09/07/2003 (8:50 am) · 14 replies

Is there any easy way to find the angle between an object in the world and the direction that the player is looking?

So if the object is to the right of the player, the formula will say... the object is 13 degrees to the right.

The info that I have is the objects location, the players location and rotation.

I think I can brute force this by making triangles and subtracting angles, but there has got to be a better way.

#1
09/07/2003 (9:37 am)
Players position = p1
Object position = p2
Players direction = v1

( p2 - p1 ) dot v1

Should do it.
I just woke up and am hung over, I blame that if it's wrong.
#2
09/09/2003 (7:10 pm)
What kind of rotation variable is v1 supposed to supply? Just the default rotation vector in torque, radians, or degrees?

Below is how I have it currently implemented and it seems to be giving me numbers that I don't know how to use. They are +/-800 or something.

I'm sure I'm doing something wrong, I just don't know what. :)

//( p2 - p1 ) dot v1

				deltaPos.x = mCheckpointPosition.x - cameraPos.x; 
                deltaPos.y = mCheckpointPosition.y - cameraPos.y; 
                deltaPos.z = mCheckpointPosition.z - cameraPos.z; 
   
                finalRot.x = deltaPos.x * cameraRot.x; 
                finalRot.y = deltaPos.y * cameraRot.y; 
                finalRot.z = deltaPos.z * cameraRot.z; 
				Con::printf(":: Rotate %f %f %f", finalRot.x, finalRot.y, finalRot.z);
#3
09/10/2003 (5:48 pm)
No no...dot is dot produtct not multiply.

v1 is a vector, normalize the players velocity for the direction he is facing.
#4
08/19/2005 (1:08 pm)
I'm trying to use this to get one player move towards another I'm not sure if it well help It doesn't even work because there is no such thing as Getyposition you also need to defing %target and %source before hand.
%TY = %target.getyposition;
%SY = %source.getyposition;
%TX = %target.getxposition;
%SX = %source.getxposition;
%TZ = %target.getzposition;
%SZ = %source.getzposition;
%PY = %SY - %TY;
%PX = %SX - %TX;
%PZ = %SZ - %TZ;
%target.player.setVelocity("%TX %TY %TZ");
#5
01/01/2006 (1:42 pm)
Angle = arccos(v1v2 / |v1||v2|) This is the formula to find the angle between two vectors. In order to find out which side say a person is compare to your eye or muzzle vector which I believe are the same then you need to use this formula: rotation = v1xv2, If the number is positive then it is on once side, and if it is negative the other. I can not remember off hand which is which but a simple print and some experimentation will figure it out. Also note that just using this logic may not fix the problem. It will give you the angle between the vectors not the angle between them horizontally. To do this all you need to do is use the first formula but flatten the vertical values, which is simply setting them to 0. I will also include some sample code from script that I used in something similar.

// Find the rotation of the two vectors, used for which half
//of the screen the player is on,
%crossProduct = VectorCross(%muzzleFlatVector, %positionFlatVector);
%rotation = GetWord(%crossProduct, 2);
*this rotation will give a vector and unless the vectors have no z value then you will need a different
way to tell which side of the screen an object may be on

//Angle between the two vectors
//angle = arccos(v1v2 / |v1||v2|)
%posX = GetWord(%posVec, 0);
%muzX = GetWord(%muzVec, 0);
%posY = GetWord(%posVec, 1);
%muzY = GetWord(%muzVec, 1);

%muzzleFlatVector = %muzX SPC %muzY SPC "0";
%positionFlatVector = %posX SPC %posY SPC "0";

%muzzleVectorLength = VectorLen(%muzzleFlatVector);
%positionVectorLength = VectorLen(%positionFlatVector);

%dotProduct = VectorDot(%muzzleFlatVector, %positionFlatVector);

%radians = mAcos(%dotProduct / %lengthMultiplied);
%angle = mRadToDeg(%radians);
#6
02/01/2009 (7:09 pm)
Then how to rotate the player to that angle?
I'm also trying to do this but the player always rotate to somewhere else rather than the correct target direction. :(
#7
03/13/2009 (1:13 pm)
Can someone shine light on this?

i need a function to tell the player how far he has to turn to look at a object.

I just need it for x and y but not z.

Something like:

function getTurnDist(%me, %obj)

Then have it return to turn right(+) or left(-) a certain number of degrees.

Thanks,
Skylar.
#9
03/14/2009 (6:32 pm)
Working code may also help :-)

function getVectorAngle(%vec1, %vec2)
{
  %vec1n = VectorNormalize(%vec1);
  %vec2n = VectorNormalize(%vec2);

  %vdot = VectorDot(%vec1n, %vec2n);
  %angle = mACos(%vdot);

  // convert to degrees and return
  %degangle = mRadToDeg(%angle);
  return %degangle;
}

To get the angle from the player's eye direction to the object:

%angle = getVectorAngle([player id].getEyeVector(),VectorSub([object].getPosition(),[player id].getPosition()));

Hope this helped!

This basically gets the angle difference of the player's eye direction and the direction from the player to the object.
#10
03/14/2009 (6:55 pm)
Good post Bryce. I believe there's a whole load of similar basic code on angle and target finding in the Killer Kork resource.
#11
03/14/2009 (7:19 pm)
This is the type of collaboration that is fun to see. Code examples, great explanations of how and whys. Even if the question is not immediately pertanit, one can still gleam something from reading the thread.
#12
03/14/2009 (7:49 pm)
@Steve: My example was taken from Killer Kork, actually! The math functions in that code are incredibly useful, I recommend it to anyone.
#13
03/16/2009 (10:32 am)
the code snippet above is good for some things,
but note that it will not distinguish between a player to the left and a player to the right. ie, it returns the size of the angle between vec1 and vec2, but not the direction of the angle.

for example, consider these vectors:
A = [ 0, 1] (straight up )
B = [ 1, 0] (straight right)
C = [-1, 0] (straight left )

A DOT B = 0, so acos() = 90 degrees.
A DOT C = 0, so acos() = 90 degrees.

to account for this, what i typically do is create a vector perpendicular to the second vector, DOT that with the first vector, and flip the sign of the angle depending on the sign of that second DOT.
note that this is easy with two dimensions, but gets a little tricky in three, but i think this thread is mainly interested in the 2D case.

so i would modify the code to something like:

function get2DVectorAngle(%vec1, %vec2)
{
  %vec1n     = VectorNormalize(%vec1);
  %vec2n     = VectorNormalize(%vec2);
  %vec3Perp  = getWord(%vec2, 1) SPC (-1 * getWord(%vec2, 0));     // x gets y, y gets -x.

  %vdot      = VectorDot(%vec1n, %vec2n);
  %angle     = mACos(%vdot);
  
  %pdot      = VectorDot(%vec1n, %vec2Perp);
  if (%pdot < 0)
  {
     %angle *= -1;
  }

  // convert to degrees and return
  %degangle = mRadToDeg(%angle);
  return %degangle;
}

to do this in three dimensions you would need to introduce an "up" vector, and rotate vec2 around that. the code above is equivelant to assuming the "up" vector is [0, 0, 1].
#14
05/01/2010 (9:46 pm)
For anyone who finds this in the future, the above post's code has a typo, %vec2Perp should read %vec3Perp. :)