Skip to content

Instantly share code, notes, and snippets.

@jonurry
Last active April 18, 2018 11:05
Show Gist options
  • Save jonurry/77af711398514839cb8128b6663e75b5 to your computer and use it in GitHub Desktop.
Save jonurry/77af711398514839cb8128b6663e75b5 to your computer and use it in GitHub Desktop.
17.3 A Bouncing Ball (Eloquent JavaScript Solutions)
<canvas width="400" height="400"></canvas>
<script>
const roundDown = num => {
return Math.floor(num);
};
const roundUp = num => {
return Math.floor(num + 0.5);
};
let cx = document.querySelector("canvas").getContext("2d");
// draw the box
let xOffset = 50;
let yOffset = 50;
let height = 200;
let width = 200;
let xMin = xOffset;
let xMax = xOffset + width;
let yMin = yOffset;
let yMax = yOffset + height;
let ballRadius = 14;
let ballXPos = xMax / 2 + xMin;
let ballYPos = yMax / 2 + yMin;
let ballAngle = Math.random() * 2 * Math.PI;
let speed = 3;
let borderWidth = 4;
let innerXMin = xMin + roundUp(borderWidth / 2);
let innerXMax = xMax - roundUp(borderWidth / 2) * 2;
let innerYMin = yMin + roundUp(borderWidth / 2);
let innerYMax = yMax - roundUp(borderWidth / 2) * 2;
let ballXMin = innerXMin + ballRadius;
let ballXMax = innerXMax + xOffset + roundDown(borderWidth / 2) - ballRadius;
let ballYMin = innerYMin + ballRadius;
let ballYMax = innerYMax + yOffset + roundDown(borderWidth / 2) - ballRadius;
// draw the box
cx.strokeStyle = 'blue';
cx.lineWidth = borderWidth;
cx.strokeRect(xMin, yMin, xMax, yMax);
// move to the centre of the box where the ball will start from
cx.moveTo(ballXPos, ballYPos);
let lastTime = null;
function frame(time) {
if (lastTime != null) {
updateAnimation(Math.min(100, time - lastTime) / 1000);
}
lastTime = time;
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
function updateAnimation(step) {
// animate the ball
let xInc = Math.cos(ballAngle) * speed;
let yInc = Math.sin(ballAngle) * speed;
if (ballXPos + xInc < ballXMin) {
ballAngle = Math.PI - ballAngle;
xInc = ballXMin - ballXPos - xInc;
};
if (ballXPos + xInc > ballXMax) {
ballAngle = Math.PI - ballAngle;
xInc = ballXMax - ballXPos - xInc;
};
if (ballYPos + yInc < ballYMin) {
ballAngle = 2 * Math.PI - ballAngle;
yInc = ballYMin - ballYPos - yInc;
};
if (ballYPos + yInc > ballYMax) {
ballAngle = 2 * Math.PI - ballAngle;
yInc = ballYMax - ballYPos - yInc;
};
ballXPos += xInc;
ballYPos += yInc;
cx.clearRect(innerXMin, innerYMin, innerXMax, innerYMax);
cx.fillStyle = 'red';
cx.beginPath();
cx.arc(ballXPos, ballYPos, ballRadius, 0, 2 * Math.PI);
cx.fill();
}
</script>
@jonurry
Copy link
Author

jonurry commented Apr 17, 2018

17.3 A Bouncing Ball

Use the requestAnimationFrame technique that we saw in Chapter 14 and Chapter 16 to draw a box with a bouncing ball in it. The ball moves at a constant speed and bounces off the box’s sides when it hits them.

@jonurry
Copy link
Author

jonurry commented Apr 17, 2018

Hints

A box is easy to draw with strokeRect. Define a binding that holds its size or define two bindings if your box’s width and height differ. To create a round ball, start a path and call arc(x, y, radius, 0, 7), which creates an arc going from zero to more than a whole circle. Then fill the path.

To model the ball’s position and speed, you can use the Vec class from Chapter 16 (which is available on this page). Give it a starting speed, preferably one that is not purely vertical or horizontal, and every frame, multiply that speed with the amount of time that elapsed. When the ball gets too close to a vertical wall, invert the x component in its speed. Likewise, invert the y component when it hits a horizontal wall.

After finding the ball’s new position and speed, use clearRect to delete the scene and redraw it using the new position.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment