๐ฎ Building a Brick Breaker Game with JavaScript
๐ Game Structure
๐ HTML Layout
The game consists of a container (div.container
) that holds the game elements:
- Score & Lives Counter
- Start Game Message
- Ball (
div.ball
) - Paddle (
div.paddle
) - Bricks (
div.brick
)
<div>Score: <span class="score">0</span> | Lives: <span class="lives">3</span></div>
<div class="container">
<div class="game-message">Start Game</div>
<div class="ball"></div>
<div class="paddle"></div>
</div>
The game-message div appears initially, allowing players to start the game when they click it.
๐จ CSS Styling
The CSS ensures that:
โ The paddle stays at the bottom
โ The ball is round and positioned at the start
โ The bricks are dynamically created
โ The game container keeps everything inside the screen
.container {
height: 400px;
width: 80%;
margin: 20px auto;
overflow: hidden;
border: 2px solid white;
position: relative;
background-color: darkgrey;
}
.paddle {
position: absolute;
width: 100px;
height: 20px;
background-color: white;
border-radius: 10px;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
}
.ball {
position: absolute;
width: 20px;
height: 20px;
background-color: white;
border-radius: 50%;
top: 70%;
left: 50%;
display: none;
}
๐ฎ JavaScript Logic: Making the Game Work
๐ Game Variables
These variables track the game state:
const player = {
gameover: true,
score: 0,
lives: 3,
inPlay: false,
ballSpeedX: 3, // Ball X speed
ballSpeedY: -5, // Ball Y speed
paddleSpeed: 6, // Paddle movement speed
numBricks: 40 // Number of bricks
};
gameover
โ Indicates whether the game is running or endedscore
โ Tracks the number of bricks hitlives
โ Reduces when the ball falls offballSpeedX
,ballSpeedY
โ Controls ball movementpaddleSpeed
โ Sets paddle movement speednumBricks
โ Determines how many bricks appear
๐ฏ Handling Player Input
The keyboard events move the paddle and start the game.
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') paddle.movingLeft = true;
if (e.key === 'ArrowRight') paddle.movingRight = true;
if (e.key === 'ArrowUp' && !player.inPlay) player.inPlay = true;
});
document.addEventListener('keyup', (e) => {
if (e.key === 'ArrowLeft') paddle.movingLeft = false;
if (e.key === 'ArrowRight') paddle.movingRight = false;
});
โ Left and Right arrow keys move the paddle
โ Up arrow key launches the ball
๐ Starting the Game
When the player clicks the start message, the game initializes:
function startGame() {
if (player.gameover) {
player.gameover = false;
gameMessage.style.display = "none";
player.score = 0;
player.lives = 3;
player.inPlay = false;
ball.style.display = "block";
resetBallPosition();
setupBricks();
updateScore();
player.animationFrame = requestAnimationFrame(updateGame);
}
}
โ Hides the start message
โ Resets the score & lives
โ Creates new bricks
โ Starts the animation loop (updateGame
)
โก Moving the Paddle
Ensures the paddle stays inside the game container:
function movePaddle() {
let currentPos = paddle.offsetLeft;
// Prevent paddle from moving off the screen
if (paddle.movingLeft && currentPos > 0) {
currentPos -= player.paddleSpeed;
if (currentPos < 0) currentPos = 0;
}
if (paddle.movingRight && currentPos < (containerBounds.width - paddle.offsetWidth)) {
currentPos += player.paddleSpeed;
if (currentPos > containerBounds.width - paddle.offsetWidth) {
currentPos = containerBounds.width - paddle.offsetWidth;
}
}
paddle.style.left = `${currentPos}px`;
}
โ Prevents the paddle from moving offscreen
โ Moves left or right based on player input
๐ต Moving the Ball
Handles ball movement and collisions:
function moveBall() {
let posBall = { x: ball.offsetLeft, y: ball.offsetTop };
if (posBall.y > (containerBounds.height - 20)) {
player.lives--;
if (player.lives <= 0) endGame();
updateScore();
player.inPlay = false;
return;
}
if (posBall.y < 0) player.ballSpeedY *= -1;
if (posBall.x > (containerBounds.width - 20) || posBall.x < 0) player.ballSpeedX *= -1;
if (isCollide(paddle, ball)) {
let hitPos = (posBall.x - paddle.offsetLeft) / paddle.offsetWidth;
player.ballSpeedX = (hitPos - 0.5) * 6;
player.ballSpeedY = -Math.abs(player.ballSpeedY);
}
document.querySelectorAll('.brick').forEach(brick => {
if (isCollide(brick, ball)) {
player.ballSpeedY *= -1;
brick.remove();
player.score++;
updateScore();
}
});
ball.style.left = `${posBall.x + player.ballSpeedX}px`;
ball.style.top = `${posBall.y + player.ballSpeedY}px`;
}
โ Ball bounces off walls, paddle, and bricks
โ Brick disappears when hit
โ Ball always bounces up after hitting the paddle
๐ Winning & Losing
- If player loses all lives, the game ends:
function endGame() {
gameMessage.style.display = "block";
gameMessage.innerHTML = `Game Over<br>Your score: ${player.score}`;
player.gameover = true;
ball.style.display = "none";
cancelAnimationFrame(player.animationFrame);
}
๐ Conclusion: How It All Works
Game Flow:
1๏ธโฃ Start the game โ Click “Start Game”
2๏ธโฃ Paddle moves โ Controlled by left/right keys
3๏ธโฃ Ball moves & bounces โ Off paddle, walls, and bricks
4๏ธโฃ Bricks disappear โ When hit by the ball
5๏ธโฃ Lose a life โ If the ball falls below the paddle
6๏ธโฃ Win or lose โ Game ends if all bricks are cleared or lives reach 0
This Brick Breaker game demonstrates JavaScriptโs ability to create interactive browser-based games with dynamic movement, collision detection, and event-driven controls.
๐ฅ Try modifying the game! Customize speed, brick layout, colors, or paddle size to make it your own. ๐๐ฎ
If you’ve been working on a Brick Breaker-style game, you may have encountered outdated JavaScript features. In this blog post, weโll modernize the code by replacing deprecated features, improving readability, and making it more efficient.
๐ง Key Improvements
- Replace
e.keyCode
withe.key
- Remove PNG-based ball image and use CSS styles instead
- Use CSS classes instead of inline styles for dynamically created elements
- Improve readability and maintainability

