JavaScript Breakout – Building Breakout with JavaScript and HTML5

June 2nd, 2019 9:34 am |  by David.Reid  |  Posted in Tutorial

 

Greetings fellow programmers. In this article we will go through the steps required to build JavaScript Breakout which is a clone of the old classic we “older” kids used to play back in the day.

By the time you have completed this tutorial, you will have programmed your very own version of Breakout and you will have covered many of the basics required to create two dimensional games with JavaScript and HTML5.

For those younger kids that are unfamiliar with Breakout you can find out more about the game here. Also, the source code for this tutorial is available on my JavaScript Breakout repository. And, there is a more complete version of the game that you can play here.

Okay, if you are ready to build JavaScript Breakout, then grab a coffee, open your favourite editor and lets get started.

JavaScript Breakout Prerequisites and Requirements

Before we begin, I’m going to assume that a) you are a programmer and b) that you are familiar with JavaScript.

All the source code you need for JavaScript Breakout is in this tutorial so a knowledge of JavaScript and for that matter programming, is not entirely necessary but it sure will make a lot more sense if you are a programmer.

Any editor will do the trick. Notepad is all you need but an editor like Visual Studio Code, Atom or Emacs is far superior. I’m using Visual Studio Code but its not a requirement, so feel free to use whatever editor floats your boat.

Although not entirely necessary, we’ll be using Node to create a package.json file for our game. You can grab Node here.

The game will run on a browser. I’m using Chrome. I haven’t tested the game on any other browser. So, if you can use Chrome then you should. And, the game will run using the file:// protocol so there is no need to host the game on a local server.

Game Requirements for JavaScript Breakout

JavaScript Breakout is a pretty simple game with very little complexity in terms of requirements. However, we should still follow the good practice of ironing out what we will build today. So here is a list of requirements for our game play.

  • There will be one paddle – the player paddle – that is fixed to the bottom of the screen. The player can move that paddle left or right using the mouse.
  • There will be a single ball that bounces off the bricks, the top, the left and the right hand of the screen. The ball can exit the lower end of the screen.
  • The top half of the screen will be a grid of coloured bricks. When the ball hits a brick, that brick will disappear.
  • The aim of the game is to use the ball to clear all the bricks from the screen.
  • If the ball passes the paddle and exits the bottom end of the screen then the grid of bricks is reset.
  • If all the bricks are cleared from the screen, the game is won.

And, that is pretty much the requirements for our game play. So that’s enough planning, lets get down to the business of coding JavaScript Breakout.

JavaScript Breakout File Architecture

Create a new folder for your game called JavaScript.Breakout. This will be the root directory for all our game files.

Open a terminal and change the directory to your new JavaScript.Breakout directory. Inside that directory run the following command and accept the default settings.

npm init

This will create a package.json file for your game. It’s overkill for this project but its good practice to create a package file for your apps. The default settings for your package.json file will look something like this.

{
  "name": "javascript.breakout",
  "version": "1.0.0",
  "description": "JavaScript breakout",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT"
}

Inside your root directory create two files. Index.html and Index.js. These two files will contain all the relevant code for our game. The Index.html file will be used to handle our games display and the Index.js file will be used to handle our games logic.

The initial Index.html file

Open up your favourite editor and add the following code to your Index.html file.

<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <script src='index.js'></script>

    <title>JavaScript Breakout</title>

</head>

<body>

        <canvas id="canvas" width="600", height="600"></canvas>
    
</body>
</html>

The initial Index.js file

Open up the Index.js file and add the following code.

window.onload = function() {
    console.log('JavaScript Breakout v1.0.0');
}

After you have saved both files, open Index.html in your browser and you will see absolutely nothing, but that’s okay. Open up the developer tools on your browser – CTRL + SHIFT + I – on Chrome, switch to the console tab and you will see JavaScript Breakout v 1.0.0 in the console.

If you see the aforementioned message, then Index.html loaded and has found the Index.js file. It did that using the following line of code in the head tag.

<script src='index.js'></script>

And, when the Index.html file loaded our Index.js file, it triggered the following code that is situated inside our Index.js file.

window.onload = function() {
    console.log('JavaScript Breakout v1.0.0');
}

Which in turn, printed the ‘JavaScript Breakout v1.0.0 message in our developer tools console.

Awesome! We’re done here. And, because Breakout is a fairly simple game, this setup will be suffice for the duration of the project.

Our file architecture is complete. From this point onward, all of the coding magic will happen in our Index.js file.

The Canvas

We’ll use the HTML5 Canvas API to build the visual components of our game. The Canvas API specifications are too in depth for this article but they are worth reading. You can do that here.

For our purposes, all you need to know is that the Canvas API allows us to draw graphical elements on our screen. For example, the ball, the paddle and the bricks.

To use the canvas, you must first add it to your HTML file and as it just so happens, we have already done this. If you open up your Index.html file you will see the following line of code nested in the BODY tag.

