heading towards enemy

Started by
10 comments, last by Zakwayda 17 years, 11 months ago
Hi how can I get my enemy to follow the player? I have the enemy's position, enemy rotation and players's position. This code is from the enemies perspective (so the player is the enemy).

        dReal *myPos = getPosition();
        
        f32 z = (nextPos[2]-myPos[2]);
        f32 x = (nextPos[0]-myPos[0]);
        dReal bearingToEnemy = atan( z/x );
        
        // convert to radians
        dReal heading = (getRotation().Y) * 3.1415926535897932384626433832795 / 180.0;
        
        printf("%f, %f\n",heading,bearingToEnemy);
        
        if ( bearingToEnemy < heading)
        {
            goLeft();
        }
        else
        {
            goRight();
        }
        
        goForwards();


This doesn't seem to work... the enemy seems to swerve towards the player but then goes off in a straight line. I wondered if the problem is with my trigonometry or something to do with the angles when they go past 360 degrees and jump to zero again (or whatever the radian equivilant is) Cheers.
Advertisement
at a first glance i notice your if statement looks a bit sus...

since if the players bearing is less than the heading they go left, but if not they ALLWAYS go right, is that intentional? what about when bearing == heading?
Based on an "if" statement you are either going left or right, but then you're always going forward.

I suspect you need a third case for the "forward" indicating that bearing == heading.

Edit: Looks like winegums beat me to it. Good show, sir!

Cheers!
Jeromy Walsh
Sr. Tools & Engine Programmer | Software Engineer
Microsoft Windows Phone Team
Chronicles of Elyria (An In-development MMORPG)
GameDevelopedia.com - Blog & Tutorials
GDNet Mentoring: XNA Workshop | C# Workshop | C++ Workshop
"The question is not how far, the question is do you possess the constitution, the depth of faith, to go as far as is needed?" - Il Duche, Boondock Saints
if it's facing to the left of the target it should turn right, and vice versa.

(so it is intentional, at the moment any way)

If it goes past the target then it should turn back to the target. But it doesn't. I'm certain it has something to do with wrapping around of the angles. But there might also be problems with my trigonometry.
Quote:Original post by xDan
if it's facing to the left of the target it should turn right, and vice versa.


yeah but thats not what your code is doing.

if facing right of enemy
{
goLeft();
}
else (it may be facing the enemy, or facing left of it)
{
goRight();
}


i can see how it may sort itself out, but i still feel that it should only check its trajectory if its not facing the target directly. this may or may not fix your problem, but at the very least it will avoid future problems.
First the usual suggestion: use atan2() if it's available, rather than atan().

It sounds like what you want is the signed relative angle between the enemy's forward vector and the vector to the player, which can be found as follows:
vector2 diff = player.pos - enemy.pos;float relative_angle = atan2(perp_dot(player.forward, diff), dot(player.forward, diff));
If you're unsure about any of those terms, just ask.

Getting the actual angle could be useful in that you could have the enemy turn faster or slower depending on how far it needs to turn, or apply an ease-in-ease-out function. But for a simple binary result (is the player to the left, or to the right), all you need is the sign of perp_dot(player.forward, diff).
I'm not sure exactly what the perp_dot is... I googled it and have this code:

        dReal heading = (getRotation().Y + 90) * 3.1415926535897932384626433832795 / 180.0;                vector2df diff;        diff.X = nextPos[0] - myPos[0];        diff.Y = nextPos[2] - myPos[2];                vector2df player = vector2df(cos(heading), sin(heading));        float perp_dot = player.X*diff.Y - player.Y*diff.X;                float relative_angle = atan2(perp_dot, player.dotProduct(diff));                //printf("%f, %f\n",heading,bearingToEnemy);        printf("%f\n",relative_angle);                if ( relative_angle < 0 )        {            goLeft();        }        else        {            goRight();        }


It works all the while the player is in front of the enemy (edit: by "in front" I mean rotation of zero). Go about 90 degrees to the enemy and it will start spinning. When behind the enemy, it moves in the opposite direction to what it should to compensate.

The rotation is caused because the relative_angle is always negative. I disabled the moving forwards so I could test.

Without the +90 in "getRotation().Y + 90" it keeps spinning when you are in front, but stabilises around 90 degrees.
"perp_dot" is simply the so-called "2d cross product". Because a normal dot product between two lines gives you the cosine of an angle, rotating one of the lines 90 degrees gives you the cosine of (90 degrees minus the angle), which by the trig identities is the sine of the angle. Since the sign of the sine (pun intended) is positive for a small positive angle and negative for a small negative angle, it tells you whether the angle between the vectors is "positive" (i.e. you rotate counterclockwise, i.e. turn left, to get from the first to the second) or "negative". In fact, for small angles sin(x) is approximately equal to x (with x being in *radians* - in any event, it's approximately *proportional to* x with any measurement, as long as the angle is small), so you can use that to decide how hard to turn.

You might want to require a certain (probably very small) "threshold" deviance from being exactly aligned before the turning kicks in. Otherwise, depending on the frame rate and the "steering ratio", the enemy might appear to "wobble" slightly and rapidly while on a direct course (due to turning left and right on alternate frames).
Thanks for the info on 2d crossproducts. I will probaly add some threshold, but I can't even think of doing that until I get the above code working...
I am still crying to myself throughout the night over this problem. :-(
Can someone see what's wrong with my code?

I also tried this after reading through some more vector tutorials:
        dReal *myPos = getPosition();                // convert to radians        dReal heading = (getRotation().Y) * 3.1415926535897932384626433832795 / 180.0;                vector2df enemyVec = vector2df(nextPos[0] - myPos[0], nextPos[2] - myPos[2]);        vector2df playerVec = vector2df(cos(heading), sin(heading));                enemyVec.normalize();        playerVec.normalize();                f32 dot = enemyVec.X*playerVec.X + enemyVec.Y*playerVec.Y;                f32 relative_angle = acos(dot) - 3.142/2.0;                //float perp_dot = player.X*diff.Y - player.Y*diff.X;        //float relative_angle = atan2(perp_dot, player.dotProduct(diff));                printf("%f\n",relative_angle);                if ( relative_angle < 0 )        {            goLeft();        }        else        {            goRight();        }


But it still spins like a mad spinny thing at some angles :-(

This topic is closed to new replies.

Advertisement