Skip to content

Instantly share code, notes, and snippets.

@straker
Last active February 17, 2025 04:31
Show Gist options
  • Save straker/98a2aed6a7686d26c04810f08bfaf66b to your computer and use it in GitHub Desktop.
Save straker/98a2aed6a7686d26c04810f08bfaf66b to your computer and use it in GitHub Desktop.
Basic Breakout HTML and JavaScript Game

Basic Breakout HTML and JavaScript Game

This is a basic implementation of the Atari Breakout game, but it's missing a few things intentionally and they're left as further exploration for the reader.

Further Exploration

  • Lives
    • The player should have 3 chances to remove all the bricks. Display how many lives the player currently has using context.fillText(). Remove a life when the ball goes below the screen
  • Score
  • Ball speed
  • Mobile and touchscreen support
  • Better paddle movement
    • Currently the paddle movement is sticky. If you press the opposite direction while releasing the other direction, the padddle doesn't move right away. And if you release a direction while holding the other, the paddle stops. Improve it so it doesn't do this.

Important note: I will answer questions about the code but will not add more features or answer questions about adding more features. This series is meant to give a basic outline of the game but nothing more.

License

(CC0 1.0 Universal) You're free to use this game and code in any project, personal or commercial. There's no need to ask permission before using these. Giving attribution is not required, but appreciated.

Other Basic Games

Support

Basic HTML Games are made possible by users like you. When you become a Patron, you get access to behind the scenes development logs, the ability to vote on which games I work on next, and early access to the next Basic HTML Game.

Top Patrons

  • Karar Al-Remahy
  • UnbrandedTech
  • Innkeeper Games
  • Nezteb