<body>

        <canvas id="canvas" width="600", height="600"></canvas>
    
</body>

The HTML CANVAS element declares a new canvas with a specified id, width and height. The id attribute is important, as we’ll need it to reference the code in our Index.js file.

We’ll also override the width and height attributes but its good practice to declare the canvas with a default dimensions in case something goes wrong when loading our game.

Now that we’ve briefly discussed the Canvas API and canvas element, lets declare and make use of it in our Index.js file.

Declaring and using the Canvas Element in our Index.js file

Open up the Index.js file and add the following code to the top of the file.

// Constants and variables
let canvas; 
let context;

The two variables that you added to your Index.js file will be used to store our canvas element and its context. The canvas object allows us to access the canvas dimensions and add events. The context allows us to draw graphical elements on the canvas.

When we created the Index.js file we added the following lines of code.

window.onload = function() {
    console.log('JavaScript Breakout v1.0.0');
}

This code declares an anonymous function that is triggered when the Index.html file is loaded. At the moment, the anonymous onload function merely prints a message to the console. However, we want to change that. Now, we want our canvas and context variables to be declared when the Index.html page loads.

We do that with the following code.

window.onload = function() {
    
    console.log('JavaScript Breakout v1.0.0');

    canvas = document.getElementById('canvas');
    context = canvas.getContext('2d');
}

If you open your Index.html file in a browser you will see absolutely nothing but that’s okay. Our canvas is in place, has been declared and is ready for use in our game.

We’ll be revisiting the canvas and its context when we create graphic utilities for our game but before we do that, we need to discuss some utility requirements.

Resizing the Canvas

In my last tutorial JavaScript Pong we created a canvas with a set width and height. For JavaScript Breakout we are going to be things a little differently. We are going set the canvas dimension to that of the browser. Using all of the browsers available space is cool but comes with some issues. Firstly, the browsers dimensions are dependant on the users screen and therefore varies quite drastically. Secondly, a user can change the size of their browser during anytime in our game.

To deal with the aforementioned, we will do two things. Firstly, when the browser initially loads, we’ll set our canvas dimensions to match our browser dimensions. And secondly, when the user changes the size of their browser we’ll trigger a resize function that resizes the canvas dimensions to the new browser dimensions.

The canvas resize function

So, enough chit chat, open up Index.js and add the following code.

// Utility functions

function resize() {

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight - 6;
}

This new function is responsible for setting our canvas dimensions to match our browser dimensions. We’ll use this new function in two places. Firstly, we’ll add it to our window.onload function to initially set our canvas size. And secondly, in our Index.html file, we’ll add an event listener to our body tag that will call our resize function every time the browser size is changed.

Resizing our canvas on window load

So lets get that done by opening up Index.js and modify the window.onload function by adding a call to the resize function beneath our canvas and context references.

window.onload = function() {
    
    console.log('JavaScript Breakout v1.0.0');

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

    resize();
}

Great, now when we load the game, the canvas will be set and then the resize function will set its dimensions to match the dimensions of the users browser. Perfect! Okay, that is page load taking care of. Lets modify our code so that the canvas resizes when the user resizes the browser.

Resizing the canvas when the browser size changes

Now open up the Index.html and add an onresize attribute to the body tag as demonstrated below.

<body onresize="resize();">

Sweet! The onresize attribute in our body tag allows us to call a function every time the browser is resized and in our case, we have called our function that resizes our canvas. That means that our canvas will always be the same size as the users browser. That is what we call sweet JavaScript magic. Give yourself a high five.

But, there is one small issue we need to deal with before we move on. Our canvas is now the same size as our body element but the latter comes with some default styling. And, that default styling comes with padding. The latter means our canvas will be a few pixels shorter in both height and width. The good news is that we can sort that with some simple styling so lets do that now.

Removing padding and margins from our Index.html page

Open up your Index.html file and modify the <head> tag as demonstrated below.

<head>

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <script src='index.js'></script>

    <!-- new styles that remove padding and margins on our body element -->
    <style>
        body {
            padding:0px;
            margin:0px;
            background:#313639;
            color:#f5f5f5;
        }
    </style>

    <title>JavaScript Breakout</title>

</head>

Basically, we’ve added a style tag to our Index page that removes padding and margins from the body tag. It’s also set the foreground and background colours for our page. The purists will argue that we should have added a .css file to our game and added our styles there. And, to be fair, the purists are right but this is the only styling we will do to our Index page and therefore we’ll skip proper convention and keep our file count down by adding the styles the old dirty way.

Okay, that was a lot of talk to do very little. Lets move on to something game orientated. Lets create the game loop.

The Game Loop

Okay, lets start this part of the tutorial by opening up the Index.js file and add the following code.

// Game Loop Functions
function gameLoop() {

    moveEverything();
    drawEverything();
}

function moveEverything() {
    console.log('move everything');
}

