What's Wrong With My Enemy Homing Code?


motorollin

Member
Joined
Jul 31, 2007
Messages
163
The following code should make the enemy home in on the player:

CODE
void Seeker::move(int index)
{
//Find the angle required to move towards the player
int distx = playerx-x;
int disty = playery-y;
int angle = atan2( disty, distx) * 57.29578;

//Set the velocities
dx = seekerspeed * cos(angle);
dy = seekerspeed * sin(angle);

//Move
x+=dx;
y+=dy;

//Set collision rect
col_l = x;
col_r = col_l + SEEKER_WIDTH;
col_t = y;
col_b = col_t + SEEKER_HEIGHT;
}


However, it has a very strange effect. The enemy moves towards the player a certain distance then stops and just wobbles. Also if the player moves away from the enemy, the player seems to reverse its direction!

Quicktime Video showing what happens
 
Parkydr said:
The "* 57.29578" shouldn't be there, atan2 returns the angle in radians and sin and cos use radians.
Yeah, that's got it! Cheers :D

(Still learning ;) )
 
Last edited by a moderator:
Hello,

Just a suggestion: instead of using atan2, cos and sin, you could just have:

dist=sqrt(distx*distx+disty*disty)
dx=speed*distx/dist
dy=speed*disty/dist

It's faster and arguably simpler. OK, your code is quite clear, but generally it's better to avoid useless trigonometric function, I think.
 
@hal9000
I was just starting to write functions to build arrays of pre-calculated atan/cos/sin when I saw your reply. Your method is much faster, simpler and easier. Thanks! It actually makes the enemies' paths more accurate too, whereas atan2() didn't give enough variance for the changes in angle to be really noticeable.

Cheers!
 
I'm not sure how your collision tests work already, but you might want to use a quadtree to partition the screen to cut down tests.

Basically you split the screen into quarters and, in your case, only check the quarter of the screen the player is in.
 
motorollin said:
whereas atan2() didn't give enough variance for the changes in angle to be really noticeable.
Duh, you where casting it to an int. As the result of atan2 is in radians, it will be between 0 and about 6.28, sticking that in an int, and then using that int for the cos/sin gives you only an accuracy of 7 different directions.

If you go for the sqrt way, and you are only using ints, then you might like this function for int based square roots. It should be a whole lot faster then sqrt() on the GP2x.
CODE

#define iter1(N) \
Try = root + (1 << (N)); \
if (n >= Try << (N)) \
{ n -= Try << (N); \
root |= 2 << (N); \
}

int INTsqrt(int n)
{
int root = 0, Try;
iter1 (15); iter1 (14); iter1 (13); iter1 (12);
iter1 (11); iter1 (10); iter1 ( 9); iter1 ( 8);
iter1 ( 7); iter1 ( 6); iter1 ( 5); iter1 ( 4);
iter1 ( 3); iter1 ( 2); iter1 ( 1); iter1 ( 0);
return root >> 1;
}
 
Last edited by a moderator:
Daid said:
If you go for the sqrt way, and you are only using ints, then you might like this function for int based square roots. It should be a whole lot faster then sqrt() on the GP2x.

Thanks! I added that function to my code and changed all my calls to sqrt() to INTsqrt() and everything still works. No noticeable speed increase yet, but I'm sure when more and more enemies appear on screen it will add up to a big saving of CPU time.

Thanks again
 
Last edited by a moderator:
hal9000 said:
Hello,

Just a suggestion: instead of using atan2, cos and sin, you could just have:

dist=sqrt(distx*distx+disty*disty)
dx=speed*distx/dist
dy=speed*disty/dist

It's faster and arguably simpler. OK, your code is quite clear, but generally it's better to avoid useless trigonometric function, I think.
and if a linear approach is to simple you could use x^4 instead! looks way more dynamic!
 
Last edited by a moderator:
Back
Top