patternjavascriptMinor
Breakout game in JavaScript
Viewed 0 times
javascriptgamebreakout
Problem
I decided to make a Breakout game in JavaScript. Is there a way of making it cleaner? For instance, creating objects for the ball and the paddle.
Brick Game
body {
background-color: black;
}
canvas {
border: 1px solid green;
}
var canvas = document.getElementById("game-canvas");
// Get a 2D context for the canvas.
var ctx = canvas.getContext("2d");
var ballR = 10;
var x = canvas.width / 2;
var y = canvas.height - 30;
var dx = 3;
var dy = -3;
var pongH = 15;
var pongW = 80;
var pongX = (canvas.width - pongW) / 2;
var rightKey = false;
var leftKey = false;
var brickRows = 3;
var brickCol = 9;
var brickW = 75;
var brickH = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var bricks = [];
for (c = 0; c b.x && x b.y && y canvas.width - ballR || x + dx canvas.height - ballR) {
if (x > pongX && x 0) {
pongX -= 7;
}
x += dx;
y += dy;
}
setInterval(draw, 10);
Solution
First, great job. I loved seeing that the whole game had been created with so little code, and was so easy to understand.
While you could consider making this more object-oriented, I don't think it's necessary, so I did some rewrites in keeping with the simple procedural style of the original.
The biggest place for improvement is in naming your concepts. For example, this:
is much clearer than:
You can apply this principle over and over, at all levels of your code. See the full rewrite for more examples.
Other notes:
Full rewrite:
While you could consider making this more object-oriented, I don't think it's necessary, so I did some rewrites in keeping with the simple procedural style of the original.
The biggest place for improvement is in naming your concepts. For example, this:
if (hitSideWall())
dx = -dx;
if (hitTop() || hitPong())
dy = -dy;
if (gameOver())
document.location.reload();is much clearer than:
if (y + dy canvas.height - ballR) {
if (x > pongX && x < pongX + pongW) {
dy = -dy;
} else {
document.location.reload();
}
}You can apply this principle over and over, at all levels of your code. See the full rewrite for more examples.
Other notes:
- Avoid nesting wherever possible, and avoid "if... else" statements.
- The nested for loop for the bricks only needs to be done once. Use it once to create a flat array of bricks. Afterward, the nested structure is superfluous, since each brick object contains the info you need. Just loop through the flat array with
forEach.
- When initializing multiple variables, just use one
varand commas.
Full rewrite:
Brick Game
body { background-color: black; }
canvas { border: 1px solid green; }
var canvas = document.getElementById("game-canvas"),
ctx = canvas.getContext("2d"),
ballR = 10,
x = canvas.width / 2,
y = canvas.height - 30,
dx = 3,
dy = -3,
pongH = 15,
pongW = 80,
pongX = (canvas.width - pongW) / 2,
rightKey = false,
leftKey = false,
brickRows = 3,
brickCol = 9,
brickW = 75,
brickH = 20,
brickPadding = 10,
brickOffsetTop = 30,
brickOffsetLeft = 30;
var bricks = [];
for (c = 0; c b.x && x b.y && y pongX && x canvas.height - ballR }
function gameOver() { return hitBottom() && !ballOverPong() }
function hitSideWall() { return x + dx > canvas.width - ballR || x + dx canvas.width - ballR || x + dx
Code Snippets
if (hitSideWall())
dx = -dx;
if (hitTop() || hitPong())
dy = -dy;
if (gameOver())
document.location.reload();if (y + dy < ballR) {
dy = -dy;
} else if (y + dy > canvas.height - ballR) {
if (x > pongX && x < pongX + pongW) {
dy = -dy;
} else {
document.location.reload();
}
}<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Brick Game</title>
<style type="text/css">
body { background-color: black; }
canvas { border: 1px solid green; }
</style>
</head>
<body>
<canvas id="game-canvas" height="600px" width="800px" </canvas>
<script type="text/javascript">
var canvas = document.getElementById("game-canvas"),
ctx = canvas.getContext("2d"),
ballR = 10,
x = canvas.width / 2,
y = canvas.height - 30,
dx = 3,
dy = -3,
pongH = 15,
pongW = 80,
pongX = (canvas.width - pongW) / 2,
rightKey = false,
leftKey = false,
brickRows = 3,
brickCol = 9,
brickW = 75,
brickH = 20,
brickPadding = 10,
brickOffsetTop = 30,
brickOffsetLeft = 30;
var bricks = [];
for (c = 0; c < brickCol; c++) {
for (r = 0; r < brickRows; r++) {
bricks.push({
x: (c * (brickW + brickPadding)) + brickOffsetLeft,
y: (r * (brickH + brickPadding)) + brickOffsetTop,
status: 1
});
}
}
// function to draw the ball
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballR, 0, Math.PI * 2);
ctx.fillStyle = "red";
ctx.fill();
ctx.closePath();
}
// function draw the pong
function drawPong() {
ctx.beginPath();
ctx.rect(pongX, canvas.height - pongH, pongW, pongH);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
}
// function draw the bricks
function drawBricks() {
bricks.forEach(function(brick) {
if (!brick.status) return;
ctx.beginPath();
ctx.rect(brick.x, brick.y, brickW, brickH);
ctx.fillStyle = "green";
ctx.fill();
ctx.closePath();
});
}
function collisionDetection() {
bricks.forEach(function(b) {
if (!b.status) return;
var inBricksColumn = x > b.x && x < b.x + brickW,
inBricksRow = y > b.y && y < b.y + brickH;
if (inBricksColumn && inBricksRow) {
dy = -dy;
b.status = 0;
}
});
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPong();
collisionDetection();
if (hitSideWall())
dx = -dx;
if (hitTop() || hitPong())
dy = -dy;
if (gameOver())
document.location.reload();
var RIGHT_ARROW = 39,
LEFT_ARROW= 37;
function hitPong() { return hitBottom() && ballOverPong() }
function ballOverPong() { return x > pongX && x < pongX + pongW }
function hitBottom() { return y + dy > canvas.height - ballR }
function gameOver() { return hitBottom() && !ballContext
StackExchange Code Review Q#109771, answer score: 4
Revisions (0)
No revisions yet.