function drawEverything() {
    console.log('draw everything');
}

What we’ve got here is three functions that will basically turn our browser into an engine for updating and drawing our game. Let’s briefly discuss what we’ve added.

The first function – gameLoop – controls all the logic required for one iteration of our game loop. As you can see it states the everything should be moved and then drawn. And those two requirements have been allocated to the moveEverything and drawEverything functions that will, well move everything and draw everything.

If you rerun your game by loading Index.html in your browser you will see that nothing happens. However, that is minor issue that we can overcome with by updating our window.onload function as follows.

window.onload = function() {
    
    console.log('JavaScript Breakout v1.0.0');

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

    resize();

    setInterval(gameLoop, 1000/FRAMES_PER_SECOND);
}

And, lets update the constants and variables section of our Index.js file with the following code.

// Constants and variables
let canvas; 
let context;
const FRAMES_PER_SECOND = 60;

Basically we added the following code segments to our window.onload function and our constants.

// We added the code below to our Constants and variables section
const FRAMES_PER_SECOND = 60;

// And we added this line of code to our window.onload function.
setInterval(gameLoop, 1000/FRAMES_PER_SECOND);

Let’s briefly go over what this small but very significant code addition does to our game.

Simulating Motion in JavaScript Breakout

Lets start this discussion with an earth shattering truth. Pictures dont move! Yep, I know, ground breaking stuff right? Now that you’ve swallowed the red pill of motion graphics, lets talk about how we actually achieve motion.

Basically, we want to position all our actors on the screen, we do that with the – moveEverything – function. Once all those actors are in place we want to draw them on the screen with our – drawEverything function. So far so good, but how do we get them to move.

Well, the trick is to move everything and draw everything repeatedly throughout the duration of the game. And, we want that repetition to be so quick that the users eye is tricked into believing that the actors on the screen are moving. That magic number is thirty times per second. Moving and drawing everything once is called a frame and our game loop code takes care of a single frame. And, the following code decides how many times we should run a frame (game loop).

setInterval(gameLoop, 1000/FRAMES_PER_SECOND);

The function – setInterval – is a JavaScript function that takes a function and a number as a parameter. It then runs the passed function at specific intervals. In our case, that is thirty times per second.

You can read more about the – setInterval – function pop over to the Mozilla Development Network and if you want to know more about frame rates then pop over to Wikipedia.

And that is pretty much it for our game loop introduction. If you rerun your game by loading Index.html in your browser yo will see a blank screen. Yawn! However, if you open up your console – control + i on chrome – you will see that moveEverything and drawEverything are spitting our console messages at a phenomenal rate, thirty times per second to be precise.

Now that we have our game loop in place. Its time to start thinking about graphics. Let’s start by creating some graphic utility classes.

JavaScript Breakout Graphic Utilities

Okay, we’ve got our game loop in place and our game is running at thirty frames per second. That’s great but we don’t actually have any game actors such as our paddle, the bricks and the ball. We obviously want to change that.

Luckily for us, the actors in this game can be drawn with just a few simple functions that take advantage of the HTML Canvas API. Let’s add the new functions to our game and then discuss them very briefly.

Add the following code to the end of your Index.js file.

// Graphic utility functions
function colorRect(topLeftX,topLeftY, boxWidth,boxHeight, fillColor) {
    context.fillStyle = fillColor;
    context.fillRect(topLeftX,topLeftY, boxWidth,boxHeight);
}

function colorCircle(centerX,centerY, radius, fillColor) {
    context.fillStyle = fillColor;
    context.beginPath();
    context.arc(centerX,centerY, 10, 0,Math.PI*2, true);
    context.fill();
}

function printText(text, xPos, yPos, size, font, color) {
    context.fillStyle = color;
    context.font = `${size} ${font}`;
    context.fillText(text, xPos, yPos);
}

Okay, as you can see, we have three new functions in our game. The first – colorRect – will allow us to draw rectangles anywhere on the screen, with any given size and color. This is a particularly useful function because we can use it for the paddle, the bricks and the background.

The next function is – colorCircle – which we can use for drawing the ball and finally, we have the – printText – function which we can use for displaying methods.

And that is it. That is all the graphic utility functions that we need for this game. Let’s go ahead and start using them to draw and move our Player paddle.

Drawing and Moving the Player Paddle

As it happens, drawing and moving the player paddle is one of the easiest coding exercises in the game. So lets get to it. First off, we want to update our constants and variables section as shown below.

// Constants and variables
let canvas; 
let context;
const FRAMES_PER_SECOND = 30;

const BACKGROUND_COLOR = '#313639'; // New color constants for our game
const COLOR_WHITE = '#f5f5f5';
const COLOR_BLUE  = '#6abef0';
const COLOR_PINK  = '#ec88e8';
const COLOR_GREEN = '#88ECC8';

