Breakout game

Breakout.html  [download]

<!DOCTYPE html>

<html>
<head>

<title>Comp 86 example</title>
<!-- Based on: https://developer.mozilla.org/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript -->

<style>
canvas { background: #eee; }
</style>

<script type="text/javascript">
"use strict";

// Globals
var canvas, ctx

// Paddle
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX

// Ball location, velocity
var ballRadius = 10;
var x, y
var dx = 2;
var dy = -2;

// Bricks
var bricks = [];
var brickRowCount = 5;
var brickColumnCount = 3;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;

// Keys
var rightPressed = false;
var leftPressed = false;

// Game rules
var score = 0;
var lives = 3;

// Initialize game
onload = function () {
	// Initalize globals that depend on window being loaded first
	canvas = document.getElementById("myCanvas");
	ctx = canvas.getContext("2d");

	x = canvas.width/2;
	y = canvas.height-30;

	paddleX = (canvas.width-paddleWidth)/2;

	// Create the bricks
	for (var c=0; c<brickColumnCount; c++) {
		bricks[c] = [];
		for (var r=0; r<brickRowCount; r++) {
			bricks[c][r] = { x: 0, y: 0, status: 1 };
		}
	}

	// Install callbacks
	document.addEventListener("keydown", keyDownHandler, false);
	document.addEventListener("keyup", keyUpHandler, false);
	document.addEventListener("mousemove", mouseMoveHandler, false);

	// Draw the first time, which will trigger the next time
	draw();
}

// Draw the ball
function drawBall() {
	ctx.beginPath();
	ctx.arc(x, y, ballRadius, 0, Math.PI*2);
	ctx.fillStyle = "#0095DD";
	ctx.fill();
	ctx.closePath();
}

// Draw the paddle
function drawPaddle() {
	ctx.beginPath();
	ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
	ctx.fillStyle = "#0095DD";
	ctx.fill();
	ctx.closePath();
}

// Draw all the bricks
function drawBricks() {
	for(var c=0; c<brickColumnCount; c++) {
		for(var r=0; r<brickRowCount; r++) {
			if(bricks[c][r].status == 1) {
				var brickX = (r*(brickWidth+brickPadding))+brickOffsetLeft;
				var brickY = (c*(brickHeight+brickPadding))+brickOffsetTop;
				bricks[c][r].x = brickX;
				bricks[c][r].y = brickY;
				ctx.beginPath();
				ctx.rect(brickX, brickY, brickWidth, brickHeight);
				ctx.fillStyle = "#0095DD";
				ctx.fill();
				ctx.closePath();
			}
		}
	}
}

function drawScore() {
	ctx.font = "16px Arial";
	ctx.fillStyle = "#0095DD";
	ctx.fillText("Score: "+score, 8, 20);
}

function drawLives() {
	ctx.font = "16px Arial";
	ctx.fillStyle = "#0095DD";
	ctx.fillText("Lives: "+lives, canvas.width-65, 20);
}

// Draw everything
function draw() {
	ctx.clearRect(0, 0, canvas.width, canvas.height);
	
	drawBricks();
	drawBall();
	drawPaddle();
	drawScore();
	drawLives();
	collisionDetection();
	
	// U-turn ball at edges and handle game over
	if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
		dx = -dx;
	}
	if(y + dy < ballRadius) {
		dy = -dy;
	}
	else if(y + dy > canvas.height-ballRadius) {
		// Ball hit bottom of screen
		if(x > paddleX && x < paddleX + paddleWidth) {
			// Hit paddle = turn around
			dy = -dy;
		}
		else {
			// Hit bottom = lose life
			lives--;
			if(lives>0) {
				// Ball resets and speeds up
				x = canvas.width/2;
				y = canvas.height-30;
				dx = 3;
				dy = -3;
				paddleX = (canvas.width-paddleWidth)/2;
			}
			else {
				alert("GAME OVER");
				document.location.reload();
			}
		}
	}
	
	// Move paddle
	if(rightPressed && paddleX < canvas.width-paddleWidth) {
		paddleX += 7;
	}
	else if(leftPressed && paddleX > 0) {
		paddleX -= 7;
	}
	
	// Update ball
	x += dx;
	y += dy;
	
	// Set up for next frame
	requestAnimationFrame(draw);
}

function collisionDetection() {
	for(var c=0; c<brickColumnCount; c++) {
		for(var r=0; r<brickRowCount; r++) {
			var b = bricks[c][r];
			if(b.status == 1) {
				if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
					dy = -dy;
					b.status = 0;
					score++;
					if(score == brickRowCount*brickColumnCount) {
						alert("YOU WIN, CONGRATS!");
						document.location.reload();
					}
				}
			}
		}
	}
}

// Keyboard callbacks
function keyDownHandler(e) {
	if(e.keyCode == 39) {
		rightPressed = true;
	}
	else if(e.keyCode == 37) {
		leftPressed = true;
	}
}

function keyUpHandler(e) {
	if(e.keyCode == 39) {
		rightPressed = false;
	}
	else if(e.keyCode == 37) {
		leftPressed = false;
	}
}

// Mouse callback
function mouseMoveHandler(e) {
	var relativeX = e.clientX - canvas.offsetLeft;
	if(relativeX > 0 && relativeX < canvas.width) {
		paddleX = relativeX - paddleWidth/2;
	}
}
</script>

</head>

<body>
<canvas id="myCanvas" width="480" height="320"></canvas>
</body>

</html>