Making a Bouncy Ball Using Physics
In this blog post, we are going to take a look at some javascript. Specifically speaking, we will have some fun with physics! The idea is to make a bouncing ball using Javascript and HTML 5 Canvas. Before we get start coding the physics involved, we need to take a quick detour to learn about the Canvas coordinate system. The Canvas coordinate system is not quite the same as the Cartesian coordinate system. The x-coordinate still runs from left to right but the y-coordinate goes from the top to bottom. The Cartesian system is known as a right-handed coordinate system, therefore we can see that the Canvas coordinate system is a left-handed coordinate system.
2D Coordinate systems (left = Cartesian, right = Canvas)
Sounds fun, right? So lets start with some of the starter code to draw a ball onto the canvas and then we will jump into the physics side of things. The first thing that we want to do is create an HTML file that is incredibly basic. It will just have a canvas and a basic height and width. We will also link it to a stylesheet and a script.
HTML
<html>
<head>
<meta charset="utf-8">
<title>Bouncing Ball</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="canvas" width="700" height="500"></canvas>
<script src="ball.js"></script>
<script src="bouncing-ball.js"></script>
</body>
</html>
Code copied
I'll also include a simple css file to center the canvas on the page.
CSS
body {
background-color: grey;
}
#canvas {
margin: auto;
padding: 0;
display: block;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: #000;
}
Code copied
One last thing before the meat and potatoes. We need a ball class whose constructor takes in a radius and a color for the ball so that we can draw the ball. The ball will have four more attributes, the x-coordinate position, the y-coordinate position and the horzontal and vertical velocity. The ball class will have one method called draw which will take in one argument, an HTML canvas element that is retrieved using the getContext() method. This method returns a drawing context on the canvas. If you'd like to read more, please refer to the MDN.
JavaScript
class Ball {
constructor(radius, color) {
this.radius = radius;
this.color = color;
this.x = 0;
this.y = 0;
this.vx = 0;
this.vy = 0;
}
draw(context) {
context.fillStyle = this.color;
context.beginPath();
context.arc(this.x, this.y, this.radius, 0, 2*Math.PI, true);
context.closePath();
context.fill();
}
}
Code copied
Let's take a look at this code a little further. The draw method that takes in the HTML 5 canvas drawing context will use the fillStyle property of the Canvas 2D API. It will specify the color inside shapes. We then need to draw a path that will render the shape of a circle by calling beginPath. This is followed by the arc property to draw the path we called previously. This will be set in our bouncing ball class and will draw a perfect circle. The parameters of the arc property take in 6 properties. The first two will specify the horizontal and vertical coordinate of the arc's center. Next is the radius of the arc which must be positive, followed by a start and end angle in radians that are measured from the positive x-axis. Last is an optional boolean value for whether we want the arc to draw counter-clockwise of clockwise. The default is false (clockwise). Now that we've drawn the circle we can close the path and finally fill the circle with our fillStyle property.
Now comes the fun part which is how we animate the ball. We will assign the ball a radius of 20 and most importantly, we need to initialize acceleration due to gravity. For now, that value is 0.1 but feel free to play around with that value. Initialization of a global ball variable will be used in the init method. The ball will be given an initial horizontal and vertical position, as well as an initial horizontal and vertical speed. The draw method from the ball class will be called and we now call setInterval with two arguments, the method onEachStep which will calculate not only the vertical and horzontal speed, but it will also calculate the path of the ball after it hits the ground or the left and right sides of the canvas object. The setInterval method repeatedly calls a function with a fixed time delay. We will give it 60fps. On each step we will add gravity to the balls vertical speed over time. The same will be said about the vertical position by adding the vertical speed that was calculated. Horizontal speed will be used to increase the balls horizontal position. All code will be commented so that it is easier to follow. Since there are three walls we are considering, we need some conditionals on an appropriate action to take if the ball hits one of the three walls. The first conditional is if the ball hits the ground. This can be calculated by checking if the balls vertical position is greater than the canvas height minus the radius, we will reposition the ball at that value and reverse the direction of the vertical speed by multiplying it by a negative value. This value will also be a little less than the gravity value given earlier so that we see a reduction in speed. This might seem confusing at first because of the knowledge of the Cartesian coordiante system. But, remember that in the Canvas Coordinate system, the y-coordinate increases as it goes down. For the right wall, we will check if the ball's horizontal position is greater than the canvas width, minus the radius. The same action will take place with the reduction of the balls speed. Lastly, if the balls horizontal position is less than 20, we have hit the left wall and the reduction of horizontal speed with be reduced. Finally, we need to clear the rectangle and redraw the ball. This will loop indefinately. Below is the code.
JavaScript
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var radius = 20;
var color = "#4b0979";
var g = 0.1; // acceleration due to gravity
var ball;
console.log(canvas.width)
window.onload = init;
function init() {
ball = new Ball(radius, color);
ball.x = 50; // initial horizontal position
ball.y = 50; // initial vertical position
ball.vx = 4 ; // initial horizontal speed
ball.vy = 0; // initial vertical speed
ball.draw(context);
setInterval(onEachStep, 1000/60); // 60 fps
};
function onEachStep() {
ball.vy += g; // gravity increases the vertical speed
ball.x += ball.vx; // horizontal speed increases horizontal position
ball.y += ball.vy; // vertical speed increases vertical position
if (ball.y > canvas.height - radius){ // if ball hits the ground
ball.y = canvas.height - radius; // reposition it at the ground
ball.vy *= -0.8; // then reverse and reduce its vertical speed
}
if(ball.x > canvas.width - radius) { // if ball hits the right wall
ball.vx *= -0.8; // reverse and reduce its horizontal speed
}
if(ball.x < 20) { // if ball hits the left wall
ball.vx *= -0.8;
}
context.clearRect(0, 0, canvas.width, canvas.height);
ball.draw(context); // draw the ball
};
Code copied
There is quite a bit of material here, so I would suggest playing with as much code as you can. It will help you understand the complexities of drawing on canvas that much easier.