<!DOCTYPE html>
<html lang="en">
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
</head>
<body style="background-color: rgb(50, 50, 50);">
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script>
var ballX = 75;
var ballY = 75;
const BALL_SPEED_X_INIT = 1;
const BALL_SPEED_Y_INIT = 3.5;
var ballSpeedX = BALL_SPEED_X_INIT;
var ballSpeedY = BALL_SPEED_Y_INIT;
var ballFired = false;
const BALL_RADIUS = 8;
const LIFES_CONST = 3;
var lifes = LIFES_CONST;
const BRICK_W = 80;
const BRICK_H = 20;
const BRICK_GAP = 2;
const BRICK_COLS = 10;
const BRICK_ROWS = 14;
var brickGrid = new Array(BRICK_COLS * BRICK_ROWS);
var bricksLeft = 0;
const PADDLE_WIDTH = 100;
const PADDLE_THICKNESS = 10;
const PADDLE_DIST_FROM_EDGE = 60;
var paddleX = 400;
var paddleSpeed = 10;
var canvas, canvasContext;
const UPDATES_PER_SECOND = 120;
const FRAMES_PER_SECOND = 60;
var mouseX = 0;
var mouseY = 0;
var mouseDown = false;
var arrowLeftDown = false;
var arrowRightDown = false;
var acceleration = 1;
var gameOver = false;
var gameWon = false;
//******** TEST SOUND BEGIN *******/
//******** TEST SOUND END *******/
const CHEAT_MOVE_BALL_WITH_MOUSE = true;
const CHEAT_BALL_BOUNCES_OFF_BOTTOM = true;
/************************************************************ ONLOAD ************************************************************/
window.onload = function() {
canvas = document.getElementById('gameCanvas');
canvasContext = canvas.getContext('2d');
setInterval(updateAll, 1000/UPDATES_PER_SECOND);
canvas.addEventListener('mousemove', updateMousePos);
//window.addEventListener('onkeydown', this.onKeyDownListener, false);
document.onmousedown = onMouseDownListener;
//document.onmouseup = onMouseUpListener;
document.onkeydown = onKeyDownListener;
document.onkeyup = onKeyUpListener;
brickReset();
ballReset();
lifes = LIFES_CONST; //ballreset() subtracts a life, therefore set lifes to default again
}
/************************************************************ EVENT LISTENERS ************************************************************/
function updateMousePos(evt) {
var rect = canvas.getBoundingClientRect();
var root = document.documentElement;
mouseX = evt.clientX - rect.left - root.scrollLeft;
mouseY = evt.clientY - rect.top - root.scrollTop;
paddleX = mouseX - PADDLE_WIDTH/2;
if(CHEAT_MOVE_BALL_WITH_MOUSE && mouseDown) { //cheat / hack to test ball in any position
ballX = mouseX;
ballY = mouseY;
ballSpeedX = 1;
//ballSpeedY = -4;
}
}
function onKeyDownListener(evt) {
var keyCode = evt.which || evt.keyCode;
switch(keyCode) {
case 37:
arrowLeftDown = true;
break;
case 39:
arrowRightDown = true;
break;
case 32: //spacebar
case 38: //arrow up
if(gameOver || gameWon) {
gameOver = false;
gameWon = false;
brickReset();
} else if(ballFired == false){
fireNewBall();
}
}
}
function onKeyUpListener(evt) {
var keyCode = evt.which || evt.keyCode;
if(keyCode == 37) {
arrowLeftDown = false;
}
if(keyCode == 39) {
arrowRightDown = false;
}
acceleration = 1;
}
function onMouseDownListener() {
mouseDown = true;
if(gameOver || gameWon) {
gameOver = false;
gameWon = false;
brickReset();
} else if(ballFired == false) {
fireNewBall();
}
}
function onMouseUpListener() {
mouseDown = true;
}
/************************************************************ GAME FUNCTION ************************************************************/
function updateAll() {
moveAll();
drawAll();
}
/************************************************************ MOVE STUFF ************************************************************/
function moveAll() {
paddleMove();
ballMove();
ballBrickHandling();
ballPaddleHandling();
}
function paddleMove() {
if(arrowRightDown && paddleX + PADDLE_WIDTH/2 <= canvas.width) {
paddleX += paddleSpeed * acceleration;
}
if(arrowLeftDown && paddleX + PADDLE_WIDTH/2 >= 0) {
paddleX -= paddleSpeed * acceleration;
}
if(acceleration <= 2) {
acceleration += 0.2;
}
}
function ballMove() {
if(ballFired && !gameOver && !gameWon) {
ballX += ballSpeedX;
ballY += ballSpeedY;
if(ballX < 0 && ballSpeedX < 0.0) { //left
ballSpeedX *= -1;
}
if(ballX > canvas.width && ballSpeedX > 0.0) { // right
ballSpeedX *= -1;
}
if(ballY < 0 && ballSpeedY < 0.0) { // top
ballSpeedY *= -1;
}
if(ballY > canvas.height) { // bottom
if(CHEAT_BALL_BOUNCES_OFF_BOTTOM) {
ballSpeedY *= -1;
} else {
ballReset();
if(lifes <= 0) {
gameOver = true;
//brickReset();
}
}
}
} else {
ballX = paddleX + PADDLE_WIDTH/2;
ballY = canvas.height - PADDLE_DIST_FROM_EDGE - BALL_RADIUS - 4;
}
}
/************************************************************ COLLISION DETECTION ************************************************************/
function ballBrickHandling() {
var ballBrickCol = Math.floor(ballX / BRICK_W);
var ballBrickRow = Math.floor(ballY / BRICK_H);
var brickIndexUnderBall = rowColToArrayIndex(ballBrickCol, ballBrickRow);
if(ballBrickCol >= 0 && ballBrickCol < BRICK_COLS &&
ballBrickRow >= 0 && ballBrickRow < BRICK_ROWS) {
if(isBrickAtColRow( ballBrickCol,ballBrickRow )) {
brickGrid[brickIndexUnderBall] = false;
bricksLeft--;
ballSpeedX += Math.sign(ballSpeedX)*(0.5/ballBrickRow);
ballSpeedY += Math.sign(ballSpeedY)*(0.5/ballBrickRow);
console.log(ballSpeedY);
// console.log(bricksLeft);
var prevBallX = ballX - ballSpeedX;
var prevBallY = ballY - ballSpeedY;
var prevBrickCol = Math.floor(prevBallX / BRICK_W);
var prevBrickRow = Math.floor(prevBallY / BRICK_H);
var bothTestsFailed = true;
if(prevBrickCol != ballBrickCol) {
if(isBrickAtColRow(prevBrickCol, ballBrickRow) == false) {
ballSpeedX *= -1;
bothTestsFailed = false;
}
}
if(prevBrickRow != ballBrickRow) {
if(isBrickAtColRow(ballBrickCol, prevBrickRow) == false) {
ballSpeedY *= -1;
bothTestsFailed = false;
}
}
if(bothTestsFailed) { // armpit case, prevents ball from going through
ballSpeedX *= -1;
ballSpeedY *= -1;
}
} // end of brick found
} // end of valid col and row
} // end of ballBrickHandling func
function isBrickAtColRow(col, row) {
if(col >= 0 && col < BRICK_COLS &&
row >= 0 && row < BRICK_ROWS) {
var brickIndexUnderCoord = rowColToArrayIndex(col, row);
return brickGrid[brickIndexUnderCoord];
} else {
return false;
}
}
function rowColToArrayIndex(col, row) {
return col + BRICK_COLS * row;
}
function ballPaddleHandling() {
var paddleTopEdgeY = canvas.height-PADDLE_DIST_FROM_EDGE;
var paddleBottomEdgeY = paddleTopEdgeY + PADDLE_THICKNESS;
var paddleLeftEdgeX = paddleX;
var paddleRightEdgeX = paddleLeftEdgeX + PADDLE_WIDTH;
if( ballY > paddleTopEdgeY && // below the top of paddle
ballY < paddleBottomEdgeY && // above bottom of paddle
ballX > paddleLeftEdgeX && // right of the left side of paddle
ballX < paddleRightEdgeX) { // left of the left side of paddle
ballSpeedY *= -1;
var centerOfPaddleX = paddleX+PADDLE_WIDTH/2;
var ballDistFromPaddleCenterX = ballX - centerOfPaddleX;
ballSpeedX = ballDistFromPaddleCenterX * 0.35;
if(bricksLeft == 0) {
gameWon = true;
//brickReset();
} // out of bricks
} // ball center inside paddle
} // end of ballPaddleHandling
/************************************************************ RESETS / GAME SETUP STUFF ************************************************************/
function brickReset() {
bricksLeft = 0;
var i;
for(i=0; i< 3*BRICK_COLS; i++) {
brickGrid[i] = false;
}
for(; i<BRICK_COLS * BRICK_ROWS; i++) {
brickGrid[i] = true;
bricksLeft++;
} // end of for each brick
lifes = LIFES_CONST;
gameWon = false;
gameOver = false;
} // end of brickReset func
function ballReset() {
/* no need for that because ball gets positioned on pedal
ballX = canvas.width/2;
ballY = canvas.height/2; */
//ballSpeedX = 1;
ballFired = false;
lifes --;
}
function fireNewBall() {
ballFired = true;
ballSpeedX = BALL_SPEED_X_INIT;
ballSpeedY = BALL_SPEED_Y_INIT;
}
/************************************************************ DRAWING ************************************************************/
function drawAll() {
colorRect(0,0, canvas.width,canvas.height, 'black'); // clear screen
drawLifes();
colorCircle(ballX,ballY, BALL_RADIUS, 'white'); // draw ball
colorRect(paddleX, canvas.height-PADDLE_DIST_FROM_EDGE,
PADDLE_WIDTH, PADDLE_THICKNESS, 'white'); //draw paddle
drawBricks();
if(gameOver) {
colorTextAdv("You Lost.", 350, 350, 'red', "center", "32px Arial");
colorTextAdv("click to continue...", 350, 420, 'red', "center", "20px Arial");
return;
}
if(gameWon) {
colorTextAdv("You Won!", 350, 350, 'green', "center", "32px Arial");
colorTextAdv("click to continue...", 350, 420, 'green', "center", "20px Arial");
return;
}
}
function drawBricks() {
for(var eachRow=0;eachRow<BRICK_ROWS;eachRow++) {
for(var eachCol=0;eachCol<BRICK_COLS;eachCol++) {
var arrayIndex = rowColToArrayIndex(eachCol, eachRow);
if(brickGrid[arrayIndex]) {
colorRect(BRICK_W*eachCol,BRICK_H*eachRow,
BRICK_W-BRICK_GAP,BRICK_H-BRICK_GAP,
'rgb('+ Math.floor(255-(255*eachRow/BRICK_ROWS)) +','+ 0 +','+ Math.floor(255*(eachRow/BRICK_ROWS)) +')' );
} // end of is this brick here
} // end of for each brick
} // end of for each row
} // end of drawBricks func
function drawLifes() {
for(var i = 0; i < lifes; i++) {
colorCircle(20 + 28*i, canvas.height - 20, 10, 'white');
}
}
/************************************************************ DRAWING BASIC FUNCTIONS ************************************************************/
function colorRect(topLeftX,topLeftY, boxWidth,boxHeight, fillColor) {
canvasContext.fillStyle = fillColor;
canvasContext.fillRect(topLeftX,topLeftY, boxWidth,boxHeight);
}
function colorCircle(centerX,centerY, radius, fillColor) {
canvasContext.fillStyle = fillColor;
canvasContext.beginPath();
canvasContext.arc(centerX,centerY, 10, 0,Math.PI*2, true);
canvasContext.fill();
}
function colorText(showWords, textX,textY, fillColor) {
canvasContext.fillStyle = fillColor;
canvasContext.fillText(showWords, textX, textY);
}
function colorTextAdv(text, textX, textY, fillColor, alignment, font) {
canvasContext.fillStyle = fillColor;
canvasContext.font=font;
canvasContext.textAlign = alignment;
canvasContext.fillText(text, textX, textY);
}
</script>
</body>
</html>