const PADDLE_WIDTH = 100; // New constants for our paddle
const PADDLE_THICKNESS = 10;
const PADDLE_DISTANCE_FROM_EDGE = 40;

let paddleX = 400; // New variable for our paddle

As you can see, we’ve added quite a few new constants. We’ve added some colours for our game and more importantly to this section of the tutorial we’ve added constants for the paddle width, thickness, the distance from the edge and the paddles X position. Theses are pretty self explanatory but we’ll discuss them in more depth as they are used.

Next we need to draw the paddle on the screen. We do that by adding the following code to our drawEverything function as demonstrated in the code below.

function drawEverything() {
    
    colorRect(paddleX, canvas.height-PADDLE_DISTANCE_FROM_EDGE, PADDLE_WIDTH, PADDLE_THICKNESS, COLOR_WHITE);
}

In the above snippet of code, we’ve used the colorRect function, which we created in the earlier as part of our graphic utilities section. This colorRect function is being used to draw our paddle. As you can see, we are using our paddleX variable to set the left most position of the paddle, and we are using the other paddle constants to set the colour, thickness and distance from the bottom of the screen.

So far so good. But, if you run the game, you’ll see that our paddle is there but it aint moving. Let’s fix that next.

Moving the Player Paddle

For this game, we are going to control the player paddle with the mouse. To do this, we need to create a function that moves the paddle based on the mouse position and then set an event to listen for mouse movement.

Add the following code to the bottom of your Index.js file.

// Input
function updateMousePos(evt) {
            
    let rect = canvas.getBoundingClientRect();
    let root = document.documentElement;
    mouseX = evt.clientX - rect.left - root.scrollLeft;
    mouseY = evt.clientY - rect.top - root.scrollTop;
    paddleX = mouseX - PADDLE_WIDTH / 2;
}

This function accepts a mouse event. It then grabs the mouse data and re-positions the paddle by setting the paddleX variable to be that of the mouse x position minus half the paddle width. In short, the paddle centre will always be equal to the mouse x position.

A keen eye will notice that we are using two variables that are not declared in the updateMousePos function. Those variables are mouseX and mouseY. We could declare them in the function but instead we are going to add them to our constants and variables section as demonstrated below.

// Constants and variables
let canvas; 
let context;
const FRAMES_PER_SECOND = 30;

const BACKGROUND_COLOR = '#313639';
const COLOR_WHITE = '#f5f5f5';
const COLOR_BLUE  = '#6abef0';
const COLOR_PINK  = '#ec88e8';
const COLOR_GREEN = '#88ECC8';

const PADDLE_WIDTH = 100;
const PADDLE_THICKNESS = 10;
const PADDLE_DISTANCE_FROM_EDGE = 40;

let paddleX = 400;
let mouseX; // New variables for our mouse.
let mouseY;

So far so good but, our new updateMousePos function is never called within our game. We fix that by adding a mouse event listener to our window.onload function as shown below.

window.onload = function() {
    
    console.log('JavaScript Breakout v1.0.0');

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

    resize();

    setInterval(gameLoop, 1000/FRAMES_PER_SECOND);

    canvas.addEventListener('mousemove', updateMousePos);
}

As you can see from the code above, the canvas.addEventListener, triggers our updateMousePos when the mouse moves.

Great. Now we have our player paddle in play. To summarise, we used the colorRect function to draw our paddle. We set a mouse listener that triggers our updateMousePos function when the mouse is moved. That function in turn re-positions the paddle and finally, because we are drawing our game every thirty seconds, it looks like our paddle moves across the bottom of the screen.

If you run the game, you’ll see something strange happening. When you move the mouse, the paddle gets wider and fills the bottom of the screen.

Any guesses why?

Well, its simple, we are re-drawing the paddle but we are not overriding the last paddle draw. We need to override the last frame before we draw the next frame. And, we do that be drawing a background coloured rectangle over the whole screen. To do that, update the drawEverything function with the code below.

function drawEverything() {

    // Background color painted over the entire canvas.
    colorRect(0, 0, canvas.width, canvas.height, BACKGROUND_COLOR);
    
    // Paddle player
    colorRect(paddleX, canvas.height-PADDLE_DISTANCE_FROM_EDGE, PADDLE_WIDTH, PADDLE_THICKNESS, COLOR_WHITE);
}

Now, if you re-run the game, you’ll see that moving the mouse moves the paddle and our weird paddle painting effect has disappeared which is great.

And that is it. We now have a player paddle on the screen that reacts to our mouse moves. We are one step closer to having a game.

Let’s move on to the more complicated problem of drawing bricks on our screen.

Drawing the JavaScript Breakout Bricks

At the beginning of this tutorial I told you to grab a coffee. Did you? Well, its time to grab another coffee because there is a lot to cover here.

Okay, now that you have your fresh new coffee, lets start by adding the constants and variables we need for JavaScript Breakout bricks. Update your constants and variables with the following code.

