Problem making a character rotate towards a clicked point?

Started by
3 comments, last by MightyDog 15 years, 2 months ago
I am having trouble trying to make a game character rotate towards a point where the user clicks. The character rotates but it doesnt face the correct direction. What I did is to find the character's facing vector and to find the vector from the player's position to the clicked point. Then both of them are normalised and the dot product between these two vectors are taken. Then I apply arc cosine to the angle and set the z axis of the SetRotation method to the angle. (The z axis is the vertical axis) I have included the code snippet of the rotation calculation below. void Rotate(NiPoint3 targetPos) //NiPoint3 is a 3D vector type { NiPoint3 playerpos = character->GetTranslate(); //get the current position //The code below calculates the facing vector NiPoint3 kFacingDir; character->GetWorldRotate().GetCol(1, kFacingDir.y, kFacingDir.x,kFacingDir.z); kFacingDir.y += kFacingDir.x; kFacingDir.x = kFacingDir.y - kFacingDir.x; kFacingDir.y -= kFacingDir.x; kFacingDir.y *= -1.0f; kFacingDir.x *= -1.0f; kFacingDir.Unitize(); //Find the vector from the player to the clicked point NiPoint3 target(targetPos.x,targetPos.y); NiPoint3 current(playerpos.x,playerpos.y); NiPoint3 targetDir = target - current; targetDir.Unitize(); //Dot product and set the rotation double angle = NiACos(kFacingDir * targetDir); character->SetRotate(angle,0,0,1); //apply the rotation angle to the z axis //(the z axis is the vertical axis) } [\CODE] The method is run when the mouse is right clicked. The part where the facing vector is calculated is obtained from a code sample which can correctly rotate the character towards the clicked point. What that code does is to calculate the rotation matrix. What is the problem in the rotation angle calculated above and using it to perform the rotation?
Advertisement
Quote:Original post by Weng

kFacingDir.y += kFacingDir.x;
kFacingDir.x = kFacingDir.y - kFacingDir.x;
kFacingDir.y -= kFacingDir.x;

kFacingDir.y *= -1.0f;
kFacingDir.x *= -1.0f;
kFacingDir.Unitize();
[\CODE]


I assume this code suppose to calculate the perpendicular of the facing direction - 'cause that's what it looks like. The formula for perpendicular to a 2D vector is (-y,x) or (y,-x), depends of your axis system and the direction you want to rotate the vector. What you did here is (-y,-x) - and that's one of the reasons you fail. Delete either "kFacingDir.y *= -1.0f;" or "kFacingDir.x *= -1.0f;".


Your second problem is that cross product can be used to calculate the angle required to rotate from one vector to another - but it can't tell the direction. Since you need the direction, you have two options:
1) Use atan2. I'm assuming you are using C++, but many other languages also have that(or a similar) function. Use it to calculate the angle of targetDir, and subtract the angle of kFacingDir from it.
2) Use the formula (kFacingDir.x*targetDir.y-kFacingDir.y*targetDir.x). If it's positive, rotate one way. If it's negative, rotate the other way. If it's zero, than the angle is either 0 or 180 degrees, so it doesn't really matter which way you'll rotate...
-----------------------------------------Everyboddy need someboddy!
Quote:


character->GetWorldRotate().GetCol(1,kFacingDir.y,kFacingDir.x, kFacingDir.z);

kFacingDir.y += kFacingDir.x;
kFacingDir.x = kFacingDir.y - kFacingDir.x;
kFacingDir.y -= kFacingDir.x;

kFacingDir.y *= -1.0f;
kFacingDir.x *= -1.0f;
kFacingDir.Unitize();
[\CODE]


Thanks for the explanation :)

For the facing vector above, I'm still not sure how it works and am not sure if it is the actual facing vector or is it the perpendicular of the facing vector.

For the lines below,

kFacingDir.y += kFacingDir.x;
kFacingDir.x = kFacingDir.y - kFacingDir.x;
kFacingDir.y -= kFacingDir.x;

What do these calculations represent?

Also, why does the x and y components need to be multiplied by -1?

For the above calculations, the z axis is the vertical axis. (corresponding to the usual y axis ). The x and y axis correspond to the usual x and z axis respectively.


Quote:Original post by Weng123
For the lines below,

kFacingDir.y += kFacingDir.x;
kFacingDir.x = kFacingDir.y - kFacingDir.x;
kFacingDir.y -= kFacingDir.x;

What do these calculations represent?



Well, this is just a fancy way to swap between kFacingDir.x and kFacingDir.y. It's supposed to save some memory allocation because you don't need a temporary swap variable, but it's less readable and slower.

Anyways, I've just noticed that an much easier and efficient way to do this swap is to simply writing:

character->GetWorldRotate().GetCol(1, kFacingDir.x, kFacingDir.y,kFacingDir.z);
instead of
character->GetWorldRotate().GetCol(1, kFacingDir.y, kFacingDir.x,kFacingDir.z);

OK, this code makes less and less sense the more I read it. First they read a x value to y and a y value to x(I assume the GetCol function uses the xyz order), and than use some fancy code to swap?

OK, forget what I said about making it perpendicular - it is not needed here. The problem is only the lack of code to determine the direction of the rotation.

Quote:Original post by Weng123
Also, why does the x and y components need to be multiplied by -1?


That's just for turning the vector 180 degrees. The same effect could be achieved by changing the line
NiPoint3 targetDir = target - current;
to
NiPoint3 targetDir = current - target;
-----------------------------------------Everyboddy need someboddy!
Since you are using Gamebryo, check out the Metal Wars demo. They have code that basically accomplishes this. I modified it and put in head tracking for following the mouse pointer. I know this doesn't explain anything, but maybe you can get some insights looking at the sample code (they even have dampening included).

This topic is closed to new replies.

Advertisement