Keeping track of character direction

Started by stownshend, September 08, 2011, 02:18:07 AM

Previous topic - Next topic

stownshend

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).


private SimpleVector queenDirection;


And the initialization of the initial direction:


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


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)):


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:


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.

EgonOlsen

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.

Alexey

Hello all! Egon, could you add a method lookAt(SimpleVector) to Object3D, like Camera has?

stownshend

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:

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);