// Constants and variables
let canvas; 
let context;
const FRAMES_PER_SECOND = 30;

const BACKGROUND_COLOR = '#313639';
const COLOR_WHITE = '#f5f5f5';
const COLOR_BLUE  = '#6abef0';
const COLOR_PINK  = '#ec88e8';
const COLOR_GREEN = '#88ECC8';

const PADDLE_WIDTH = 100;
const PADDLE_THICKNESS = 10;
const PADDLE_DISTANCE_FROM_EDGE = 40;

const BRICK_WIDTH = 80; // New constants for our bricks
const BRICK_HEIGHT = 20;
let BRICK_COLS = 10;
const BRICK_GAP = 2;
const BRICK_ROWS = 14;

let bricksLeft; // New variables for our bricks
let brickGrid = Array(BRICK_COLS * BRICK_ROWS);
let paletteGrid = Array(BRICK_COLS * BRICK_ROWS);

let paddleX = 400;
let mouseX;
let mouseY;

Okay, so we’ve added quite a lot of constants and variables to our game. Many of the constants are self explanatory such as width, height, cols and rows. We also have two arrays, one for storing bricks and the other for storing colours. This will allow us to add random colours to the bricks on our screen.

The purists would make the Brick a class and add a random colour as a class field. And, once again, the purists would be right. However, the purists will be perfecting their unfinished game till the end of time. We’d like to finish our game today so we’ll skip the classes tutorial and stick with two arrays, one for bricks and one for brick colours.

Resetting JavaScript Breakout Bricks

The next thing we need to do is prepare the bricks so that they are ready to display when the game starts. We also need to reset the bricks when the player destroys all the bricks or the player resizes the screen. And finally, we need to reset the bricks if the ball exits the bottom of the screen. These four scenarios, startup, completion, resize and ball miss, require the bricks to be prepared, therefore we’ll kill four birds with one stone by creating a function called brickReset. Let’s do that now.

Add the following code to the bottom of your Index.js file.

// Brick Functions
function brickReset() {
    
    BRICK_COLS = Math.ceil(canvas.width / BRICK_WIDTH);
    
    brickGrid = Array(BRICK_COLS * BRICK_ROWS);
    paletteGrid = Array(BRICK_COLS * BRICK_ROWS);

    bricksLeft = 0;
        
    for (let i = 0; i < BRICK_COLS * BRICK_ROWS; i++) {
        
        brickGrid[i] = true;
        bricksLeft++;

        let index = Math.floor(Math.random() * Math.floor(3));
        
        switch (index) {
            case 1:
                paletteGrid[i] = COLOR_BLUE;
                break;
            case 2:
                paletteGrid[i] = COLOR_GREEN;
                break;
            default:
                paletteGrid[i] = COLOR_PINK;
        }
    }
}

Now that we have a function for resetting bricks we can use it within our game to reset our brick grid at critical moments in the game life cycle. As I mentioned before those critical moments are, when the game starts, when the player destroys all the bricks, when the player resizes the screen and when the player misses the ball. At this point in the game we can deal with two of those critical moments – game start and screen resize – lets do that now.

Resetting Bricks on Game Start and Screen Resize.

Let’s start with the game start. Open up your Index.js file and update your window.onload function as demonstrated below.

window.onload = function() {
    
    console.log('JavaScript Breakout v1.0.0');

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

    resize();

    setInterval(gameLoop, 1000/FRAMES_PER_SECOND);

    canvas.addEventListener('mousemove', updateMousePos);

    brickReset(); // Place our new brickReset function here.
}

Cool, now when you load the game in your browser, the brickReset function will kick in and prepare our brick grid and assign a random brick colour for each brick.

Now, we want to reset the grid when the player resizes the screen. We do that by updating our utility function resize as shown below.

function resize() {

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight - 6;

    brickReset(); // Place our new brickReset function here.
}

And there you have it. We’ve modified our game to reset the bricks every time the game is loaded and every time the user resizes the screen. We are getting through our brick logic but before we move on, I want to discuss why we reset the bricks when the screen resizes.

Why do we reset bricks when the user resizes the screen?

In our brick reset function you will see the following line of code.

BRICK_COLS = Math.ceil(canvas.width / BRICK_WIDTH);

That code sets how many columns our brick grid has by checking the width of the canvas and then dividing it by the width of a brick. In short, we’re finding out the width of the players screen and filling the width of that screen with bricks. That goes some way to ensure that players will see a screen full of bricks on their screen dimensions.

By this point, you will realise that our bricks are explicitly linked to the users screen. And, if the user resizes the screen it will catastrophically destroy our gaming environment. And, there is a rule in programming.

If it can happen then at some point it will happen.

In short, we have to deal with this problem, and the simplest and quickest solution is to reset the grids when the player resizes the screen. And yes, that means that resizing the screen resets all the bricks including any the player may have destroyed at the point of resize. That sucks but then again, the dumb ass did resize the screen when they should have been killing bricks. They basically asked for it.

