When you are first learning coding, you should write small bits of code that you expect to work and that you have an exact idea of what you want it to do.
I will illustrate by developing a program that bounces a ball off walls within a rectangle. It is very helpful to break the program into specific tasks that the program needs to do. Here is a list of the steps that my program will need:
- Draw a rectangle
- Draw a ball
- Move a ball
- Detect when the ball hits a wall
- Change the direction of the ball
It is possible to write this program and have it work the first time if you are very experienced. But even with experience, there are likely to be errors in your code. With experience, it becomes easier to track down those errors.
But when you are just starting out, you will make more errors and you will have a harder time finding those errors. So, start slowly and get your program to do something and then build it up a little bit at a time.
Step 1: Drawing a rectangle
Here is the code needed to draw a rectangle:
<html>
<body>
<canvas id = "myCanvas" width = "500" height = "300" style="border:1px solid blue; background: white"></canvas>
</body>
</html>
This code gives you this:
It’s short and simple. It works. But even this can be a challenge if you are not familiar with using the canvas tag, you don’t know how big you want the rectangle to be on the screen, or you aren’t sure which properties need to be in “style”.
Step 2: Drawing a ball
The code can quickly escalate in complexity. To draw a ball, we need to use JavaScript. The new code will be in bold.
<html>
<body>
<canvas id = "myCanvas" width = "500" height = "300" style="border:1px solid blue; background: white"></canvas>
<script>
x = 100;
y = 100;
ctx = document.getElementById('myCanvas').getContext('2d');
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(x,y,10,0,2*3.14159);
ctx.fill();
</script>
</body>
</html>
This gives me this:
x = 100; y = 100; ctx = document.getElementById(‘myCanvas’).getContext(‘2d’); ctx.fillStyle = ‘red’; ctx.beginPath(); ctx.arc(x,y,10,0,2*3.14159); ctx.fill();I have only added a few lines of code. But I have had to understand:
- how to define a variable (‘ctx’) for the context
- how to change colors
- how to draw anything using .beginPath() and .fill()
- how to draw an arc that will display a complete circle of the correct radius
Step 3: Moving the ball
Once I am able to draw the ball within the rectangle, it is time to get the ball moving. This requires a little understanding of the logic behind the code.
The position of the ball within the rectangle is specified by x and y. The idea is to adjust x and y by a small amount each time and then redraw it. The small amount that the ball moves is defined by vx and vy. The absolute value of vx and vy determines how much the ball moves each time and the sign determines what direction the ball moves.
I have turned the code to draw the ball into a function which I can then call repeatedly by using the function setInterval(). setInterval() calls a function at repeated intervals defined by the second parameter which indicates the number of milliseconds.
In order to give the ball the appearance of movement, the old ball must be erased first. This is done with a ctx.clearRect(). This function requires the width and height of the canvas, which requires another reference to the <canvas> element. I therefore defined the variable ‘canvas’ and replaced part of my previous code with this variable. This has the added benefit of making the code a little easier to read.
The code now looks like this:
<html>
<body>
<canvas id = "myCanvas" width = "500" height = "300" style="border:1px solid blue; background: white"></canvas>
<script>
x = 100;
y = 100;
vx = 1;
vy = 1;
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
ctx.fillStyle = 'red';
setInterval(moveBall,500);
function moveBall() {
ctx.clearRect(0,0,canvas.width,canvas.height);
x = x + vx;
y = y + vy;
ctx.beginPath();
ctx.arc(x,y,10,0,2*3.14159);
ctx.fill();
}
</script>
</body>
</html>
The code now does this:
x = 100; y = 100; vx = 1; vy = 1; canvas = document.getElementById(‘myCanvas’); ctx = canvas.getContext(‘2d’); ctx.fillStyle = ‘red’; setInterval(moveBall,500); function moveBall() { ctx.clearRect(0,0,canvas.width,canvas.height); x = x + vx; y = y + vy; ctx.beginPath(); ctx.arc(x,y,10,0,2*3.14159); ctx.fill(); }If you don’t see anything, it’s because the ball has already left the screen. You can rerun the code by refreshing the webpage.
Step 4: Detecting the wall
Now it’s time to get the code to determine when the ball hits a wall. This is done by checking to see if x or y will be outside the boundary of the rectangle the next time it is updated. If it will be, then the “velocity” in the x or y direction is reversed by making vx = -vx or vy = -vy, respectively.
The code will get too long and difficult to read if we cram it all into the function moveBall(). Since detecting the walls is a different task, it should have its own function. Now I can’t just call moveBall() using setInterval(), so I make a function called update() which is called by setInterval(). Although this may seem like an extra step, it sets me up to add other functions to update().
The first time I wrote the code, the ball did not bounce, it just disappeared. I adjusted the code to help me troubleshoot the problem. First, I changed the color of the ball to blue when the floor was detected. This would let me see if the code for detecting the floor was triggered. Second, I raised the floor above the border of the rectangle. This let me see if the ball being drawn outside of the rectangle might cause the code to stop working. Eventually, I realized that I had not changed the function referred to by setInterval() from moveBall() to update(). So, my first two adjustments to help with troubleshooting were unnecessary, but that is often how troubleshooting goes.
Here is the new code:
<html>
<body>
<canvas id = "myCanvas" width = "500" height = "300" style="border:1px solid blue; background: white"></canvas>
<script>
x = 100;
y = 100;
vx = 1;
vy = 1;
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
ctx.fillStyle = 'red';
setInterval(update,50);
function update() {
checkWall();
moveBall();
}
function moveBall() {
ctx.clearRect(0, 0,canvas.width,canvas.height);
x = x + vx;
y = y + vy;
ctx.beginPath();
ctx.arc(x,y,10,0,2*3.14159);
ctx.fill();
}
function checkWall() {
if (x + vx > 500) {
vx = -1;
}
if (x + vx < 0) {
vx = 1;
}
if (y + vy > 200) {
vy = -1;
ctx.fillStyle = 'blue';
}
if (y + vy < 0) {
vy = 1;
}
}
</script>
</body>
</html>
This gives me this:
x = 100; y = 100; vx = 1; vy = 1; canvas = document.getElementById(‘myCanvas’); ctx = canvas.getContext(‘2d’); ctx.fillStyle = ‘red’; setInterval(update,50); function update() { checkWall(); moveBall(); } function moveBall() { ctx.clearRect(0, 0,canvas.width,canvas.height); x = x + vx; y = y + vy; ctx.beginPath(); ctx.arc(x,y,10,0,2*3.14159); ctx.fill(); } function checkWall() { if (x + vx > 500) { vx = -1; } if (x + vx 200) { vy = -1; ctx.fillStyle = ‘blue’; } if (y + vy < 0) { vy = 1; } }This makes me pretty happy, but it is not completely satisfying yet. Still, at this point, it feels like it is all going to work.
Step 5: Cleaning things up
The code is now working except for a few minor details:
- The ball only bounces when the middle of the ball hits the wall, instead of the edge of the ball.
- The ball bounces off an invisible floor.
- The movement is too slow.
- The ball changes color
I have fixed all of these in this code:
<html>
<body>
<canvas id = "myCanvas" width = "500" height = "300" style="border:1px solid blue; background: white"></canvas>
<script>
x = 100;
y = 100;
vx = 1;
vy = 1;
r = 5;
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
ctx.fillStyle = 'red';
setInterval(update,10);
function update() {
checkWall();
moveBall();
}
function moveBall() {
ctx.clearRect(0,0,canvas.width,canvas.height);
x = x + vx;
y = y + vy;
ctx.beginPath();
ctx.arc(x,y,10,0,2*3.14159);
ctx.fill();
}
function checkWall() {
if (x + vx + r> 500) {
vx = -1;
}
if (x + vx - r< 0) {
vx = 1;
}
if (y + vy + r > 300) {
vy = -1;
}
if (y + vy - r < 0) {
vy = 1;
}
}
</script>
</body>
</html>
The main thing to notice is that I adjusted the detection of hitting a wall by the ball’s radius, r. Finally, I get this:
x = 100; y = 100; vx = 1; vy = 1; r = 5; canvas = document.getElementById(‘myCanvas’); ctx = canvas.getContext(‘2d’); ctx.fillStyle = ‘red’; setInterval(update,10); function update() { checkWall(); moveBall(); } function moveBall() { ctx.clearRect(0,0,canvas.width,canvas.height); x = x + vx; y = y + vy; ctx.beginPath(); ctx.arc(x,y,10,0,2*3.14159); ctx.fill(); } function checkWall() { if (x + vx + r> 500) { vx = -1; } if (x + vx – r 300) { vy = -1; } if (y + vy – r < 0) { vy = 1; } }Step 6: Going further
There are many other steps to finish to make this a complete game. These would include:
- drawing a paddle near the bottom
- moving the paddle using the arrow keys
- detecting when the ball hits the paddle
- drawing blocks near the top
- detecting when the ball hits the blocks
- drawing a score
- updating the score
Most of these steps would require a new function.
When it is finished, the update() function would look something like this:
function update() {
checkWall();
checkPaddle();
moveBall();
movePaddle();
drawBlocks();
drawScore();
}
Hopefully, this gives you an idea of how to build up to writing a bigger, more complicated program by getting the code to work in small steps. Even experienced programmers do this in the form of writing one function at a time and keeping that function relatively simple.
Leave a comment