• 沒有找到結果。

As mentioned, acceleration has a value—the force—and a direction, just like velocity. And like velocity, if you start with those two factors, you need to break them down into the component x and y forces. Now, if you are paying attention, you know that the way to do that is by using

Math.cos

and

Math.sin

. Here’s how that looks:

var force = 10,

angle = 45, //degrees. Need to convert!

ax = Math.cos(angle * Math.PI / 180) * force, ay = Math.sin(angle * Math.PI / 180) * force;

Now that you have acceleration for each axis, you can update the velocity on each axis, and from that, update the object’s position.

Let’s resurrect the mouse follower example from earlier in the chapter and make it work with acceleration instead of just plain velocity. Because that example used the

Arrow

class, find the

arrow.js

file to include in this exercise. Remember that in the earlier incarnation, you took the angle from the arrow to the mouse and used that to determine

vx

and

vy

. This time, you use the same calculations, but employ them to determine

ax

and

ay

instead. Then you add the acceleration values to the velocity values and the velocity values to the

x

and

y

properties. Here’s the code

(10-follow-mouse-2.html)

:

<!doctype html>

<html>

<head>

<meta charset="utf-8">

<title>Follow Mouse 2</title>

<link rel="stylesheet" href="style.css">

</head>

<body>

<canvas id="canvas" width="400" height="400"></canvas>

<script src="utils.js"></script>

<script src="arrow.js"></script>

<script>

window.onload = function () {

var canvas = document.getElementById('canvas'), context = canvas.getContext('2d'),

window.requestAnimationFrame(drawFrame, canvas);

context.clearRect(0, 0, canvas.width, canvas.height);

var dx = mouse.x - arrow.x, dy = mouse.y - arrow.y,

angle = Math.atan2(dy, dx), //radians ax = Math.cos(angle) * force,

ay = Math.sin(angle) * force;

124

arrow.rotation = angle;

vx += ax;

vy += ay;

arrow.x += vx;

arrow.y += vy;

arrow.draw(context);

}());

};

</script>

</body>

</html>

Notice that we also change the variable

speed

into

force

and make it much smaller. Because acceleration is additive, you want to start with small amounts because it builds up quickly. Also, now

vx

and

vy

are declared at the top of the script; earlier, they were calculated newly on each frame, but now you need to keep track of them and add or subtract from their value each time. Of course, you can do away with the

ax

and

ay

variables here altogether and just add the result of the sine and cosine lines directly to the velocities. Here, they are separated for clarity.

Run the example and you see the accelerating arrow swinging around a moving cursor and pointing toward the mouse position the entire time. But look back to the first motion example you did at the beginning of the chapter, and see just how far you’ve come. By learning just a couple of basic principles, you’ve now created something a million times more fluid and dynamic—something that almost feels alive.

And you’re not even at the end of the chapter yet!

Let’s pull everything together and see how much further you can go with it.

A spaceship

We’ve been talking a lot about spaceships travelling from here to there. Well, with the ground you’ve covered so far, you should be able to put together a reasonable spaceship simulation.

Here’s the plan. The spaceship will be a class of its own that takes care of drawing itself, much like the

Arrow

or

Ball

classes you’ve been using. You can use the left and right keys to rotate it left and right. The up key will act to fire the rocket. Of course, the rocket is in the back of the ship and fires straight back.

Thus, the force that the rocket applies will cause acceleration in the direction the ship is facing at that time.

Actually, what you’re going to make is like the ship in the old game Asteroids, but without the actual asteroids.

First, you need a ship class. Its

draw

method uses a few lines of canvas drawing API code to render four short, white lines, as an homage to the original that we are copying. Save the following code in the file

ship.js

to import into the next example:

function Ship () { this.x = 0;

this.y = 0;

this.width = 25;

this.height = 20;

this.rotation = 0;

this.showFlame = false;

125

}

Ship.prototype.draw = function (context) { context.save();

context.translate(this.x, this.y);

context.rotate(this.rotation);

context.lineWidth = 1;

context.strokeStyle = "#ffffff";

context.beginPath();

context.moveTo(10, 0);

context.lineTo(-10, 10);

context.lineTo(-5, 0);

context.lineTo(-10, -10);

context.lineTo(10, 0);

context.stroke();

if (this.showFlame) { context.beginPath();

context.moveTo(-7.5, -5);

context.lineTo(-15, 0);

context.lineTo(-7.5, 5);

context.stroke();

}

context.restore();

};

The

draw

method references the ship's property

showFlame

, which is a true or false value. This way, you can draw the ship with or without a flame showing. This is useful to show that the engines are firing. You can see how it looks with and without the flame in Figures 5-8 and 5-9.

Figure 5-8. The future of space travel.

126

Figure 5-9. All systems go.