And there you have it. We’ve made a programming and gaming decision. That’s the programmers prerogative. Let’s move on.

More brick utility functions

At this point, we’ve done quite a lot of the brick logic but we still don’t see any bricks on our screen. And, we still can’t draw bricks because we still have some brick utility functions to deal with. Lets deal with those utilities now so we can see some god damn bricks.

Add the following two functions to the bottom of your Index.js file.

function rowColToArrayIndex(col, row) {
    return col + BRICK_COLS * row;
}

function isBrickAtColRow(col, row) {
    
    if (col >= 0 && col < BRICK_COLS &&
        row >= 0 && row < BRICK_ROWS) {
        
        var brickIndexUnderCoord = rowColToArrayIndex(col, row);
        return brickGrid[brickIndexUnderCoord];
    }
    else {
        return false;
    }
}

Okay, our brick grid is just an array of size brick columns multiplied by brick rows. So if we have a one hundred columns and six rows, we’ll have an array of six hundred bricks. The problem is our array doesn’t know about columns or rows, it just knows it has six hundred bricks.

So, if we need to find the brick on column ninety seven on row three we need a function to figure out where in the array that brick is. And, that is basically what the first function – rowColToArrayIndex – does for us. It accepts a column and a row value and works out where in the array that brick lives. It then sends that array index value back to us.

And, the second function – isBrickAtColRow – does something similar. It finds the array index for the specified column and row values. But instead of returning the array index value, it returns true if there is a brick there otherwise, it returns false.

Okay, that is all the utility work done. Its time to draw some bricks.

Drawing the JavaScript Breakout Brick Grid

Add the following function to the bottom of your Index.js file

function drawBricks() {
    for (let eachRow=0; eachRow<BRICK_ROWS; eachRow++) {
        for (let eachCol=0; eachCol<BRICK_COLS; eachCol++) {
            let arrayIndex = rowColToArrayIndex(eachCol, eachRow);
            if (brickGrid[arrayIndex] == true) {
                colorRect(BRICK_WIDTH*eachCol,BRICK_HEIGHT*eachRow, BRICK_WIDTH-BRICK_GAP,BRICK_HEIGHT-BRICK_GAP, paletteGrid[arrayIndex]);
            }
        }
    }
}

Once you have done that, update your drawEverything function with the new code shown below.

function drawEverything() {

    // Background color painted over the entire canvas.
    colorRect(0, 0, canvas.width, canvas.height, BACKGROUND_COLOR);
    
    // Paddle player
    colorRect(paddleX, canvas.height-PADDLE_DISTANCE_FROM_EDGE, PADDLE_WIDTH, PADDLE_THICKNESS, COLOR_WHITE);

    drawBricks(); // New code that will draw bricks on screen
}

Now run your game in the browser and voila! You have bricks on the screen and when you resize the browser you will see the bricks resetting.

The drawBricks function basically loops through each column in each row of the brick grid and adds a new brick with a colour specified in the brick colour grid. You then added that function to our drawEverything function which in turn, ensures that the bricks are drawn on the screen thirty times per second.

A quick recap or our JavaScript Breakout Brick Logic

So before we move on, lets briefly go over what you just did. First off, you wrote a function that would reset the brick and brick colour array which would be used in four different scenarios. You then used that function for two of those scenarios, game start and screen resize. Secondly, you wrote some utility function that could extract bricks from an array based on a specified row and column. And, finally, you used your brick utility methods and your graphic utility methods to draw your bricks on the screen.

And, that is it, you now have your player paddle and your bricks. The next thing we need is a ball.

Resetting, Moving and Drawing our Ball

Okay, as mentioned before, we have a player paddle and a grid full of multi-coloured bricks. Now we want to add the ball and have it move around the screen. Like the bricks, there are certain times when we’ll want to reset the ball, which basically means resetting the balls position on the screen. But before we do that, lets add some variables for our ball. Update your constant and variables section with the following code.

var ballX = 0; // New variables for our ball.
var ballY = 0;
var ballSpeedX = 0;
var ballSpeedY = 7;

Now that we have the variables for our ball, lets go ahead and create that ball reset function. Add the following code at the bottom of your Index.js file.

// Ball functions

function ballReset() {
    ballX = canvas.width/2;
    ballY = canvas.height/2;
    ballSpeedX = 0;
    ballSpeedY = 7;
}

Cool, we’ve got the ball variables and the ballReset function. Let’s put that ballReset function to good use.

Resetting the ball position on game load

You may have noticed that our ball x and y positions are set with a starting value of zero. If we left it like that, the ball would be stuck in the top corner and would destroy a ton of bricks before the player got to hit the ball. That obviously wont do so we need to position the ball before the game starts. Ideally, we want the ball in the middle of the screen and moving downwards.