๐ฎ Updated Brick Breaker Game Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brick Breaker Game</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
background-color: #222;
color: white;
}
.container {
height: 400px;
width: 80%;
margin: 20px auto;
overflow: hidden;
border: 2px solid white;
position: relative;
background-color: darkgrey;
}
.score,
.lives {
font-size: 2em;
margin: 10px;
}
.brick {
position: absolute;
width: 80px;
height: 30px;
color: white;
border: 1px solid white;
font-size: 1.4em;
text-align: center;
line-height: 30px;
background-color: #ff5722;
}
.game-message {
position: absolute;
width: 100%;
height: 100px;
text-align: center;
font-size: 2em;
line-height: 100px;
background-color: red;
cursor: pointer;
top: 50%;
transform: translateY(-50%);
}
.ball {
position: absolute;
width: 20px;
height: 20px;
background-color: white;
border-radius: 50%;
top: 70%;
left: 50%;
display: none;
}
.paddle {
position: absolute;
width: 100px;
height: 20px;
background-color: white;
border-radius: 10px;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
}
</style>
</head>
<body>
<div>Score: <span class="score">0</span> | Lives: <span class="lives">3</span></div>
<div class="container">
<div class="game-message">Start Game</div>
<div class="ball"></div>
<div class="paddle"></div>
</div>
<script>
const container = document.querySelector('.container');
const gameMessage = document.querySelector('.game-message');
const ball = document.querySelector('.ball');
const paddle = document.querySelector('.paddle');
const scoreDisplay = document.querySelector('.score');
const livesDisplay = document.querySelector('.lives');
let containerBounds = container.getBoundingClientRect();
const player = {
gameover: true,
score: 0,
lives: 3,
inPlay: false,
ballSpeedX: 3,
ballSpeedY: -5,
paddleSpeed: 6,
numBricks: 40
};
gameMessage.addEventListener('click', startGame);
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') paddle.movingLeft = true;
if (e.key === 'ArrowRight') paddle.movingRight = true;
if (e.key === 'ArrowUp' && !player.inPlay) player.inPlay = true;
});
document.addEventListener('keyup', (e) => {
if (e.key === 'ArrowLeft') paddle.movingLeft = false;
if (e.key === 'ArrowRight') paddle.movingRight = false;
});
function startGame() {
if (player.gameover) {
player.gameover = false;
gameMessage.style.display = "none";
player.score = 0;
player.lives = 3;
player.inPlay = false;
ball.style.display = "block";
resetBallPosition();
setupBricks();
updateScore();
player.animationFrame = requestAnimationFrame(updateGame);
}
}
function resetBallPosition() {
ball.style.left = `${paddle.offsetLeft + paddle.offsetWidth / 2 - 10}px`;
ball.style.top = `${paddle.offsetTop - 20}px`;
}
function setupBricks() {
document.querySelectorAll('.brick').forEach(brick => brick.remove());
let row = { x: 10, y: 50 };
let bricksPerRow = Math.floor(containerBounds.width / 90);
let totalRows = Math.ceil(player.numBricks / bricksPerRow);
for (let i = 0; i < player.numBricks; i++) {
if (i % bricksPerRow === 0 && i !== 0) {
row.y += 40;
row.x = 10;
}
createBrick(row, i);
row.x += 90;
}
}
function createBrick(pos, index) {
const brick = document.createElement('div');
brick.classList.add('brick');
brick.style.backgroundColor = getRandomColor();
brick.textContent = index + 1;
brick.style.left = `${pos.x}px`;
brick.style.top = `${pos.y}px`;
container.appendChild(brick);
}
function updateGame() {
if (!player.gameover) {
movePaddle();
player.inPlay ? moveBall() : resetBallPosition();
player.animationFrame = requestAnimationFrame(updateGame);
}
}
function movePaddle() {
let currentPos = paddle.offsetLeft;
// Prevent paddle from moving off the screen
if (paddle.movingLeft && currentPos > 0) {
currentPos -= player.paddleSpeed;
if (currentPos < 0) currentPos = 0;
}
if (paddle.movingRight && (currentPos < containerBounds.width - paddle.offsetWidth)) {
currentPos += player.paddleSpeed;
if (currentPos > containerBounds.width - paddle.offsetWidth) {
currentPos = containerBounds.width - paddle.offsetWidth;
}
}
paddle.style.left = `${currentPos}px`;
}
function moveBall() {
let posBall = { x: ball.offsetLeft, y: ball.offsetTop };
if (posBall.y > (containerBounds.height - 20)) {
player.lives--;
if (player.lives <= 0) endGame();
updateScore();
player.inPlay = false;
return;
}
if (posBall.y < 0) player.ballSpeedY *= -1;
if (posBall.x > (containerBounds.width - 20) || posBall.x < 0) player.ballSpeedX *= -1;
if (isCollide(paddle, ball)) {
let hitPos = (posBall.x - paddle.offsetLeft) / paddle.offsetWidth;
player.ballSpeedX = (hitPos - 0.5) * 6;
player.ballSpeedY = -Math.abs(player.ballSpeedY); // Ensure it always bounces upwards
}
document.querySelectorAll('.brick').forEach(brick => {
if (isCollide(brick, ball)) {
player.ballSpeedY *= -1;
brick.remove();
player.score++;
updateScore();
}
});
ball.style.left = `${posBall.x + player.ballSpeedX}px`;
ball.style.top = `${posBall.y + player.ballSpeedY}px`;
}
function isCollide(a, b) {
let aRect = a.getBoundingClientRect();
let bRect = b.getBoundingClientRect();
return !(
aRect.right < bRect.left ||
aRect.left > bRect.right ||
aRect.bottom < bRect.top ||
aRect.top > bRect.bottom
);
}
function updateScore() {
scoreDisplay.textContent = player.score;
livesDisplay.textContent = player.lives;
}
function endGame() {
gameMessage.style.display = "block";
gameMessage.innerHTML = `Game Over<br>Your score: ${player.score}`;
player.gameover = true;
ball.style.display = "none";
cancelAnimationFrame(player.animationFrame);
}
function getRandomColor() {
return `#${Math.floor(Math.random() * 16777215).toString(16)}`;
}
</script>
</body>
</html>
๐ฅ Improvements
โ
Uses e.key
instead of deprecated e.keyCode
โ
Removes PNG ball (uses CSS for rendering)
โ
Uses CSS classes for styling elements
โ
Cleaner & More Readable Code
Now, your game is modernized, responsive, and efficient. ๐ ๐ฎ

