Racialz Racialz - 6 months ago 8
Javascript Question

How can I always move a ball at the same speed to an (x,y) position regardless of its starting position

This image illustrates my problem very well:
http://i.imgur.com/2NdRXGn.gifv

The ball moves very slow when it is close to its endpoint (orange circle) but moves very fast when it's farther away from its endpoint.

The reason this happens is because I'm using this code to calculate my vertical and horizontal velocities for the balls

var startingBallSpeed = 100;
xDistance = targetX - this.x;
yDistance = targetY - this.y;

this.horizontalVelocity = (xDistance / startingBallSpeed);
this.verticalVelocity = (yDistance / startingBallSpeed);


QUESTION: How can I make sure that the balls travel the same speed and will still hit the targetX and targetY



Current Behavior: Balls close to endpoint move slow, balls far from endpoint move fast

Desired Behavior: Balls move at the same speed regardless of how close they are to the endpoint

JS: https://jsfiddle.net/7ct1ap53/1

ball1 = new Ball(400, 480, "green");
ball2 = new Ball(20, 480, "blue");

targetX = 500;
targetY = 400;
targetBall = new Ball(targetX, targetY, "magenta", radius=10)

var gameArea = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 500;
this.canvas.height = 500;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[4]);
this.interval = setInterval(updateGame, 20); //20
}
};

function Ball(x, y, color, radius=15) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color

this.draw = function() {
gameArea.context.beginPath();
gameArea.context.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
gameArea.context.fillStyle = color;
gameArea.context.fill();
gameArea.context.closePath();
}

this.launch = function() {
var startingBallSpeed = 100;
xDistance = targetX - this.x;
yDistance = targetY - this.y;

this.horizontalVelocity = (xDistance / startingBallSpeed);
this.verticalVelocity = (yDistance / startingBallSpeed);
}

this.updatePos = function() {
this.x += this.horizontalVelocity;
this.y += this.verticalVelocity;
};
}


$(function() {
startGame();
});


function updateGame() {
gameArea.context.clearRect(0,0,500,500);
ball1.updatePos();
ball2.updatePos();

ball1.draw();
ball2.draw();
targetBall.draw();
}

function startGame() {

gameArea.start();
ball1.launch();
ball2.launch();
}

Answer

You need to normalize the vector defined by xDistance, yDistance to create a unit vector that specifies the direction but has a length of 1. Then you can multiply it by your desired ball speed to get the velocity.

Normalize by dividing by the length:

xDistance = targetX - this.x;
yDistance = targetY - this.y;
length = Math.sqrt((xDistance * xDistance) + (yDistance * yDistance));
if(length > 0) // avoid divide by zero
{
     xUnitVector = xDistance / length;
     yUnitVector = yDistance / length;

     this.horizontalVelocity = xUnitVector * startingBallSpeed;
     this.verticalVelocity = yUnitVector * startingBallSpeed;
}
else
{
     // cancel the launch because you are already at your destination
}

Adjust your ball speed to whatever constant speed you require