Skip to content

Instantly share code, notes, and snippets.

@jpbyrne
Created October 25, 2012 21:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jpbyrne/3955627 to your computer and use it in GitHub Desktop.
Save jpbyrne/3955627 to your computer and use it in GitHub Desktop.
A simple Breakout clone created using JavaScript
function Ball(x, y, radius, color) {
this.x = x;
this.y = y;
this.dx = 10;
this.dy = 10;
this.dxRange = this.dx * 2;
this.radius = radius;
this.color = color;
this.draw = function(context) {
context.save();
context.translate(this.x, this.y);
context.fillStyle = this.color;
context.beginPath();
context.arc(0, 0, this.radius, 0, (Math.PI * 2), true);
context.closePath();
context.fill();
context.restore();
}
// prevents the ball from leaving the stage
// (except via the bottom of the screen)
this.bound = function(canvas) {
if(this.x - (this.radius / 2) <= 0 ||
this.x + (this.radius / 2) >= canvas.width) {
this.dx = - this.dx;
}
if(this.y - (this.radius / 2) <= 0) {
this.dy = - this.dy;
}
}
}
function Brick(x, y, width, height, color) {
this.x = x;
this.y = y;
this.height = height;
this.width = width;
this.color = color;
this.state = true;
this.draw = function(context) {
context.save();
context.translate(this.x, this.y);
context.fillStyle = this.color;
context.fillRect (0,0,this.width,this.height);
context.restore();
}
// detects collision between the brick and ball
this.collide = function(ball) {
if(this.state == true &&
ball.x - ball.radius <= this.x + this.width &&
ball.x + ball.radius >= this.x &&
ball.y - ball.radius <= this.y + this.height &&
ball.y + ball.radius >= this.y) {
this.state = false;
ball.dy = - ball.dy;
return true;
}
else {
return false;
}
}
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style>
#canvas {
background-color: #000000;
}
</style>
<script type="text/javascript" src="raf.js"></script>
<script type="text/javascript" src="paddle.js"></script>
<script type="text/javascript" src="ball.js"></script>
<script type="text/javascript" src="brick.js"></script>
<script type="text/javascript">
var canvas;
var ctx;
var paddle;
var PADDLE_WIDTH;
var PADDLE_HEIGHT;
var MARGIN;
var ball;
var BALL_WIDTH;
var BALL_HEIGHT;
var bricks;
var NROWS;
var NCOLS;
var BRICK_WIDTH;
var BRICK_HEIGHT;
var PADDING;
var rightDown = false;
var leftDown = false;
var releaseDown = false;
var resetDown = false;
var lives;
var score;
var livesEle;
var scoreEle;
function init() {
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
PADDLE_WIDTH = 120;
PADDLE_HEIGHT = 20;
MARGIN = 15;
paddle = new Paddle(canvas.width / 2 - (PADDLE_WIDTH / 2),
canvas.height - PADDLE_HEIGHT - MARGIN,
PADDLE_WIDTH,
PADDLE_HEIGHT,
'#FFFFFF');
BALL_WIDTH = 20;
BALL_HEIGHT = 20;
ball = new Ball(canvas.width / 2, canvas.height/ 2, BALL_WIDTH, '#FFFFFF');
NROWS = 5;
NCOLS = 9;
BRICK_WIDTH = (canvas.width/NCOLS) - 1;
BRICK_HEIGHT = 20;
PADDING = 1;
//initialises a 2D array of bricks
bricks = new Array(NROWS);
for (var i = 0; i < NROWS; i++) {
bricks[i] = new Array(NCOLS);
for (var j = 0; j < NCOLS; j++) {
bricks[i][j] = new Brick((BRICK_WIDTH + PADDING) * j,
((BRICK_HEIGHT + PADDING) * i) + MARGIN,
BRICK_WIDTH,
BRICK_HEIGHT,
'#FFFFFF');
}
}
ball.dx = 0;
lives = 3;
livesEle = document.getElementById('lives');
livesEle.innerHTML = lives;
score = 0;
scoreEle = document.getElementById('score');
scoreEle.innerHTML = score;
loop();
}
function loop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(loop);
if(lives >= 0) {
livesEle.innerHTML = lives;
scoreEle.innerHTML = score;
// prevents the ball from leaving the stage
ball.bound(canvas);
// resets the ball and decrements lives if
// it passes off the bottom of the screen
if(ball.y - (ball.radius * 2) >= canvas.height) {
paddle.x = canvas.width / 2 - (PADDLE_WIDTH / 2);
ball.x = canvas.width / 2;
ball.y = canvas.height/ 2;
ball.dx = 0;
lives--;
}
// ball/paddle collision detection
paddle.collide(ball);
// ball/brick collision detection
for (var i = 0; i < NROWS; i++) {
for (var j = 0; j < NCOLS; j++) {
if(bricks[i][j].collide(ball) == true) {
score++;
}
}
}
// update ball coords
ball.x += ball.dx;
ball.y += ball.dy;
// update paddle coords based on user input
if(leftDown == true && paddle.x >= 0) {
paddle.x -= paddle.dx;
}
if(rightDown == true && paddle.x + paddle.width <= canvas.width) {
paddle.x += paddle.dx;
}
//draw
ball.draw(ctx);
paddle.draw(ctx);
for (i=0; i < NROWS; i++) {
for (j=0; j < NCOLS; j++) {
if(bricks[i][j].state == true) {
bricks[i][j].draw(ctx);
}
}
}
}
else {
// draw game over text and restart instructions
ctx.fillStyle = '#FFFFFF';
ctx.font = '64px Arial';
ctx.fillText('You lose', 400, 300);
ctx.font = '18px Arial';
ctx.fillText('Press [r] to start again', 400, 380);
// reset all game elements
if(resetDown == true) {
lives = 2;
score = 0;
for (i=0; i < NROWS; i++) {
for (j=0; j < NCOLS; j++) {
bricks[i][j].state = true;
}
}
}
}
}
function onKeyDown(evt) {
if (evt.keyCode == 39) rightDown = true;
else if (evt.keyCode == 37) leftDown = true;
else if (evt.keyCode == 38) leftDown = true;
else if (evt.keyCode == 82) resetDown = true;
}
function onKeyUp(evt) {
if (evt.keyCode == 39) rightDown = false;
else if (evt.keyCode == 37) leftDown = false;
else if (evt.keyCode == 38) leftDown = false;
else if (evt.keyCode == 82) resetDown = false;
}
window.onresize = function() {
console.log('resize');
}
</script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Breakout</title>
</head>
<body onload="init()" onkeydown="onKeyDown(event)" onkeyup="onKeyUp(event)">
<h2>Breakout</h2>
<canvas id="canvas" width="800" height="600">
Canvas is not supported
</canvas>
<table>
<tr>
<td>Lives: </td>
<td id="lives"></td>
</tr>
<tr>
<td>Score: </td>
<td id="score"></td>
</tr>
</table>
</body>
</html>
function Paddle(x, y, width, height, color) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
this.dx = 10;
this.draw = function(context) {
context.save();
context.translate(this.x, this.y);
context.fillStyle = this.color;
context.fillRect (0, 0, this.width, this.height);
context.restore();
}
// detects collison between the ball and paddle
this.collide = function(ball) {
if(ball.x + ball.radius >= this.x &&
ball.x - ball.radius <= this.x + this.width &&
ball.y + (ball.radius / 2) >= this.y) {
// detects where on the paddle the ball has collided
// and deflects the ball in the appropriate direction
var percentage = (ball.x - this.x) / this.width;
ball.dx = (percentage * ball.dxRange) - (ball.dxRange / 2);
ball.dy = - ball.dy;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment