JavaScript Bouncing Ball Game 2D (CSS, HTML & JAVASCRIPT)

JavaScript Bouncing Ball Game (CSS, HTML & JAVASCRIPT)

Welcome to another tutorial, where we’re going to create a game called “2D JavaScript Bouncing Ball Game” using JavaScript,HTML and CSS, the tutorial is created especially for beginners in JavaScript. We will discuss the logic behind every line of code, And try to break down things as much as we can.

Video: JavaScript Bouncing Ball Game 2D

Project Folder Structure:

Now before we move on to actual coding we create a project folder structure. We name the project folder as ”Bouncing Ball ”. Within this folder we have 3 files. These files are:

  • index.html
  • style.css
  • script.js

HTML Code

The HTML document structure is quite minimal, as the game will be rendered entirely on the <canvas> element. Using your favorite text editor, create a new HTML document, save it as index.html, in a sensible location, and add the following code to it:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bouncing Ball</title>
    <!-- Stylesheet -->
    <link rel="stylesheet" href="style.css">
  </head>
  <body>   
    <H1>Nijaa.com</H1>
        <!-- Further code here -->
        <canvas id="mycanvas" width="650" height="450">
            <!--Fallback Content-->
        </canvas>

  <script src="script.js"></script>
  </body>
</html>Code language: HTML, XML (xml)

We have a charset defined,  and some basic CSS in the header. The body contains  <canvas>  and  <script>  elements — we will render the game inside the first one and write the JavaScript code that controls it in the second one. The <canvas> element has an id of myCanvas to allow us to easily grab a reference to it, and it is 650 pixels wide and 450 pixels high.

CSS Code

The CSS code styles the game elements, providing visual effects and animations to enhance the user experience. copy the ensuing code and insert it into your stylesheet.

body {
  min-height: 100vh;  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgb(187, 194, 86);
}
h1{
  position: absolute;
  padding-top: 1rem;
  top: 0;
  right: 50;
  color: rgb(255, 0, 0);
  font-weight: 700;
  text-shadow: 1px 1px 5px black;
}

#mycanvas {
  background-color: black;
  margin-top: 2rem;
}Code language: CSS (css)

JS Code

Finally, we add functionality using Javascript. copy the code below and paste it into your script file.

//Create variables to reference and store canvas 
let canvas = document.getElementById('mycanvas');
let ctx = canvas.getContext('2d');
let ballRadius = 10;
let x = canvas.width / 2;
let y = canvas.height - 30;
let dx = 2;
let dy = -2;

//create the paddle
let paddleHeight = 12;
let paddleWidth = 72;

//specify starting point of paddle
let paddleX = (canvas.width - paddleWidth) / 2;

//holding variables for right and left arrows on keyboard
let rightPressed = false;
let leftPressed = false;

//holding variables for bricks
let brickRowCount = 4;
let brickColumnCount = 7;
let brickWidth = 72;
let brickHeight = 24;
let brickPadding = 12;
let brickOffsetTop = 32;
let brickOffsetLeft = 32;
//Create variables to take score
let score = 0;

//Creating arrays for the bricks
let bricks = [];
for (c = 0; c < brickColumnCount; c++) {
    bricks[c] = [];
    for (r = 0; r < brickRowCount; r++) {
        //set the x and y position of the bricks
        bricks[c][r] = { x: 0, y: 0, status: 1 };
    }
}

document.addEventListener('keydown', keyDownHandler, false);
document.addEventListener('keyup', keyUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);

//Anchor paddle movement to mouse movement
function mouseMoveHandler(e) {
    var relativeX = e.clientX - canvas.offsetLeft;
    if (relativeX > 0 && relativeX < canvas.width) {
        paddleX = relativeX - paddleWidth / 2;
    }
}

function keyDownHandler(e) {
    if (e.keyCode === 39) {
        rightPressed = true;
    }
    else if (e.keyCode === 37) {
        leftPressed = true;
    }
}
function keyUpHandler(e) {
    if (e.keyCode === 39) {
        rightPressed = false;
    }
    else if (e.keyCode === 37) {
        leftPressed = false;
    }
}

