2
\$\begingroup\$

Given a sprite with an x and y coordinate, how would I move it toward another sprite with an x and y coordinate?

I've already made it face towards the other sprite, and I've made it move towards the other sprite, however because I'm using sin and cos it's circling the player and slowly moving in on them. Here's the method:

Enemy.prototype.update = function(playerX, playerY) {
    // Rotate us to face the player
    this.rotation = Math.atan2(this.y - playerY, this.x - playerX) - 2.35;

    // Move towards the player
    this.x += Math.sin(this.rotation) * this.speed;
    this.y -= Math.cos(this.rotation) * this.speed;
}

How can I get the sprite to just move towards the player in a straight line rather than a circle? I found a good example but it uses XNA Vector2's so it's not working with x and y positions directly.

\$\endgroup\$

2 Answers 2

6
\$\begingroup\$

I'm not particularly sure where that 2.35 value is coming from, which could be adding artifacts to your code, so I've removed it from my answers.

That being said, your basic intuition seems to be correct, however you have your sin and cos switched. Also, I'd wager that since you're already taking the difference between two (X,Y) coordinates, that you do not need to subtract the Y value since you're in the reference frame of the sprite itself. Finally, if you're trying to move towards the player, then your vector math is wrong. Given two vectors a and b, (a - b) is the vector in the direction from b to a and (b - a) is the vector in the direction from a to b.

Perhaps what you wanted was:

Enemy.prototype.update = function(playerX, playerY) {
    // Rotate us to face the player
    this.rotation = Math.atan2(playerY - this.y, playerX - this.x);

    // Move towards the player
    this.x += Math.cos(this.rotation) * this.speed;
    this.y += Math.sin(this.rotation) * this.speed;
}

A better way to encode this is to separate the rotation from the movement. If all you're doing is moving towards the player, then you shouldn't be worried about what way you're facing:

Enemy.prototype.update = function(playerX, playerY) {

    // Calculate direction towards player
    toPlayerX = playerX - this.x;
    toPlayerY = playerY - this.y;

    // Normalize
    toPlayerLength = Math.sqrt(toPlayerX * toPlayerX + toPlayerY * toPlayerY);
    toPlayerX = toPlayerX / toPlayerLength;
    toPlayerY = toPlayerY / toPlayerLength;

    // Move towards the player
    this.x += toPlayerX * this.speed;
    this.y += toPlayerY * this.speed;

    // Rotate us to face the player
    this.rotation = Math.atan2(toPlayerY, toPlayerX);
}
\$\endgroup\$
1
  • \$\begingroup\$ Worked perfect, thanks. The -2.35 is there because the sprite starts off a little off centre, and that's the radians needed to make it look centre. :) \$\endgroup\$ Commented Mar 13, 2013 at 20:41
3
\$\begingroup\$

I would solve this using simple algebra.

Given your sprite's position and the target location you should be able to find the slope of the line that would connect the two coordinates. This can be done using the following equation:

enter image description here

Essentially, the numerator (top number) is going to be velocity you apply on the Y axis and the denominator (bottom number) is going to be the velocity you apply to the X axis. These numbers already have a bit of a bias on speed though and could improperly influence how fast you end up moving. As a result, we want to normalize this into a single unit.

To normalize this into a unit vector you first must find the length (aka magnitude) of the vector using the equation sqrt((x * x) + (y * y))

Once you've found the length you can convert it to a unit vector by dividing the x and y values by the length.

Multiply this unit vector by your speed and you should be properly moving towards your target.

In code this would look something like:

var run = playerX - this.x;
var rise = playerY - this.y;
var length = sqrt((rise*rise) + (run*run)); //pseudocode
var unitX = run / length;
var unitY = rise / length;

this.x += unitX * this.speed;
this.y += unitY * this.speed;

You might need to do some fiddling with the sign or the order of the numbers depending on what direction is up, etc. but the concept should apply.

\$\endgroup\$
2
  • \$\begingroup\$ I was excited for this answer because I'm mathlexic and it was doing a great explanation until you dropped ax without any explanation of what it is. \$\endgroup\$
    – kevzettler
    Commented Nov 3, 2014 at 2:20
  • 1
    \$\begingroup\$ @kevzettler merely a typo - should have just been x. Thanks for pointing it out. Hopefully the rest is fairly clear yet. \$\endgroup\$ Commented Nov 3, 2014 at 13:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .