I've made a small breakout game, so far with one level. My plan is to expand it so that it has a level editor, but for now I wanted to make sure that everything is currently looking well-designed. I don't use js a lot so I'm not always very sure where to put things.
Just a heads up, the collision doesn't work entirely, but that's a side issue that can be fixed in it's own function. If you'd like to give it a try, go for it, but mainly I want to see what you think of the rest of the code and the structure.
The game is already hosted on my website, but since I don't have all the features I want it isn't linked to anywhere but here now.
Since I assume people want the actual code here and not having to inspect for it, here ya go.
var then;
var text;
var canvasW = 600;
var canvasH = 400;
var numX = 30;
var numY = 20;
var blockW = 20;
var blockH = 15;
var paddleW = 50;
var paddleH = 5;
var paddleX = canvasW/2-paddleW/2;
var paddleY = canvasH - 10;
var ballX = paddleX+paddleW/2;
var ballY = paddleY-2.5;
var ballS = 5;
var maxSpeed = paddleW*5;
var ballSpeedX = 0;
var ballSpeedY = maxSpeed;
var ballDirX = 1;
var ballDirY = -1;
var ballAlive = true;
var ballReleased = false;
var gameBoard = new Array(numX);
for(var i = 0; i < numX; i++) {
gameBoard[i] = new Array(numY);
for(var j = 0; j < numY; j++) {
gameBoard[i][j] = 'black';
}
}
var ctx;
var canvas;
var keysDown = {};
$(document).ready(function() {
if (Modernizr.canvas) {
$('#broken').hide();
initialize();
then = Date.now();
setInterval(main, 1);
}
});
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
}, false);
function initialize(){
$('#game').removeClass();
canvas = $('<canvas>');
canvas.attr('id', 'canvas');
canvas.attr('width', $('#game').width());
canvas.attr('height', $('#game').height());
canvas.appendTo('#game');
ctx = $('#canvas')[0].getContext("2d");
levelSelect(1);
}
function main() {
var now = Date.now();
var delta = now - then;
update(delta / 1000);
draw();
then = now;
};
function levelSelect(i){
switch(i) {
case 1:
level1();
break;
case 2:
level2();
break;
}
}
function level1() {
for(var i = 0; i < numX; i++) {
gameBoard[i][0] = 'gray';
if(i<numY) {
gameBoard[0][i] = 'gray';
gameBoard[numX-1][i] = 'gray';
}
}
for(var i = 4; i < numX; i++) {
for(var j = 2; j < numY; j++) {
gameBoard[i-2][j] = 'green';
}
}
}
function update(time) {
keys(time);
ball(time);
}
function keys(time) {
if ((37 in keysDown)&&(paddleX > 0)) { // Player holding left
paddleX -= 256*time;
}
if ((39 in keysDown)&&(paddleX < canvasW-paddleW)) { // Player holding right
paddleX += 256*time;
}
if (32 in keysDown) {
ballReleased = true;
}
if (32 in keysDown) {
text = "";
}
}
function ball(time) {
if(ballAlive)
{
if(ballReleased) {
moveBallY(time);
moveBallX(time);
checkBlocks();
}
else {
ballX = paddleX+paddleW/2;
ballY = paddleY-2.5;
}
} else {
resetBall();
}
}
function resetBall() {
ballSpeedX = 0;
ballSpeedY = maxSpeed;
ballDirX = 1;
ballDirY = -1;
ballAlive = true;
ballReleased = false;
}
function moveBallX(time) {
if(checkXWalls(time)) {
ballDirX = -ballDirX;
}
ballX = ballX + ballSpeedX*ballDirX*time;
}
function moveBallY(time) {
if(checkYWalls(time)||checkPaddle(time))
{
ballDirY = -ballDirY;
}
ballY = ballY + ballSpeedY*ballDirY*time;
}
function checkBlocks(time) {
if(contains(ballX, ballY)) {
var ballXC = ballX + ballS/2;
var ballYC = ballY + ballS/2;
var ballLeft = ballXC - ballS/2 - 1;
var ballRight = ballXC + ballS/2 + 1;
var ballTop = ballYC - ballS/2 - 1;
var ballBottom = ballYC + ballS/2 + 1;
text = "";
if(contains(ballLeft, ballYC)) {
hit(ballLeft, ballYC);
text = text + "left";
ballDirX = 1;
} if (contains(ballRight, ballYC)) {
text = text + "right";
hit(ballRight, ballYC);
ballDirX = -1;
} if(contains(ballXC, ballTop)) {
text = text + "top";
hit(ballXC, ballTop);
ballDirY = 1;
} else if (contains(ballXC, ballBottom)) {
text = text + "bottom";
hit(ballXC, ballBottom);
ballDirY = -1;
}
}
}
function contains(i, j) {
var x = Math.floor(i/blockW);
var y = Math.floor(j/blockH);
var block = gameBoard[x][y];
return intersects(block);
}
function intersects(block) {
if((block != 'black')&&(typeof block != 'undefined')) {
return true;
} else {
return false;
}
}
function hit(i, j) {
var x = Math.floor(i/blockW);
var y = Math.floor(j/blockH);
if(gameBoard[x][y] != 'gray') {
gameBoard[x][y] = 'black';
}
}
function checkXWalls(time) {
var newBallX = ballX + ballSpeedX*ballDirX*time;
if((newBallX <= 0)||(newBallX >= canvasW)) {
return true;
} else {
return false;
}
}
function checkYWalls(time) {
var newBallY = ballY + ballSpeedY*ballDirY*time;
if(newBallY <= 0) {
return true;
} else if (newBallY >= canvasH) {
ballAlive = false;
return false;
}
return false;
}
function checkPaddle(time) {
var newBallX = ballX + ballSpeedX*ballDirX*time;
var newBallY = ballY + ballSpeedY*ballDirY*time;
if((newBallX >= paddleX) && (newBallX <= paddleX + paddleW)
&& (newBallY >= paddleY)
&& (newBallY <= paddleY + paddleH)) {
ballSpeedX = (ballX - (paddleX + paddleW/2))*10;
if(ballSpeedX<0) {
ballSpeedX = -ballSpeedX;
ballDirX = -1;
} else {
ballDirX = 1;
}
ballSpeedY = maxSpeed - ballSpeedX;
return true;
}
return false;
}
function draw() {
if(ctx) {
drawBackground();
drawBoard();
if(ballAlive) {
drawBall();
}
drawPaddle();
ctx.fillStyle = "blue";
ctx.font = "bold 16px Arial";
ctx.fillText(text, 100, 100);
}
}
function drawBackground() {
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvasW, 400);
}
function drawBoard() {
for(var i = 0; i < numX; i++) {
for(var j = 0; j < numY; j++) {
if(gameBoard[i][j] != 'black') {
ctx.fillStyle = gameBoard[i][j];
ctx.strokeStyle = 'blue';
ctx.fillRect(i*blockW,j*blockH, blockW, blockH);
ctx.strokeRect(i*blockW,j*blockH, blockW, blockH);
}
}
}
}
function drawPaddle() {
ctx.fillStyle = 'blue';
ctx.fillRect(paddleX, paddleY, paddleW, paddleH);
}
function drawBall() {
ctx.beginPath();
ctx.arc(ballX, ballY, ballS/2, 0, 2 * Math.PI, false);
ctx.fillStyle = 'white';
ctx.fill();
}
setInterval
with an interval of less than 17 might not make sense. – Stuart Jan 19 '13 at 19:57