Skip to content

Instantly share code, notes, and snippets.

@straker

straker/README.md

Last active Apr 15, 2021
Embed
What would you like to do?
Basic Breakout HTML Game

Basic Breakout HTML 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.

image

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

  • Innkeeper Games
  • Karar Al-Remahy
<!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>
@misterslime

This comment has been minimized.

Copy link

@misterslime misterslime commented Aug 18, 2019

Nice!

@misterslime

This comment has been minimized.

Copy link

@misterslime misterslime commented Aug 18, 2019

You should make more of these things

@straker

This comment has been minimized.

Copy link
Owner Author

@straker straker commented Oct 24, 2019

Done! Tetris just went live

@Pro496951

This comment has been minimized.

Copy link

@Pro496951 Pro496951 commented Mar 20, 2020

I destroted all bricks in tetris.now?(after destroying all bricks)

@Pro496951

This comment has been minimized.

Copy link

@Pro496951 Pro496951 commented Mar 20, 2020

destroyed

@Pro496951

This comment has been minimized.

@white-asteroid

This comment has been minimized.

Copy link

@white-asteroid white-asteroid commented Nov 5, 2020

why is it not working?

@straker

This comment has been minimized.

Copy link
Owner Author

@straker straker commented Nov 5, 2020

@white-asteroid What's not working? The game is controlled using the arrow keys and the space bar to launch the ball.

@Benjamin-adler

This comment has been minimized.

Copy link

@Benjamin-adler Benjamin-adler commented Mar 31, 2021

Hey @straker I was wondering if it's possible to make it so that whenever I press space it spawns a new ball even if the current ball in still moving and in the canvas. If so please tell me the code.

@straker

This comment has been minimized.

Copy link
Owner Author

@straker straker commented Mar 31, 2021

@BenjiG64 yep, for that you'd need two things. You'd first need to have more than one ball object and you'd want to change the code that listens for the space event to not check the state of the ball to see if it's not moving.

@Benjamin-adler

This comment has been minimized.

Copy link

@Benjamin-adler Benjamin-adler commented Mar 31, 2021

So can you send here the exact code I would need?

@straker

This comment has been minimized.

Copy link
Owner Author

@straker straker commented Mar 31, 2021

@BenjiG64 I cannot. I leave adding new features to the code as a further exploration.

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