function drawBall() {
    ctx.beginPath();
    ctx.arc(x, y, ballRadius, 0, Math.PI * 2); //centered at (x,y) position with radius r = ballRadius starting at 0 = startAngle, ending at Math.PI*2 = endAngle (in Radians)
    ctx.fillStyle = 'lawngreen';
    ctx.fill();
    ctx.closePath();
}
//Create a function to create the paddle
function drawPaddle() {
    ctx.beginPath();
    ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight); //centered at (x,y) position with radius r = ballRadius starting at 0 = startAngle, ending at Math.PI*2 = endAngle (in Radians)
    ctx.fillStyle = 'lawngreen';
    ctx.fill();
    ctx.closePath();
}
//Create a function to draw the bricks
function drawBricks() {
    for (c = 0; c < brickColumnCount; c++) {
        for (r = 0; r < brickRowCount; r++) {
            if (bricks[c][r].status === 1) {
                let brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
                let brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop;
                bricks[c][r].x = brickX;
                bricks[c][r].y = brickY;
                ctx.beginPath();
                ctx.rect(brickX, brickY, brickWidth, brickHeight);
                ctx.fillStyle = '#ff0000';
                ctx.fill();
                ctx.closePath();
            }
        }
    }
}
//Create function to keep track of score
function drawScore() {
    ctx.font = '18px Arial';
    ctx.fillStyle = 'white';
    ctx.fillText('score: ' + score, 8, 20); //position score at 8,20 on the x,y axis of the canvas
}

//Collision dections for the bricks
function collisionDetection() {
    for (c = 0; c < brickColumnCount; c++) {
        for (r = 0; r < brickRowCount; r++) {
            let b = bricks[c][r];
            if (b.status === 1) {
                if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) {
                    dy = -dy;
                    b.status = 0;
                    score++;
                    if (score === brickRowCount * brickColumnCount) {
                        alert('Congratulations!! You\'ve won!');
                        document.location.reload();
                    }
                }
            }
        }
    }
}

function draw() {
    //clear each instance of the canvas so a new circle can be drawn
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawScore();
    drawBricks();
    drawBall();
    drawPaddle();
    collisionDetection();
    //Calculate collision detections
    //left and right walls
    if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
        dx = -dx;
    }
    //top walls
    if (y + dy < ballRadius) {
        dy = -dy;
    }
    else if (y + dy > canvas.height - ballRadius) {
        //detect paddle hits
        if (x > paddleX && x < paddleX + paddleWidth) {
            dy = -dy;
        }
        //if no paddle hit, body of canvas is hit ==> game over
        else {
            alert('GAME OVER!!');
            document.location.reload();
        }
    }

    //bottom wall
    if (y + dy > canvas.height - ballRadius || y + dy < ballRadius) {
        dy = -dy;
    }
    //Make paddle move
    if (rightPressed && paddleX < canvas.width - paddleWidth) {
        paddleX += 7;
    }
    else if (leftPressed && paddleX > 0) {
        paddleX -= 7;
    }
    //Making the ball move
    x += dx; //update x movement every frame
    y += dy; //update y movement every frame
}

setInterval(draw, 10)Code language: JavaScript (javascript)

Canvas basics

To actually be able to render graphics on the <canvas> element, first we have to grab a reference to it in JavaScript.

const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");Code language: JavaScript (javascript)

Here we’re storing a reference to the <canvas> element to the canvas variable. Then we’re creating the ctx variable to store the 2D rendering context — the actual tool we can use to paint on the Canvas.

let ballRadius = 10;
let x = canvas.width / 2;
let y = canvas.height - 30;
let dx = 2;
let dy = -2;Code language: JavaScript (javascript)

Here, we define properties related to the ball in our game. For example, ballRadius specifies the size of the ball, x and y represent its initial position, and dx and dy represent its horizontal and vertical speeds respectively.

let paddleHeight = 12;
let paddleWidth = 72;
let paddleX = (canvas.width - paddleWidth) / 2;Code language: JavaScript (javascript)

These lines define properties related to the paddle. Similar to the ball, we specify its height, width, and initial position on the canvas.

let rightPressed = false;
let leftPressed = false;Code language: JavaScript (javascript)

These variables are used to track whether the right or left arrow keys are currently pressed on the keyboard, allowing us to control the paddle’s movement.

let brickRowCount = 4;
let brickColumnCount = 7;
let brickWidth = 72;
let brickHeight = 24;
let brickPadding = 12;
let brickOffsetTop = 32;
let brickOffsetLeft = 32;Code language: JavaScript (javascript)

These variables define properties of the bricks in the game, such as the number of rows and columns, their size, and spacing.

let bricks = [];
for (c = 0; c < brickColumnCount; c++) {
    bricks[c] = [];
    for (r = 0; r < brickRowCount; r++) {
        bricks[c][r] = { x: 0, y: 0, status: 1 };
    }
}Code language: JavaScript (javascript)

Here, we initialize an array to hold the brick positions and status. This loop populates the array with bricks, each having an x and y position, and a status indicating whether it’s visible (1) or not (0).

document.addEventListener('keydown', keyDownHandler, false);
document.addEventListener('keyup', keyUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);
Code language: JavaScript (javascript)

These lines set up event listeners to detect keydown, keyup, and mousemove events. They call corresponding functions (keyDownHandler, keyUpHandler, and mouseMoveHandler) when these events occur, allowing us to respond to user input.

function mouseMoveHandler(e) {
    var relativeX = e.clientX - canvas.offsetLeft;
    if (relativeX > 0 && relativeX < canvas.width) {
        paddleX = relativeX - paddleWidth / 2;
    }
}Code language: JavaScript (javascript)

This function is responsible for handling mouse movement. It calculates the relative position of the mouse within the canvas and adjusts the paddle’s position accordingly, ensuring it follows the mouse horizontally.

function keyDownHandler(e) {
    if (e.keyCode === 39) {
        rightPressed = true;
    }
    else if (e.keyCode === 37) {
        leftPressed = true;
    }
}Code language: JavaScript (javascript)

Here, we handle keydown events for the right and left arrow keys. When the right arrow key is pressed, rightPressed becomes true, and similarly for the left arrow key.

function keyUpHandler(e) {
    if (e.keyCode === 39) {
        rightPressed = false;
    }
    else if (e.keyCode === 37) {
        leftPressed = false;
    }
}Code language: JavaScript (javascript)

This function handles keyup events for the arrow keys, setting rightPressed or leftPressed to false when the respective arrow key is released.

function drawBall() {
    ctx.beginPath();
    ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
    ctx.fillStyle = 'lawngreen';
    ctx.fill();
    ctx.closePath();
}Code language: JavaScript (javascript)

This function draws the ball on the canvas using the arc method to create a circular path. It sets the ball’s color and fills it.

function drawPaddle() {
    ctx.beginPath();
    ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
    ctx.fillStyle = 'lawngreen';
    ctx.fill();
    ctx.closePath();
}Code language: JavaScript (javascript)

Similar to drawBall, this function draws the paddle on the canvas using the rect method to create a rectangle path. It also sets the paddle’s color and fills it.

function drawBricks() {
    // Drawing bricks on the canvas
}Code language: JavaScript (javascript)

This function is responsible for drawing all the bricks on the canvas based on their positions and status. It loops through the bricks array and draws each visible brick using the rect method.

function drawScore() {
    // Drawing the score on the canvas
}Code language: JavaScript (javascript)

Here, we draw the current score on the canvas. It sets the font, color, and position of the score text using the fillText method.

function collisionDetection() {
    // Handling collision detection between the ball and bricks
}Code language: JavaScript (javascript)

This function checks for collisions between the ball and bricks. If a collision is detected, it changes the ball’s direction, updates the brick’s status, and increases the player’s score. If all bricks are destroyed, it displays a winning message.

function draw() {
    // Drawing the game elements and handling game logic
}Code language: JavaScript (javascript)

Finally, this function is the heart of the game. It’s called repeatedly to update the game state, draw all elements on the canvas, handle collisions, and respond to user input. It essentially runs the game loop.

In summary, the draw function is responsible for updating the game state and drawing all game elements on the canvas. It clears the canvas, draws the score, bricks, ball, and paddle, handles collisions with walls and the paddle, moves the paddle based on user input, and updates the position of the ball for the next frame. This function is repeatedly called at a specified interval (every 10 milliseconds) to create an animation effect and keep the game running smoothly.

Leave a Reply

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