// Game state variables
let canvas = document.getElementById('game');
let ctx = canvas.getContext('2d');
let paddleWidth = 60;
let paddleHeight = 10;
let ballSpeed = 3;
let ballDirectionX = -ballSpeed;
let ballDirectionY = (Math.random() > 0.5 ? 2 : -2);
let lives = 3;
// Bricks' array of objects
let bricks = [
{x: 0, y: 0},
{x: 80, y: 0},
{x: 160, y: 0},
{x: 240, y: 0},
{x: 320, y: 0},
{x: 0, y: 40}
];
// Ball object properties
let ballX = canvas.width / 2;
let ballY = canvas.height - 10 - ballDirectionY;
let ballRadius = 3;
// Paddle object properties
let paddleX = canvas.width / 2 - paddleWidth / 2;
// Game functions
function gameLoop() {
update();
render();
checkCollisions();
movePaddle();
if (lives < 0) {
gameOver();
}
}
function restart() {
location.reload();
}
function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ballX += ballDirectionX;
ballY += ballDirectionY;
// Ball bounces off walls
if (ballX < 0 || ballX > canvas.width - ballRadius) {
ballDirectionX = -ballDirectionX;
}
// Ball bounces off paddle
if (ballY < 0) {
if (ballX >= paddleX && ballX <= paddleX + paddleWidth) {
let diffY = ballY - (canvas.height - ballRadius);
if (diffY > 0) {
ballDirectionY = -ballDirectionY;
} else {
gameOver();
}
}
}
// Ball bounces off bricks
for (let i = bricks.length - 1; i >= 0; i--) {
let brick = bricks[i];
if (brick.x + brick.width < 0 || brick.y > canvas.height - ballRadius * 2) {
bricks.splice(i, 1);
score += 10;
} else if (Math.abs(ballX - (brick.x + brick.width / 2)) < ballRadius && Math.abs(ballY - (canvas.height - ballRadius * 2) - brick.y) < ballRadius) {
bricks[i].destroyed = true;
score += 10;
}
}
// Move paddle
paddleX += 5;
}
function render() {
ctx.save();
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
let brickWidth = 80;
let brickHeight = 20;
let brickPadding = 5;
let brickMargin = 10;
let brickOffsetX = (canvas.width - (brickWidth * 8)) / 2;
let brickOffsetY = (canvas.height - (brickHeight * 4)) / 2 + brickMargin;
// Draw bricks
for (let i = bricks.length - 1; i >= 0; i--) {
let brick = bricks[i];
if (!brick.destroyed) {
ctx.fillStyle = 'cyan';
ctx.fillRect(brickOffsetX + brickWidth * brick.x, brickOffsetY + brickHeight * brick.y, brickWidth, brickHeight);
ctx.strokeRect(brickOffsetX + brickWidth * brick.x, brickOffsetY + brickHeight * brick.y, brickWidth, brickHeight);
}
}
// Draw paddle
ctx.fillStyle = 'cyan';
ctx.fillRect(paddleX, canvas.height - 10 - paddleHeight, paddleWidth, paddleHeight);
ctx.strokeRect(paddleX, canvas.height - 10 - paddleHeight, paddleWidth, paddleHeight);
// Draw score
ctx.fillStyle = 'white';
ctx.textBaseline = 'top';
ctx.font = '24px Arial';
ctx.fillText('Score: ' + score, 5, 5);
ctx.restore();
}
function checkCollisions() {
for (let i = bricks.length - 1; i >= 0; i--) {
let brick = bricks[i];
if (!brick.destroyed) {
let diffX = ballX - (brick.x + brickWidth / 2);
let diffY = ballY - (canvas.height - ballRadius * 2 - brick.y);
// Check collision with walls
if (diffX < 0 && diffX > -ballRadius) {
ballDirectionX = -ballDirectionX;
} else if (diffX > 0 && diffX < canvas.width - ballRadius) {
ballDirectionX = -ballDirectionX;
}
// Check collision with paddle
if ((diffY <= ballRadius * 2 + paddleHeight / 2 && diffX >= paddleWidth / 2 - ballRadius && diffX <= paddleWidth / 2 + ballRadius) || (diffY <= ballRadius)) {
let diffDirectionX = Math.sign(ballDirectionX);
let diffDirectionY = Math.sign(ballDirectionY);
// Reflect ball upward and flip dy if hit top/bottom paddle edge
if ((brick.x + brickWidth / 2 < paddleX && diffY <= -paddleHeight / 2) || (brick.x + brickWidth / 2 > canvas.width - paddleWidth + paddleX && diffY >= paddleHeight / 2)) {
ballDirectionY = -ballDirectionY;
if (diffY < -paddleHeight / 2) {
ballDirectionY *= -1;
} else if (diffY > paddleHeight / 2) {
ballDirectionY *= -1;
}
}
// Reflect ball left/right if hit side edge of brick
let dx = diffX * diffDirectionX;
let dy = diffY * diffDirectionY + ballRadius;
ballDirectionX = dx;
ballDirectionY = dy;
} else {
bricks[i].destroyed = true;
}
}
}
}
function movePaddle() {
if (event.type == 'touchmove') {
let touchX = event.touches[0].clientX - paddleWidth / 2;
if (touchX >= 0 && touchX <= canvas.width) {
paddleX = touchX;
}
} else if (event.type == 'mousemove') {
let mouseX = event.clientX - paddleWidth / 2;
if (mouseX >= 0 && mouseX <= canvas.width) {
paddleX = mouseX;
}
}
}
function gameOver() {
ctx.save();
ctx.fillStyle = 'black';
ctx.textAlign = 'center';
ctx.font = '32px Arial';
ctx.fillText('Game Over!', canvas.width / 2, canvas.height / 2);
ctx.restore();
}