The problem is we don’t know the screen size until the game loads. But, because you are a smart cookie, we do know when our game registers our canvas width. Yes, that’s right, we resize the screen when the window loads and therefore, we can reset the ball straight after the latter.

We do that by modifying our window.onload function as follows.

window.onload = function() {
    
    console.log('JavaScript Breakout v1.0.0');

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

    resize();

    setInterval(gameLoop, 1000/FRAMES_PER_SECOND);

    canvas.addEventListener('mousemove', updateMousePos);

    brickReset();

    // We can safely set the ball position at this point because
    // our canvas size has been set.
    ballReset(); 
}

Now when our game loads, it resizes the canvas and a few instructions later resets our ball to be in the middle of the canvas and moving towards the bottom of the screen.

Moving our JavaScript Breakout ball

Now that we have dealt with the balls start position. Lets create the ballMove function so we can have the ball moving around the screen. Add the following code to the bottom of your Index.js file.

function ballMove() {
    
    ballX += ballSpeedX;
    ballY += ballSpeedY;

    if (ballX < 0 && ballSpeedX < 0.0) { // left
        ballSpeedX *= -1;
    }
    if (ballX > canvas.width && ballSpeedX > 0.0) { // right
        ballSpeedX *= -1;
    }
    if (ballY < 0 && ballSpeedY < 0.0) { // top
        ballSpeedY *= -1;
    }
    if (ballY > canvas.height) { // bottom
        ballReset();
        brickReset();
    }
}

Cool, as you can see from our the above code, we move our ball by speedX and speedY. Then we do a number of checks.

  • Firstly, if the ball hits the left boundary – the left edge of the screen – the ball rebounds.
  • Secondly, if the ball hits the right boundary – the right edge of the screen – the ball rebounds.
  • Thirdly, if the ball hits the top boundary – the top edge of the screen – the ball rebounds.

And finally,

  • Finally, if the ball goes beyond the bottom boundary – the bottom edge of the screen – the ball and the bricks reset.

The latter is an indication that the player missed the ball and therefore the game resets.

Cool, but if you run the game, you will notice that we cant see the ball. That’s because we haven’t drawn it on the screen. Lets fix that now.

Drawing the JavaScript Breakout ball

Our ball, is basically a circle and because you wrote some useful graphic utilities earlier on in this project, we can utilise the colorCircle function to draw our ball on the screen. You can do that by updating your drawEverything function as demonstrated below.

function drawEverything() {

    // Background color painted over the entire canvas.
    colorRect(0, 0, canvas.width, canvas.height, BACKGROUND_COLOR);
    
    // Paddle player
    colorRect(paddleX, canvas.height-PADDLE_DISTANCE_FROM_EDGE, PADDLE_WIDTH, PADDLE_THICKNESS, COLOR_WHITE);

    drawBricks();

    // The function that draws our ball.
    colorCircle(ballX,ballY, 10, COLOR_WHITE);
}

Finally, update the moveEverything function as demonstrated below.

function moveEverything() {
    ballMove();
}

Cool. Now, when you run the game, you can watch in amazement as your ball moves off the bottom of the screen and resets the ball position and bricks. You can watch that happen all day, but it would be much more to hit that damned ball with the paddle.

Handling Ball and Paddle Collisions in JavaScript Breakout

Okay, we are getting close. Our balls moving but it ain’t colliding with our ball. Let’s get that done. Firstly, add the following function to the bottom of your Index.js file.

function ballPaddleHandling() {
    
    let paddleTopEdgeY = canvas.height - PADDLE_DISTANCE_FROM_EDGE;
    let paddleBottomEdgeY = paddleTopEdgeY + PADDLE_THICKNESS; 
    let paddleLeftEdgeX = paddleX;
    let paddleRightEdgeX = paddleLeftEdgeX + PADDLE_WIDTH;
    
    // Check if we have collided with the paddle.
    if (ballY > paddleTopEdgeY &&
        ballY < paddleBottomEdgeY &&
        ballX > paddleLeftEdgeX &&
        ballX < paddleRightEdgeX) {
        ballSpeedY *= -1;
        
        // Changes x speed based on where the ball collides with the paddle.
        // This technique gives the player some ball control.
        let centerOfPaddleX = paddleX + PADDLE_WIDTH / 2;
        let ballDistFromPaddleCenterX = ballX - centerOfPaddleX;
        ballSpeedX = ballDistFromPaddleCenterX * 0.35;
        if (bricksLeft == 0) {
            brickReset();
        }
    } 
}

Secondly, add the function we just created to our moveEverything function as demonstrated below.

function moveEverything() {
    ballMove();
    ballPaddleHandling(); // Neew ball paddle collision handling function.
}

Now, run the game and you’ll see that you can hit the ball with the paddle. Sweet!