<!DOCTYPE html>
<html>
<head>
<title>Basic Breakout HTML Game</title>
<meta charset="UTF-8">
<style>
html, body {
height: 100%;
margin: 0;
}
body {
background: black;
display: flex;
align-items: center;
justify-content: center;
}
</style>
</head>
<body>
<canvas width="400" height="500" id="game"></canvas>
<script>
const canvas = document.getElementById('game');
const context = canvas.getContext('2d');
// each row is 14 bricks long. the level consists of 6 blank rows then 8 rows
// of 4 colors: red, orange, green, and yellow
const level1 = [
[],
[],
[],
[],
[],
[],
['R','R','R','R','R','R','R','R','R','R','R','R','R','R'],
['R','R','R','R','R','R','R','R','R','R','R','R','R','R'],
['O','O','O','O','O','O','O','O','O','O','O','O','O','O'],
['O','O','O','O','O','O','O','O','O','O','O','O','O','O'],
['G','G','G','G','G','G','G','G','G','G','G','G','G','G'],
['G','G','G','G','G','G','G','G','G','G','G','G','G','G'],
['Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'],
['Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y']
];
// create a mapping between color short code (R, O, G, Y) and color name
const colorMap = {
'R': 'red',
'O': 'orange',
'G': 'green',
'Y': 'yellow'
};
// use a 2px gap between each brick
const brickGap = 2;
const brickWidth = 25;
const brickHeight = 12;
// the wall width takes up the remaining space of the canvas width. with 14 bricks
// and 13 2px gaps between them, thats: 400 - (14 * 25 + 2 * 13) = 24px. so each
// wall will be 12px
const wallSize = 12;
const bricks = [];
// create the level by looping over each row and column in the level1 array
// and creating an object with the bricks position (x, y) and color
for (let row = 0; row < level1.length; row++) {
for (let col = 0; col < level1[row].length; col++) {
const colorCode = level1[row][col];
bricks.push({
x: wallSize + (brickWidth + brickGap) * col,
y: wallSize + (brickHeight + brickGap) * row,
color: colorMap[colorCode],
width: brickWidth,
height: brickHeight
});
}
}
const paddle = {
// place the paddle horizontally in the middle of the screen
x: canvas.width / 2 - brickWidth / 2,
y: 440,
width: brickWidth,
height: brickHeight,
// paddle x velocity
dx: 0
};
const ball = {
x: 130,
y: 260,
width: 5,
height: 5,
// how fast the ball should go in either the x or y direction
speed: 2,
// ball velocity
dx: 0,
dy: 0
};
// check for collision between two objects using axis-aligned bounding box (AABB)
// @see https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
function collides(obj1, obj2) {
return obj1.x < obj2.x + obj2.width &&
obj1.x + obj1.width > obj2.x &&
obj1.y < obj2.y + obj2.height &&
obj1.y + obj1.height > obj2.y;
}
// game loop
function loop() {
requestAnimationFrame(loop);
context.clearRect(0,0,canvas.width,canvas.height);
// move paddle by it's velocity
paddle.x += paddle.dx;
// prevent paddle from going through walls
if (paddle.x < wallSize) {
paddle.x = wallSize
}
else if (paddle.x + brickWidth > canvas.width - wallSize) {
paddle.x = canvas.width - wallSize - brickWidth;
}
// move ball by it's velocity
ball.x += ball.dx;
ball.y += ball.dy;
// prevent ball from going through walls by changing its velocity
// left & right walls
if (ball.x < wallSize) {
ball.x = wallSize;
ball.dx *= -1;
}
else if (ball.x + ball.width > canvas.width - wallSize) {
ball.x = canvas.width - wallSize - ball.width;
ball.dx *= -1;
}
// top wall
if (ball.y < wallSize) {
ball.y = wallSize;
ball.dy *= -1;
}
// reset ball if it goes below the screen
if (ball.y > canvas.height) {
ball.x = 130;
ball.y = 260;
ball.dx = 0;
ball.dy = 0;
}
// check to see if ball collides with paddle. if they do change y velocity
if (collides(ball, paddle)) {
ball.dy *= -1;
// move ball above the paddle otherwise the collision will happen again
// in the next frame
ball.y = paddle.y - ball.height;
}
// check to see if ball collides with a brick. if it does, remove the brick
// and change the ball velocity based on the side the brick was hit on
for (let i = 0; i < bricks.length; i++) {
const brick = bricks[i];
if (collides(ball, brick)) {
// remove brick from the bricks array
bricks.splice(i, 1);
// ball is above or below the brick, change y velocity
// account for the balls speed since it will be inside the brick when it
// collides
if (ball.y + ball.height - ball.speed <= brick.y ||
ball.y >= brick.y + brick.height - ball.speed) {
ball.dy *= -1;
}
// ball is on either side of the brick, change x velocity
else {
ball.dx *= -1;
}
break;
}
}
// draw walls
context.fillStyle = 'lightgrey';
context.fillRect(0, 0, canvas.width, wallSize);
context.fillRect(0, 0, wallSize, canvas.height);
context.fillRect(canvas.width - wallSize, 0, wallSize, canvas.height);
// draw ball if it's moving
if (ball.dx || ball.dy) {
context.fillRect(ball.x, ball.y, ball.width, ball.height);
}
// draw bricks
bricks.forEach(function(brick) {
context.fillStyle = brick.color;
context.fillRect(brick.x, brick.y, brick.width, brick.height);
});
// draw paddle
context.fillStyle = 'cyan';
context.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);
}
// listen to keyboard events to move the paddle
document.addEventListener('keydown', function(e) {
// left arrow key
if (e.which === 37) {
paddle.dx = -3;
}
// right arrow key
else if (e.which === 39) {
paddle.dx = 3;
}
// space key
// if they ball is not moving, we can launch the ball using the space key. ball
// will move towards the bottom right to start
if (ball.dx === 0 && ball.dy === 0 && e.which === 32) {
ball.dx = ball.speed;
ball.dy = ball.speed;
}
});
// listen to keyboard events to stop the paddle if key is released
document.addEventListener('keyup', function(e) {
if (e.which === 37 || e.which === 39) {
paddle.dx = 0;
}
});
// start the game
requestAnimationFrame(loop);
</script>
</body>
</html>
@benjaminrotrou
Copy link

Bonjour lucar, je ne vous pas comment integrer votre code dans l orginal. Pouvez vous m aider ? Merci

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment