HTML5 Breakout Game

Here is fun HTML5 version of the classic retro computer game Breakout. Use the paddle to direct the ball to hit all the yellow bricks, using either the left/right arrow keys or the mouse.

If you are not aware, HTML5 is a terms usually used to describe the combination of the 5th official standard of HTML, or Hyper Text Markup Language, along with JavaScript and CSS to create visually stunning dynamic and interactive web-pages and applications.

It might be a bold statement, but I would say that

knowing JavaScript is as important for people wanting to work in software development as speaking English is for international business and communication.

Anther bold claim I would make is that WordPress is such a significant technology that it really should be included in school computing courses. I say this because it is the platform behind nearly a third of the entire internet (including this website!). It can be studied at many different levels and with many different angles, such as as a business tool, or a blogging platform or as a code base for developers to bend to their will.

Python is an awesome programming language and is the primary focus of this blog. However in the name of providing a more rounded perspective of the kinds of skills and technologies you will need to master for a successful career in computing, I will occasionally branch out into other topics, such as in this post.

In terms of WordPress, all I want to point out here is the there is a very easy way to add JavaScript and CSS code to a blog post using a plugin called Scripts n Styles. There are other ways to do this, for example enqueuing scripts and stylesheets through your theme’s functions.php file or via a plugin, but there are many situations where that is unnecessarily complex and the Scripts n Styles solution works just fine. One point to mention is that unless you want to wrap your JavaScript code in some kind of document.ready function, then it should be placed at the end of the <body> element – an option provided by the plugin.

OK so, it’s a bit of a hotchpotch of different themes in this article, but hopefully there is something in it that you will find useful or interesting. I have provided the HTML5 code for the Breakout game below. This is not an actual tutorial on how to build the game, but there are some comments to help you understand what is going on. You can run it yourself locally by copy/pasting the code into your favourite text editor, saving as something like game.html and navigating to that file in your browser.

Complete code listing for HTML5 Retro Breakout Game

<!DOCTYPE html>
<html>
    <head>
    <title>Breakout Game with HTML5</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        canvas { 
        background: green;
        display: block;
        margin: auto;
        }
    </style>
    </head>
    <body>
    <canvas id="myCanvas" width="480" height="320"></canvas>
    <script>
        'use strict';
        const canvas = document.getElementById( "myCanvas" );
        const ctx = canvas.getContext( "2d" );
        const ballRadius = 10;
        const paddleHeight = 10;
        const paddleWidth = 75;
        const numBrickColumns = 5;
        const numBrickRows = 3;
        const brickWidth = 75;
        const brickHeight = 20;
        const brickPadding = 10;
        const brickOffsetTop = 30;
        const brickOffsetLeft = 30;
        let ballX;
        let ballY;
        let dx = 2;
        let dy = -2;
        let score;
        let lives;
        let bricks;
        let playing = true;
        let paddleX;
        let rightPressed;
        let leftPressed;

