Please help with direction code
by Katrina Rose · in Torque Game Engine · 10/18/2004 (10:28 am) · 31 replies
Hi,
I am trying to make an arrow that points to the next waypoint. I am having trouble figuring out how to get the direction from your Y (forward) to the waypoint, and then translating that into an arrow gui. I have a gui with 8 arrows 1 being straight ahead and then 2-8 rotating clockwise back to arrow 1. I can get the distance from the player to the waypoint, but I can't figure out how to get the angle between to and the waypoint. I have played with vectorSub and VectorAdd to no avail. Someone please help. Thanks in advance.
Marrion Cox
I am trying to make an arrow that points to the next waypoint. I am having trouble figuring out how to get the direction from your Y (forward) to the waypoint, and then translating that into an arrow gui. I have a gui with 8 arrows 1 being straight ahead and then 2-8 rotating clockwise back to arrow 1. I can get the distance from the player to the waypoint, but I can't figure out how to get the angle between to and the waypoint. I have played with vectorSub and VectorAdd to no avail. Someone please help. Thanks in advance.
Marrion Cox
About the author
#2
Marrion
10/18/2004 (10:54 am)
Thanks for looking Owen. Both. I need the angle and a way to translate it to the GUI Correctly.Marrion
#3
10/18/2004 (11:08 am)
@KATRINA ROSE: Have you looked at the compass GUI resource? I think that could be modified to do what you're describing with just a bit of coding.
#4
Given 2 vectors, A and B and theta (the angle between them) the dot product is given as
A dot B = |A||B| cos theta
solving for theta you get
theta = arccos( (A dot B) / (|A||B|) )
if A and B are unit length vectors then their magnitudes are 1 and so the magnitudes can be disregarded giving
theta = arccos( A dot B )
In torquescript you would use mAcos( VectorDot( %A, %B );
As far as translating into screen space I'll have to think on it a bit since I always screw it up
10/18/2004 (11:11 am)
My math is a bit rusty but here it goes. As far as the angle, you can find this by using the dot product formula.Given 2 vectors, A and B and theta (the angle between them) the dot product is given as
A dot B = |A||B| cos theta
solving for theta you get
theta = arccos( (A dot B) / (|A||B|) )
if A and B are unit length vectors then their magnitudes are 1 and so the magnitudes can be disregarded giving
theta = arccos( A dot B )
In torquescript you would use mAcos( VectorDot( %A, %B );
As far as translating into screen space I'll have to think on it a bit since I always screw it up
#5
10/18/2004 (11:17 am)
%A and %B are getPosition or getTransform?
#6
10/18/2004 (11:23 am)
One would be the player's forward vector and the other would be the vector formed by doing a vector subtraction of the position of the object from the player's position.
#7
4
3 3
2 2
1 1
0 0
-1 -1
-2 -2
-3 -3
-4
I need the whole 360 degrees. There is no way I can find out if it's in the top left or top right with these numbers. here is my code:
Thanks for your help
10/18/2004 (11:42 am)
Ok. That gives me the following:4
3 3
2 2
1 1
0 0
-1 -1
-2 -2
-3 -3
-4
I need the whole 360 degrees. There is no way I can find out if it's in the top left or top right with these numbers. here is my code:
function pointToPos(%playerForward, %playerPos, %objPos)
{
%vec = VectorSub(%objPos,%playerPos);
return VectorDot(%playerForward,%vec);
}Thanks for your help
#8
I have done this a couple different ways, and the code is almost identical for C++ and Torquescript.
This returns the angle in Radians (0 to 2PI) . If you plugged this angle directly into the Z Rotation, your player would snap, looking directly at the target. In script, its a little more cumbersome to make the player face the target because it uses Quaternions.
Like I said before, the angle is in Radians. This angle isn't local to the player, it is World-based. So it is pretty easy to translate to arrows...
%northOrUp = 0; // zero or 2Pi
%SouthOrDown = 3.141592; //Pi/2 OR 180 DEGREES
%EastOrRight = 1.570796; // Pi OR 90 Degrees
%WestOrLeft = 4.712388; // Pi * (3/2) OR 270 DEGREES
It depends which direction you want to be North/Up. Since the player really doesn't have any indication which way true North is in a game, you can make any angle North. From this, you should be able to find the other 4 angles.
*Disclaimer: I haven't slept in 38 hours, so I may have the Radians wound the wrong direction. If so, just swap East and West.
10/18/2004 (11:43 am)
You actually need the Z axis value to determine your heading (rotations).I have done this a couple different ways, and the code is almost identical for C++ and Torquescript.
I dumped this code example and replaced it with a better example below
This returns the angle in Radians (0 to 2PI) . If you plugged this angle directly into the Z Rotation, your player would snap, looking directly at the target. In script, its a little more cumbersome to make the player face the target because it uses Quaternions.
I dumped this code example and replaced it with a better example below
Like I said before, the angle is in Radians. This angle isn't local to the player, it is World-based. So it is pretty easy to translate to arrows...
%northOrUp = 0; // zero or 2Pi
%SouthOrDown = 3.141592; //Pi/2 OR 180 DEGREES
%EastOrRight = 1.570796; // Pi OR 90 Degrees
%WestOrLeft = 4.712388; // Pi * (3/2) OR 270 DEGREES
It depends which direction you want to be North/Up. Since the player really doesn't have any indication which way true North is in a game, you can make any angle North. From this, you should be able to find the other 4 angles.
*Disclaimer: I haven't slept in 38 hours, so I may have the Radians wound the wrong direction. If so, just swap East and West.
#9
10/18/2004 (11:53 am)
I assumed the arrows would be pointing like a compass, which is probably wrong, now that I think about it. If you need to figure out the angle to the target in relation to the player, then you have to do a few more funky things.
#10
I needed the same thing, if I remember my code then it is what is below. I will double check when I get home. BTW, this ignores any height as I wanted to know general direction, not if heigher or lower than me.
10/18/2004 (11:53 am)
KatrinaI needed the same thing, if I remember my code then it is what is below. I will double check when I get home. BTW, this ignores any height as I wanted to know general direction, not if heigher or lower than me.
// return angle to targetPos from playerPos in radians
function getAngle( %playerPos, %targetPos )
{
%dir = VectorSub( %targetPos, %playerPos );
return mAtan( GetWord(%dir,2), GetWord(%dir,0) );
}
#11
This will destroy the current X and Y Rotations and set them back to Zero. I had to do this in order to eliminate errors in looking at the target. This is probably tolerable, unless the player is a vehicle (flying or terrain vehicle) that depends on Pitch and Roll rotations.
10/18/2004 (12:01 pm)
I should point out that in my code above:%myCurrentTransform = setWord(%myCurrentTransform, 3, "0"); %myCurrentTransform = setWord(%myCurrentTransform, 4, "0");
This will destroy the current X and Y Rotations and set them back to Zero. I had to do this in order to eliminate errors in looking at the target. This is probably tolerable, unless the player is a vehicle (flying or terrain vehicle) that depends on Pitch and Roll rotations.
#12
@Randall I like funky things. Anything that will get this working. Thanks for your help.
@Simon Your code does not take into account the players angle, and When I rotate my player the angle does not change. I need a arrow that points to the waypoint no matter what direction you are facing.
@Owen your code works, but I can't use it to make a needle point in a 360 degree arc because it will only tell me is the waypoint is in front or behind, and not the sides.
Thanks for your help so far.
10/18/2004 (12:05 pm)
Hi,@Randall I like funky things. Anything that will get this working. Thanks for your help.
@Simon Your code does not take into account the players angle, and When I rotate my player the angle does not change. I need a arrow that points to the waypoint no matter what direction you are facing.
@Owen your code works, but I can't use it to make a needle point in a 360 degree arc because it will only tell me is the waypoint is in front or behind, and not the sides.
Thanks for your help so far.
#13
10/18/2004 (12:07 pm)
Randall when I rotate my player the numbers don't change. The z Axis remains the same. Thanks for your help though.
#14
I know this code works (assuming I didn't copy/paste the wrong sections and leave out a step), because I can click on the world and the player will turn in that direction (third person).
My interest in this thread is that I hope someone can help me figure out how to make the player turn instead of snapping to the angle. calling turnLeft(1) will turn the player left, but he keeps spinning until I call turnLeft(0). Is there a simpler method, and way to make him stop turning when he is facing the target? Remember, I HAVE the angle or amount I need to turn and can make him snap to that angle. I want him to turn slowly and naturally.
I just started learning TorqueScript about a week ago, so I don't know all the in-outs yet. For instance, I don't even know if there is a Global value for Pi (there is a global in C++, but I can't seem to find the one exposed to Script)
10/18/2004 (12:21 pm)
Sooooo tired. I forgot that mAtan returns -pi to +pi. This should make the angle positive and take into account the players current heading.I dumped this code example and replaced it with a better example below
I know this code works (assuming I didn't copy/paste the wrong sections and leave out a step), because I can click on the world and the player will turn in that direction (third person).
My interest in this thread is that I hope someone can help me figure out how to make the player turn instead of snapping to the angle. calling turnLeft(1) will turn the player left, but he keeps spinning until I call turnLeft(0). Is there a simpler method, and way to make him stop turning when he is facing the target? Remember, I HAVE the angle or amount I need to turn and can make him snap to that angle. I want him to turn slowly and naturally.
I just started learning TorqueScript about a week ago, so I don't know all the in-outs yet. For instance, I don't even know if there is a Global value for Pi (there is a global in C++, but I can't seem to find the one exposed to Script)
#15
$Player = %player;
also, how exactly are you retrieving the Z axis rotation? Since Transform uses Quaternions, you have to retrieve the SEVENTH value:
%currentAngle = getWord(%myCurrentTransform,6);
Regardless which axis you change, the value of %currentAngle should reflect some change. I'm not quit fluent in TorqueScript, so I am not sure if there is another method to set/get the Z axis rotation.
10/18/2004 (12:27 pm)
Katrina, I know the code works I am using it right now. I don't think the $Player global is available by default, so you probably have to create it when the player is spawned in ./mymodname/server/game.cs search for the createPlayer function. Just after MissionCleanup.add(%player); add this:$Player = %player;
also, how exactly are you retrieving the Z axis rotation? Since Transform uses Quaternions, you have to retrieve the SEVENTH value:
%currentAngle = getWord(%myCurrentTransform,6);
Regardless which axis you change, the value of %currentAngle should reflect some change. I'm not quit fluent in TorqueScript, so I am not sure if there is another method to set/get the Z axis rotation.
#16
What do I have wrong?
Thanks for your help.
10/18/2004 (12:34 pm)
This is what I have now, but it still does not change when my player rotates around.function pointToPos(%playerForward, %playerPos, %objPos)
{
//%vec = VectorSub(%objPos,%playerPos);
//return VectorDot(%playerForward,VectorNormalize(%vec));
//GET THE DISTANCE FROM THE TARGET
%distFromTarget = VectorSub(%playerPos, %objPos);
%distFromTarget = VectorNormalize(%distFromTarget);
//GET THE X VALUE
%xValue = getWord(%distFromTarget,0);
//GET THE Y VALUE
%yValue = getWord(%distFromTarget,1);
//USE X AND Y VALUE TO GET Z ANGLE
%myAngle = mAtan(%xValue,%yValue);
//MAKE IT BETWEEN 0 AND 2PI
if (%myAngle != 0)
{
%myAngle += 3.141592;
while(%myAngle > 6.283185)
{
%myAngle -= 6.283185;
}
}
//DETERMINE THE OFFSET BETWEEN CURRENT ANGLE AND TARGET ANGLE
%currentAngle = getWord(%playerPos,6);
%angleDiff = %myAngle - %currentAngle;
//AGAIN, MAKE IT BETWEEN 0 AND 2PI
while(%angleDiff < 0)
{
%angleDiff += 6.283185;
}
while(%angleDiff > 6.283185)
{
%angleDiff -= 6.283185;
}
//ADJUST THE OFFSET TO TAKE THE SHORT WAY AROUND IN RADIANS
if(%angleDiff > 3.141592)
%angleDiff -= 6.283185;
return %angleDiff;
}What do I have wrong?
Thanks for your help.
#17
I don't know where you are deriving the waypoint or target position... so first you need put this code just after you retrieve that position. I called the target position %pos and remember that this assumes that %pos is a valid position:
Just for a quick run through, the code above will also spawn New Player at %pos (as a marker) and force your avatar/player to look at it. The first line calls this function (just paste this within the same CS file):
This function returns not only the angle needed to face the target, it also returns the direction (left or right) the player needs to turn so the value *might* be negative. Once we verify all this works, we can work on making the angle useful for the arrows. The code above *should* work since I copy/pasted directly from my own file (I've said that before, haven't I?)
Again, we make a few assumptions before plugging in this code:
$Player is a global var containing the player (%player)
%pos is a valid world position in the form of "100 30 200"
10/18/2004 (1:29 pm)
Lets try this again. I created a bunch of "sure fire" things just to be sure its all working properly (yeah, rite :) )I don't know where you are deriving the waypoint or target position... so first you need put this code just after you retrieve that position. I called the target position %pos and remember that this assumes that %pos is a valid position:
//CALL FUNCTION TO GET THE LOCAL ANGLE TO TARGET
%myAngle = playerToTargetAngle(%pos);
//GET THE CURRENT TRANSFORM OF THE PLAYER
%myCurrentTransform = $Player.GetTransform();
//JUST TO VERIFY THIS IS WORKING
//THIS WILL MAKE THE PLAYER FACE THE TARGET
//ADD THIS TO OUR CURRENT HEADING
%myAngle += getWord(%myCurrentTransform, 6);
//KEEP IT BETWEEN 0 AND 2PI
while(%myAngle < 0)
%myAngle += 6.283185;
while(%myAngle > 6.283185)
%myAngle -= 6.283185;
//SET THE NEW ANGLE TO FACE THE TARGET
%myCurrentTransform = setWord(%myCurrentTransform, 6, %myAngle);
%myCurrentTransform = setWord(%myCurrentTransform, 3, "0");
%myCurrentTransform = setWord(%myCurrentTransform, 4, "0");
%myCurrentTransform = setWord(%myCurrentTransform, 5, "1");
$Player.SetTransform(%myCurrentTransform);
//JUST TO BE EXTRA SURE, SPAWN ANOTHER PLAYER AT THE TARGET %pos
%bot = new Player() {
dataBlock = PlayerShape;
client = %this;
position = %pos;
};
MissionCleanup.add(%bot);Just for a quick run through, the code above will also spawn New Player at %pos (as a marker) and force your avatar/player to look at it. The first line calls this function (just paste this within the same CS file):
function playerToTargetAngle(%pos)
{
//RETURNS THE ANGLE TO TARGET
//TAKING THE PLAYERS CURRENT HEADING INTO CONSIDERATION
//GET THE CURRENT TRANSFORM OF THE PLAYER
%myCurrentTransform = $Player.GetTransform();
//GET THE ANGLE TOWARD THE TARGET
%distFromTarget = VectorSub(%myCurrentTransform, %pos);
%distFromTarget = VectorNormalize(%distFromTarget);
%xValue = getWord(%distFromTarget,0);
%yValue = getWord(%distFromTarget,1);
%myAngle = mAtan(%xValue,%yValue);
//KEEP IT BETWEEN 0 AND 2PI
if (%myAngle != 0)
{
%myAngle += 3.141592;
while(%myAngle > 6.283185)
%myAngle -= 6.283185;
}
//DETERMINE THE OFFSET BETWEEN CURRENT ANGLE AND TARGET ANGLE
%currentAngle = getWord(%myCurrentTransform,6);
%angleDiff = %myAngle - %currentAngle;
//KEEP IT BETWEEN 0 AND 2PI
while(%angleDiff < 0)
%angleDiff += 6.283185;
while(%angleDiff > 6.283185)
%angleDiff -= 6.283185;
//ADJUST THE OFFSET TO TAKE THE SHORT WAY AROUND IN RADIANS
if(%angleDiff > 3.141592)
%angleDiff -= 6.283185;
//RETURN THE ANGLE AND DIRECTION WE NEED TO TURN
return %angleDiff;
}This function returns not only the angle needed to face the target, it also returns the direction (left or right) the player needs to turn so the value *might* be negative. Once we verify all this works, we can work on making the angle useful for the arrows. The code above *should* work since I copy/pasted directly from my own file (I've said that before, haven't I?)
Again, we make a few assumptions before plugging in this code:
$Player is a global var containing the player (%player)
%pos is a valid world position in the form of "100 30 200"
#18
10/18/2004 (1:38 pm)
Oh, Katrina, the function you created simply returns a value. It doesn't set the players heading/rotation/transform. So you won't see a change in the rotation until you specifically set the transform.
#19
10/18/2004 (1:41 pm)
I just need the angle so I can use it for the directional arrow. I Don't need to spawn something. I am trying the code right now.
#20
Can't believe I had to edit this for clarity.
10/18/2004 (1:49 pm)
I know you don't need to spawn anything, but oftentimes you need to do such things to be sure your code is indeed doing what you expect. Wherever that other player spawns, is where %pos (or your waypoint) *supposedly* is. If that other player spawns somewhere else unexpectedly, then %pos isn't defined properly.Can't believe I had to edit this for clarity.
Torque Owner Owen Ortmayer