So, what we did here is we wrote a function that checks for collisions between the ball and the paddle. If the function detects a collision it rebounds the ball. And, for that collision to be detected, we needed to add the function to the moveEverything function. Now our ball paddle collision detecting code runs thirty times a second and rebounds the ball when a collision happens.

Thus, our ball and paddle interact which has brought us close to having something that looks and acts like a game. Lets improve the game interaction for detecting collision between the ball and the bricks.

Handling Ball and Brick Collisions in JavaScript Breakout

Okay, the process is kind of similar, so lets get the ball brick collision detecting function coded and called in our moveEverything function. Start by adding the following code to the bottom of your Index.js file.

function ballBrickHandling() {
    
    let ballBrickCol = Math.floor(ballX / BRICK_WIDTH);
    let ballBrickRow = Math.floor(ballY / BRICK_HEIGHT);
    let brickIndexUnderBall = rowColToArrayIndex(ballBrickCol, ballBrickRow);
    
    if (ballBrickCol >= 0 && ballBrickCol < BRICK_COLS &&
        
        ballBrickRow >= 0 && ballBrickRow < BRICK_ROWS) {
        if (isBrickAtColRow(ballBrickCol, ballBrickRow)) {
            
            brickGrid[brickIndexUnderBall] = false;
            bricksLeft--;

            let prevBallX = ballX - ballSpeedX;
            let prevBallY = ballY - ballSpeedY;
            let prevBrickCol = Math.floor(prevBallX / BRICK_WIDTH);
            let prevBrickRow = Math.floor(prevBallY / BRICK_HEIGHT);
            let bothTestsFailed = true;
            
            if (prevBrickCol != ballBrickCol) {
                if (isBrickAtColRow(prevBrickCol, ballBrickRow) == false) {
                    ballSpeedX *= -1;
                    bothTestsFailed = false;
                }
            }
            if (prevBrickRow != ballBrickRow) {
                
                if (isBrickAtColRow(ballBrickCol, prevBrickRow) == false) {
                    ballSpeedY *= -1;
                    bothTestsFailed = false;
                }
            }
            if (bothTestsFailed) { // The armpit scenario
                ballSpeedX *= -1;
                ballSpeedY *= -1;
            }
            
        }
    }
}

Now add the function we just created to the moveEverything function as demonstrated below.

function moveEverything() {
    ballMove();
    ballPaddleHandling(); 
    ballBrickHandling(); // New ball brick collision handling function.
}

If you save the changes and run the game, you’ll be playing JavaScript Breakout. Give yourself a pat on the back but before we go, lets look a little closer at the ball brick collision logic.

The ball and brick collision detecting logic

Okay, lets go over the logic in our ballBrickHandling function.

First off, we translate the column and row index for our balls current position. Secondly, we then check to see if the translated column and row index is within the current brick grid area. If it is, then it means our ball is in the grid area. We then find the brick and set it to false. And, when we draw our bricks, we omit any bricks that are set to false. Thus, to the gamer, it looks like the brick has been destroyed.

We also do a little check to prevent a glitch in collisions were the ball may have collided with more than one brick. And finally, like our ball paddling collisions we do this check thirty time per second and thus give the illusion of interaction between the game actors.

And that is it. You have built the basics that make up JavaScript Breakout. You can now enjoy the fruits of your labor. However, before we go, every good coder looks for ways to improve their work. And, you should treat this project no differently.

Taking JavaScript Breakout to the Next Level

We’ve got the game to a decent point. You can now interact with the game and try and destroy all the bricks. It is essentially JavaScript Breakout. But, you could do more, you can always do more, so here are some suggestions for taking JavaScript Breakout to the next level.

#1 Increase the frame rate

We’ve set the frame rate to thirty frames per second but that is the bare minimum. Try bumping up the rate to see if it improves the game. Note, you may need to change the speed of the ball.

#2 Add a scoring mechanism

You could add give the player points every time they destroy a brick. How would you go about scoring and where and how would you display that score on the screen.

#3 Add a game over screen before we reset

If the ball passes the paddle or the player destroys all the bricks, the game immediately resets. A good game would show a game over message and the players score. The player would then have to trigger the game to restart. How would you do that?

#4 Give the player three strikes

The game is pretty hard because one slip up and the bricks reset. You could give the player some breathing space by giving them three lives. That way, when the player misses the ball, they lose a life and on the third miss, the lose the game. How would you add in player lives into the games logic.

#5 Add some audio to enhance the experience

Adding sound would really enhance the game. How would you add sound to the game and how would you make sure that the sound clips were properly loaded before the game began?

#6 Its your game

Finally, its your game. You coded it, you own it and you can do whatever you like with JavaScript Breakout. Go wild and be creative. That is the beauty of coding your own games.

Have fun and keeping coding

And we are done here. You have created JavaScript Breakout. You have the beginnings of a game that you can push in any direction you want. And you have learned the basics of JavaScript game programming and can use that to produce whatever takes your fancy.

Have fun, keep coding, keep creating.