views:

432

answers:

4

I'm creating a game in c++ and OpenGL and want an enemy to move towards the player.

What is the best method of making game objects move towards other game objects, that works in both 2D and 3D game environments?

UPDATE:

wow thanks everyone for the quick replies!

strangely enough I managed to get this to work just as I posted it

although for some reason i have to multiply the x values by more to get them to move as fast as the y direction.

anyone have any ideas why? or if what I'm doing is wrong/bad

float playerX = player.getXPos();
float playerY = player.getYPos();
float enemyX = XPos-*xscroll;
float enemyY = YPos-*yscroll;

glPushMatrix();

glTranslatef(enemyX, enemyY, 0.0);
glColor3f(1.0,0.0,0.0);
    glBegin(GL_POLYGON);
        glVertex2f(-40,40);
        glVertex2f(-40,-40);
        glVertex2f(40,-40);
        glVertex2f(40,40);
    glEnd();

glPopMatrix();


float xDistance = abs(playerX-enemyX);
float yDistance = abs(playerY-enemyY);

if((playerX - enemyX)*(playerX - enemyX)+(playerY - enemyY)*(playerY - enemyY) < 400*400){
    float heading = asin(xDistance/yDistance);

    if(playerY > enemyY){
        YPos += timeFactor*(200*(sin((90+heading)*(PI/180.0f))));
    }else{
        YPos += -(timeFactor*(200*(sin((90+heading)*(PI/180.0f)))));
    }

    if(playerX > enemyX){
        XPos += -(timeFactor*(10000*(cos((90+heading)*(PI/180.0f)))));
    }else{
        XPos += timeFactor*(10000*(cos((90+heading)*(PI/180.0f))));
    }
}
+4  A: 

Use vectors. This is dead simple and exactly how real games do this.

If your player is at position 10, 10 (Presume this is 2D space) and your enemy was at 20, 10. The vector from the player to the enemy is:

Player - Enemy

or

(10, 10) - (20, 10) = -10, 0

Normalising this vector gives you the unit vector, or direction. Which in this case is -1, 0. Multiple the unit vector (which is the direction remember) by a scalar value each frame and the enemy will move towards the player. What happens when it gets there is up to you ;)

Finglas
@Chris - the link I suggested while simple (no offence) is a nice introduction and will do the job you need, I hope.
Finglas
+16  A: 

Create a vector in the direction that you want the enemy to move. That's easy:

dir.x = player.x - enemy.x;
dir.y = player.y - enemy.y;

Now normalize this vector. That means divide the terms by the magnitude (the hypotenuse) of the vector.

hyp = sqrt(dir.x*dir.x + dir.y*dir.y);
dir.x /= hyp;
dir.y /= hyp;

Now you just need to add that vector to the enemy's position, multiplied by the speed you want the enemy to move:

enemy.x += dir.x*speed;
enemy.y += dir.y*speed;

Here's how it works - if you add that initial vector to the enemy's position it will instantly be transported to the player. You obviously want to enemy to move at a slower speed. When you normalize the vector, you make it's magnitude (essentially the hypotenuse of the triangle it forms) equal to 1. So now, adding the direction vector moves the enemy by one unit. Multiply that 1 unit by the enemy's speed, and now it's moving at the correct speed.

Edit: all of this extends to 3D as well. You just need a z-component.

Further edits to comment on your code:

You are doing a lot of extra work. You have enough information once you calculate the hypotenuse to move the enemy towards the player. You don't need to use any trig at all - see my code above. You are also calculating (sort of) the magnitude twice:

float hypotenuse = sqrt((xDistance * xDistance) + (yDistance * yDistance));
...
(playerX - enemyX)*(playerX - enemyX)+(playerY - enemyY)*(playerY - enemyY)

The second time it's the distance squared which is a nice optimization, but unnecessary here because you've already calculated the distance and the distance squared.

Here's what I would do:

float xDistance = playerX-enemyX;
float yDistance = playerY-enemyY;
float hypotenuse = sqrt((xDistance * xDistance) + (yDistance * yDistance));

if(hypotenuse < 400){

        YPos += timeFactor*200*(yDistance/hypotenuse);
        XPos += timeFactor*200*(xDistance/hypotenuse);
}

You'll notice that by removing the abs() I've also managed to remove the if(playerY > enemyY), etc parts.

Niki Yoshiuchi
In this example speed is expressed in terms of distance per frame, if your frame time is variable then your speed will be dependent on your frame rate which is bad. You should express your speed in terms of distance units (meters, feet, etc.) per second and scale it each frame based on how many milliseconds passed since the last frame.
Fraser Graham
my game creates a timefactor that all movement is multiplied by to get rid of framerate differences
Chris
Thank you! a much improved solution to mine, a lot simpler too thanks a lot
Chris
It only gets more exciting when the enemies are moving and you try to predict where the enemy will be when you get in range. :)
dash-tom-bang
+1  A: 

The player's position is point1. Enemy's position is point2. First you'll need to find the difference between the x1 and x2 and y1 and y2 (I'll call these xd and yd). Then you can get the angle between the two points by doing theta = atan(yd/xd). Now you should be able to get the new x and y (which I will call x3 and y3) by using the angle and the distance you want to travel where x3 = (d)(cos(theta)) and y3 = (d)(sin(theta)). Move the enemy to (x3, y3).

d is the speed the enemy is moving per update. You might have to mess with the signs to get the directions right (i.e. if the enemy moves in the correct x direction but wrong y direction then change the sign on y).

Hope this helps!

Peter
+1  A: 

This is where you need a "path finding algorithm". On a clear playfield, you could follow a straight line to the target. However, with obstacles in the way, you need to give it the AI to decide the best way around, or if it's even possible.

A search on codeproject.com will yield several articles on path finding.

spoulson
Will I agree, this question (and for what the user wants) is far too simple to bother with even simple path finding.
Finglas