🎮 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.keyCodewithe.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. 🚀 🎮

