Levi - 5 months ago 39

HTML Question

I am trying to move an object smoothly from point A to point B using HTML canvas and regular javascript.

Point A is a set of coordinates

Point B is in the case the cursor location.

I made a jsfiddle of what I have so far: https://jsfiddle.net/as9fhmw8/

`while(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)`

{

ctx.save();

ctx.beginPath();

ctx.translate(projectile.x, projectile.y);

ctx.arc(0,0,5,0,2*Math.PI);

ctx.fillStyle = "blue";

ctx.fill();

ctx.stroke();

ctx.restore();

if(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)

{

var stepsize = (projectile.mouseX - projectile.x) / (projectile.y - projectile.mouseY);

projectile.x += (stepsize + 1);

}

if(projectile.mouseY < projectile.y)

{

var stepsize = (projectile.y - projectile.mouseY) / (projectile.mouseX - projectile.x);

projectile.y -= (stepsize + 1);

}

}

Essentially what I can't figure out to do is to make the while loop slower (so that it appears animated in stead of just going through every iteration and showing the result).

I also can't figure out how to prevent the Arc from duplicating so that it creates a line that is permanent, instead of appearing to move from point a to point b.

Answer

Smooth animation here is really about determining how far to move your object for each iteration of the loop.

There is a little math involved here, but it's not too bad.

Velocity in your case is just the speed at which your particles travel in any given direction over a period of time. If you want your particle to travel `200px`

over the course of 4 seconds, then the velocity would be `50px / second`

.

With this information, you can easily determine how many pixels to move (animate) a particle given some arbitrary length of time.

`pixels = pixelsPerSecond * seconds`

This is great to know *how many* pixels to move, but doesn't translate into individual X and Y coordinates. That's where vectors come in.

A vector in mathematics is a measurement of both direction and magnitude. For our purposes, it's like combining our *velocity* with an angle (47°).

One of the great properties of vectors is it can be broken down into it's individual X and Y components (for 2-Dimensional space).

So if we wanted to *move* our particle at `50px / second`

at a `47°`

angle, we could calculate a vector for that like so:

```
function Vector(magnitude, angle){
var angleRadians = (angle * Math.PI) / 180;
this.magnitudeX = magnitude * Math.cos(angleRadians);
this.magnitudeY = magnitude * Math.sin(angleRadians);
}
var moveVector = new Vector(50, 47);
```

The wonderful thing about this is that these values can simply be added to any set of X and Y coordinates to *move* them based on your velocity calculation.

Modeling your objects in this way has the added benefit of making things nice and mathematically consistent. The distance between your particle and the mouse is just another vector.

We can back calculate both the distance and angle using a little bit more math. Remember that guy Pythagoras? Turns out he was pretty smart.

```
function distanceAndAngleBetweenTwoPoints(x1, y1, x2, y2){
var x = x2 - x1,
y = y2 - y1;
return {
// x^2 + y^2 = r^2
distance: Math.sqrt(x * x + y * y),
// convert from radians to degrees
angle: Math.atan2(y, x) * 180 / Math.PI
}
}
var mouseCoords = getMouseCoords();
var data = distanceAndAngleBetweenTwoPoints(particle.x, particle.y, mouse.x, mouse.y);
//Spread movement out over three seconds
var velocity = data.distance / 3;
var toMouseVector = new Vector(velocity, data.angle);
```

Animating your stuff around the screen in a way that isn't jerky means doing the following:

- Run your animation loop as fast as possible
- Determine how much time has passed since last time
- Move each item based on
*elapsed*time. - Re-paint the screen

For the animation loop, I would use the `requestAnimationFrame`

API instead of `setInterval`

as it will have better overall performance.

**Clearing The Screen**

Also when you re-paint the screen, just draw a big rectangle over the entire thing in whatever background color you want before re-drawing your items.

```
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
```

Here is a Fiddle demonstrating all these techniques: https://jsfiddle.net/jwcarroll/2r69j1ok/3/