// Assign callbacks
        document.addEventListener( "keydown", keyDownHandler, false );
        document.addEventListener( "keyup", keyUpHandler, false );
        document.addEventListener( "mousemove", mouseMoveHandler, false );
        canvas.addEventListener( 'click', restart, false );

        function restart() {
        // Unbind click handler for canvas to avoid multiple restarts.
        canvas.removeEventListener( 'click', restart, false );

        // Create bricks (2d array)
        bricks = [];
        for ( var rowNum = 0; rowNum < numBrickRows; rowNum++ ) {
            bricks[rowNum] = [];
            for ( var colNum = 0; colNum < numBrickColumns; colNum++ ) {
            bricks[rowNum][colNum] = {x: 0, y: 0, status: 1};
            }
        }

        // Initial game values
        paddleX = ( canvas.width - paddleWidth ) / 2;
        ballX = canvas.width / 2;
        ballY = canvas.height - 30;
        playing = true;
        score = 0;
        lives = 3;
        rightPressed = false;
        leftPressed = false;

        // Start animation
        draw();
        }

        function keyDownHandler( e ) {
        if ( e.key == "Right" || e.key == "ArrowRight" ) {
            rightPressed = true;
        } else if ( e.key == "Left" || e.key == "ArrowLeft" ) {
            leftPressed = true;
        }
        }

        function keyUpHandler( e ) {
        if ( e.key == "Right" || e.key == "ArrowRight" ) {
            rightPressed = false;
        } else if ( e.key == "Left" || e.key == "ArrowLeft" ) {
            leftPressed = false;
        }
        }

        function mouseMoveHandler( e ) {
        var relativeX = e.clientX - canvas.offsetLeft;
        if ( relativeX > 0 && relativeX < canvas.width ) {
            paddleX = relativeX - paddleWidth / 2;
        }
        }
        function collisionDetection() {
        for ( var rowNum = 0; rowNum < numBrickRows; rowNum++ ) {
            for ( var colNum = 0; colNum < numBrickColumns; colNum++ ) {
            var b = bricks[rowNum][colNum];
            if ( b.status == 1 ) {
                if ( ballX > b.x && ballX < b.x + brickWidth && ballY > b.y && ballY < b.y + brickHeight ) {
                dy = -dy;
                b.status = 0;
                score++;
                if ( score == numBrickColumns * numBrickRows ) {
                    playing = false;
                    ctx.textAlign = "center";
                    ctx.font = "24px Comic Sans MS";
                    ctx.fillStyle = '#fff';
                    ctx.fillText( "You won!", 240, 140 );
                    ctx.fillText( "Click on the canvas to play again.", 240, 180 );
                    canvas.addEventListener( 'click', restart, false );
                }
                }
            }
            }
        }
        }

        function drawBall() {
        ctx.beginPath();
        ctx.arc( ballX, ballY, ballRadius, 0, Math.PI * 2 );
        ctx.fillStyle = "magenta";
        ctx.fill();
        ctx.closePath();
        }
        function drawPaddle() {
        ctx.beginPath();
        ctx.rect( paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight );
        ctx.fillStyle = "red";
        ctx.fill();
        ctx.closePath();
        }
        function drawBricks() {
        for ( var rowNum = 0; rowNum < numBrickRows; rowNum++ ) {
            for ( var colNum = 0; colNum < numBrickColumns; colNum++ ) {
            if ( bricks[rowNum][colNum].status == 1 ) {
                var brickX = ( colNum * ( brickWidth + brickPadding ) ) + brickOffsetLeft;
                var brickY = ( rowNum * ( brickHeight + brickPadding ) ) + brickOffsetTop;
                bricks[rowNum][colNum].x = brickX;
                bricks[rowNum][colNum].y = brickY;
                ctx.beginPath();
                ctx.rect( brickX, brickY, brickWidth, brickHeight );
                ctx.fillStyle = "yellow";
                ctx.fill();
                ctx.closePath();
            }
            }
        }
        }
        function drawScore() {
        ctx.textAlign = "left";
        ctx.font = "16px Comic Sans MS";
        ctx.fillStyle = "white";
        ctx.fillText( "Score: " + score, 8, 20 );
        }
        function drawLives() {
        ctx.textAlign = "left";
        ctx.font = "16px Comic Sans MS";
        ctx.fillStyle = "white";
        ctx.fillText( "Lives: " + lives, canvas.width - 65, 20 );
        }

        function draw() {
        ctx.clearRect( 0, 0, canvas.width, canvas.height );
        drawBricks();
        drawBall();
        drawPaddle();
        drawScore();
        drawLives();
        collisionDetection();

        if ( ballX + dx > canvas.width - ballRadius || ballX + dx < ballRadius ) {
            dx = -dx;
        }
        if ( ballY + dy < ballRadius ) {
            dy = -dy;
        } else if ( ballY + dy > canvas.height - ballRadius ) {
            if ( ballX > paddleX && ballX < paddleX + paddleWidth ) {
            dy = -dy;
            } else {
            lives--;
            if ( !lives ) {
                playing = false;
                ctx.textAlign = "center";
                ctx.font = "24px Comic Sans MS";
                ctx.fillStyle = '#fff';
                ctx.fillText( "Bad luck. You are out of lives!", 240, 140 );
                ctx.fillText( "Click on the canvas to play again.", 240, 180 );
                canvas.addEventListener( 'click', restart, false );
            } else {
                ballX = canvas.width / 2;
                ballY = canvas.height - 30;
                dx = 3;
                dy = -3;
                paddleX = ( canvas.width - paddleWidth ) / 2;
            }
            }
        }

        if ( rightPressed && paddleX < canvas.width - paddleWidth ) {
            paddleX += 7;
        } else if ( leftPressed && paddleX > 0 ) {
            paddleX -= 7;
        }

        ballX += dx;
        ballY += dy;
        if ( playing ) {
            requestAnimationFrame( draw );
        }
        }

        restart();
    </script>
    </body>
</html>

Happy computing!

Sharing is caring!

Leave a Reply

Your email address will not be published. Required fields are marked *