Game Development Community

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
Page «Previous 1 2
#1
10/18/2004 (10:50 am)
Does the problem lie in finding the angle between the player's facing and the waypoint. Or translating this into screen space correctly so the gui element draws correctly?
#2
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
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
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
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
10/18/2004 (11:53 am)
Katrina

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.

// 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
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
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
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
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
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
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
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.
Page «Previous 1 2