Author Topic: Keeping track of character direction  (Read 2928 times)

Offline stownshend

  • byte
  • *
  • Posts: 25
    • View Profile
Keeping track of character direction
« on: September 08, 2011, 02:18:07 am »
I have a character in my game who sits in the middle of a 5x5 grid of tiles. Aesthetically she has a front (where she is looking).

When I click on one of the tiles, I want my character to look at the centre of that tile.

I've currently spent 6 hours or more trying to work this out but I'm failing miserably. I will describe my approach below, but if there is an easier way or a way JPCT-AE can assist me in doing this, that would be great.

My approach:

My character is called the Queen. I've set up a property which is a SimpleVector which represents the direction the Queen is looking. At first she is looking away from the camera so this Vector is set to (0,0,1).

Code: [Select]
private SimpleVector queenDirection;

And the initialization of the initial direction:

Code: [Select]
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
// The Queen is originally facing to 0 degrees.
queenDirection = new SimpleVector(0f,0f,1f);
...

My algorithm is:

- Calculate a vector from the Queen's current position (0,0,0 for now in world space) to the centre of the tile selected. I use the formula vector = destinationX-currentX, destinationY-currentY, destinationZ-currentZ

Code: [Select]
SimpleVector eyeline = new SimpleVector(
destinationX - queen.getTransformedCenter().x,
0,
destinationZ - queen.getTransformedCenter().z).normalize();

- Then I calculate the angle (in radians) between the Queen's current viewing direction, and this new vector using the formula angle = acos((v1 DOT v2) / (v1.length * v2.length)):

Code: [Select]
float dotProduct = queenDirection.calcDot(eyeline);

Double temp = (double)  dotProduct / ( queenDirection.length() * eyeline.length());

double angle = Math.acos(temp)

... but already I run into problems because (perhaps due to the accuracy of float/double or something else) the dotProduct and therefore "temp" variable which is passed into the arc cosine function is sometimes either slightly higher than 1 (1.00000123) or it's negative - either way the acos function returns NaN because it only accepts parameters between 0 and 1.

The code which actually does the rotation is:

Code: [Select]
if ( angle > 0.5 )
{
queen.rotateY((float) angle);

queenDirection.x = eyeline.x;
queenDirection.z = eyeline.z;
}

I'm not great at mathematics, but I'll get stuck into if it I have to. My primary question is whether there is an easier way? If not, I'll keep working at this but I wanted to check before I spend another 6 hours at it.

This game is going to have a lot of models who need to turn and face each other often, so I need to have this down before I move on.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Keeping track of character direction
« Reply #1 on: September 08, 2011, 07:55:38 am »
You might want to check out the getRotationMatrix()-method in SimpleVector. Try to feed the direction vector you create into it and use the result as the new rotation matrix for your object.

Offline Alexey

  • int
  • **
  • Posts: 50
    • View Profile
Re: Keeping track of character direction
« Reply #2 on: September 08, 2011, 09:23:44 am »
Hello all! Egon, could you add a method lookAt(SimpleVector) to Object3D, like Camera has?

Offline stownshend

  • byte
  • *
  • Posts: 25
    • View Profile
Re: Keeping track of character direction
« Reply #3 on: September 09, 2011, 06:31:43 am »
Hi Egon,

Thank you very much for the suggestion!

It took a little bit of fiddling but the code and algorithm is ridiculously simple compared to what I was trying to achieve before. It works like a charm, she is facing whatever tile I click without any hassle.

My problem was that I thought you had to do an Object3D.rotateMesh() after setting up a rotation matrix in order to make it do the rotation but it wasn't required. My code:

Code: [Select]
SimpleVector queenDesiredEyeline = new SimpleVector(
destinationX - antQueen.getTransformedCenter().x,
0,
destinationZ - antQueen.getTransformedCenter().z).normalize();

Matrix queenRotationMatrix = new Matrix(queenDesiredEyeline.getRotationMatrix());

Log.d("queenDesiredEyeline",queenRotationMatrix.toString());

antQueen.setRotationMatrix(queenRotationMatrix);