You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
9.6 KiB
379 lines
9.6 KiB
2 years ago
|
var strokePadding = 3;
|
||
|
|
||
|
function Level(level){
|
||
|
|
||
|
this.startingPoint = Math.random();
|
||
|
|
||
|
var table = tableSwitch(level, this);
|
||
|
|
||
|
this.cols = table.cols;
|
||
|
this.rows = table.rows;
|
||
|
|
||
|
this.setDefault = function(){
|
||
|
|
||
|
this.isStarted = false;
|
||
|
this.isPaused = false;
|
||
|
this.isWon = false;
|
||
|
this.isLost = false;
|
||
|
|
||
|
this.levelNum = level;
|
||
|
this.recordTime = getRecordTime(level);
|
||
|
this.totalBricksDestroyed = getTotalBricksDestroyed(level);
|
||
|
this.currentTime = 0;
|
||
|
|
||
|
this.brickPadding = (wWidth * 0.0125 + wHeight * 0.0125) / 2;
|
||
|
this.brickWidth = (wWidth - this.brickPadding * (this.cols + 1)) / this.cols;
|
||
|
this.brickHeight = (wHeight * 0.75 - this.brickPadding * (this.rows + 1)) / this.rows;
|
||
|
|
||
|
this.bricks = [];
|
||
|
this.balls = [];
|
||
|
this.toBeErased = [];
|
||
|
this.items = [];
|
||
|
|
||
|
this.itemFrequency = floor(levelCount / this.levelNum) * 2;
|
||
|
|
||
|
var p = new Paddle();
|
||
|
p.v = 10;
|
||
|
p.width = wWidth * 0.15;
|
||
|
p.x = (wWidth - p.width) / 2;
|
||
|
p.y = wHeight * 0.95;
|
||
|
p.height = wHeight * 0.025;
|
||
|
|
||
|
var b = new Ball();
|
||
|
b.radius = (wWidth * 0.02 + wHeight * 0.02) / 2;
|
||
|
b.x = p.x + this.startingPoint * p.width;
|
||
|
b.y = p.y - b.radius - strokePadding;
|
||
|
var velocityVector = {mag: (wWidth * 0.01 + wHeight * 0.01) / 3, x: 0, y: 0};
|
||
|
b.v = velocityVector;
|
||
|
b.v.x = b.calcVelocityX(p, 0);
|
||
|
b.v.y = -b.calcVelocityY();
|
||
|
|
||
|
this.paddle = p;
|
||
|
this.balls.push(b);
|
||
|
|
||
|
for (var c = 1; c <= this.cols; c++){
|
||
|
for (var r = 1; r <= this.rows; r++){
|
||
|
var b = new Brick();
|
||
|
b.x = this.brickPadding + (c - 1) * (this.brickWidth + this.brickPadding);
|
||
|
b.y = this.brickPadding + (r - 1) * (this.brickHeight + this.brickPadding);
|
||
|
b.width = this.brickWidth;
|
||
|
b.height = this.brickHeight;
|
||
|
b.state = designSwitch(level, c, r);
|
||
|
this.bricks.push(b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Border Top
|
||
|
bt = new Frameborder(0, -50, wWidth, 50);
|
||
|
//Border Bottom
|
||
|
bb = new Frameborder(0, wHeight, wWidth, 50);
|
||
|
//Border Left
|
||
|
bl = new Frameborder(-50, 0, 50, wHeight);
|
||
|
//Border Right
|
||
|
br = new Frameborder(wWidth, 0, 50, wHeight);
|
||
|
|
||
|
this.frameBorders = [bt, bb, bl, br];
|
||
|
}
|
||
|
|
||
|
this.setDefault();
|
||
|
|
||
|
//Draw everything and check and react to collisions and events
|
||
|
this.drawShapes = function(){
|
||
|
|
||
|
if (this.isWon || this.isLost) return;
|
||
|
|
||
|
//Background gets cleared and bg color is gray
|
||
|
clear();
|
||
|
background(100);
|
||
|
|
||
|
//Bricks have black stroke and rounded corners
|
||
|
stroke(0);
|
||
|
strokeWeight(strokePadding * 2);
|
||
|
strokeJoin(ROUND);
|
||
|
|
||
|
//Counter to check if game is won
|
||
|
var brickCounter = 0;
|
||
|
|
||
|
//Draw bricks
|
||
|
for (var b of this.bricks){
|
||
|
|
||
|
//If there are bricks "living" counter goes up and game keeps running
|
||
|
if (b.state > 0) brickCounter++;
|
||
|
|
||
|
//Select brick color based on his state
|
||
|
var fillColor = colorSwitch(b.state);
|
||
|
if (!fillColor) continue;
|
||
|
else fill(fillColor);
|
||
|
|
||
|
//Drawing
|
||
|
rect(b.x, b.y, b.width, b.height);
|
||
|
}
|
||
|
|
||
|
//If no brick is "living" game is won
|
||
|
if (brickCounter == 0) this.gameWon(); //Deactivate in TestMode
|
||
|
|
||
|
//Draw downfalling items
|
||
|
for (var i of this.items){
|
||
|
var sw = i.radius * 0.2;
|
||
|
|
||
|
fill(0);
|
||
|
stroke(0);
|
||
|
strokeWeight(0);
|
||
|
ellipse(i.x, i.y, i.radius * 2, i.radius * 2);
|
||
|
strokeWeight(sw);
|
||
|
|
||
|
var rectX = i.x - i.radius * sin(5 * PI / 8) + sw;
|
||
|
var rectY = i.y + i.radius * cos(5 * PI / 8) + sw;
|
||
|
var rectW = i.radius * 2 * sin(5 * PI / 8) - sw * 2;
|
||
|
var rectH = i.radius * 2 * abs(cos(5 * PI / 8)) - sw * 2;
|
||
|
|
||
|
var lineLength = i.radius * 0.5;
|
||
|
|
||
|
switch(i.item){
|
||
|
case FastBall:
|
||
|
fill("#00FF00");
|
||
|
strokeWeight(0);
|
||
|
ellipse(i.x, i.y, i.radius * 1.25, i.radius * 1.25);
|
||
|
break;
|
||
|
case FastPaddle:
|
||
|
fill("#00FF00");
|
||
|
strokeWeight(0);
|
||
|
rect(rectX, rectY, rectW, rectH);
|
||
|
break;
|
||
|
case SlowBall:
|
||
|
fill("#FF0000");
|
||
|
strokeWeight(0);
|
||
|
ellipse(i.x, i.y, i.radius * 1.25, i.radius * 1.25);
|
||
|
break;
|
||
|
case SlowPaddle:
|
||
|
fill("#FF0000");
|
||
|
strokeWeight(0);
|
||
|
rect(rectX, rectY, rectW, rectH);
|
||
|
break;
|
||
|
case CreateBall:
|
||
|
strokeWeight(sw * 2);
|
||
|
stroke("#00FF00");
|
||
|
line(i.x - lineLength, i.y, i.x + lineLength, i.y);
|
||
|
line(i.x, i.y - lineLength, i.x, i.y + lineLength);
|
||
|
break;
|
||
|
case UpgradeBricks:
|
||
|
strokeWeight(sw * 2);
|
||
|
stroke("#FF0000");
|
||
|
line(i.x - lineLength, i.y, i.x + lineLength, i.y);
|
||
|
line(i.x, i.y - lineLength, i.x, i.y + lineLength);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Balls and paddleboard are black
|
||
|
fill(0);
|
||
|
stroke(0);
|
||
|
strokeWeight(strokePadding * 2);
|
||
|
|
||
|
var p = this.paddle;
|
||
|
|
||
|
//Draw paddleboard
|
||
|
rect(p.x, p.y, p.width, p.height);
|
||
|
|
||
|
//Ball doesnt need rounded corners
|
||
|
strokeWeight(0);
|
||
|
|
||
|
//Draw every ball
|
||
|
for (var b of this.balls) ellipse(b.x, b.y, b.radius * 2, b.radius * 2);
|
||
|
|
||
|
//Break if game isnt running
|
||
|
if (this.isPaused || !this.isStarted) return;
|
||
|
|
||
|
//Check collision and other situations of balls
|
||
|
for(var ball1 of this.balls){
|
||
|
|
||
|
//Check if ball flew away
|
||
|
if (ball1.isLost()) this.toBeErased.push(ball1);
|
||
|
|
||
|
//Check collision with frameborders
|
||
|
for (var fb of this.frameBorders){
|
||
|
var collision = collisionDetection(ball1, fb);
|
||
|
if (collision.isTouching) performCollision(ball1, fb, collision);
|
||
|
}
|
||
|
|
||
|
//Check collision with paddleboard
|
||
|
var collision = collisionDetection(ball1, p);
|
||
|
if (collision.isTouching) performCollision(ball1, p, collision);
|
||
|
|
||
|
//Check collision with bricks
|
||
|
for (var brick of this.bricks){
|
||
|
if (brick.state == 0) continue;
|
||
|
var collision = collisionDetection(ball1, brick);
|
||
|
if (collision.isTouching){
|
||
|
performCollision(ball1, brick, collision);
|
||
|
if (brick.state > 0) brick.state--;
|
||
|
if (floor(random(this.itemFrequency + 1)) % this.itemFrequency == 0 && brick.state == 0) this.createItem(brick);
|
||
|
if (brick.state == 0) this.totalBricksDestroyed++;
|
||
|
setTotalBricksDestroyed(level, this.totalBricksDestroyed);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Check collision with other balls
|
||
|
for (var ball2 of this.balls){
|
||
|
if (ball1 == ball2) continue;
|
||
|
var collision = collisionDetection(ball1, ball2);
|
||
|
if (collision.isTouching) performCollision(ball1, ball2, collision);
|
||
|
}
|
||
|
|
||
|
//Check if velocites go to NaN due to mistakes
|
||
|
if (isNaN(ball1.v.x) || isNaN(ball1.v.y)){
|
||
|
ball1.x = p.x + p.width / 2;
|
||
|
ball1.y = p.y - ball1.radius - strokePadding * 2;
|
||
|
ball1.v.x = 0;
|
||
|
ball1.v.y = ball1.v.mag;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Checkings for items
|
||
|
for (var item of this.items){
|
||
|
|
||
|
var index = this.items.indexOf(item);
|
||
|
|
||
|
//Check collision with paddleboard
|
||
|
var collision = collisionDetection(item, p);
|
||
|
if (collision.isTouching){
|
||
|
this.items.splice(index, 1);
|
||
|
switch (item.item){
|
||
|
case FastBall:
|
||
|
for (var b of this.balls) for (var v in b.v) b.v[v] *= 1.25;
|
||
|
break;
|
||
|
case FastPaddle:
|
||
|
p.v *= 1.25;
|
||
|
break;
|
||
|
case SlowBall:
|
||
|
for (var b of this.balls) for (var v in b.v) b.v[v] *= 0.75;
|
||
|
break;
|
||
|
case SlowPaddle:
|
||
|
p.v *= 0.75;
|
||
|
break;
|
||
|
case CreateBall:
|
||
|
var p = this.paddle;
|
||
|
var radius = (wWidth * 0.02 + wHeight * 0.02) / 2 * random(0.75, 1.25);
|
||
|
var x = p.x + p.width / 2;
|
||
|
var y = p.y - (radius + strokePadding);
|
||
|
var v = (wWidth * 0.01 + wHeight * 0.01) / 3;
|
||
|
var vx = 0;
|
||
|
var vy = v;
|
||
|
this.createBall(x, y, radius, v, vx, vy);
|
||
|
break;
|
||
|
case UpgradeBricks:
|
||
|
for (var b of this.bricks) if (b.state > 0 && b.state < stateCount - 1) b.state++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (item.y - item.radius > wHeight){
|
||
|
this.items.splice(index, 1);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//Erase all balls out of screen
|
||
|
for (var ball of this.toBeErased){
|
||
|
var index = this.balls.indexOf(ball);
|
||
|
this.balls.splice(index, 1);
|
||
|
}
|
||
|
this.toBeErased = [];
|
||
|
|
||
|
//Game is lost of no balls are in there
|
||
|
if (this.balls.length == 0) this.gameLost();
|
||
|
|
||
|
//Break if game isnt running once more because previous checkings could've caused a paused game
|
||
|
if (!this.isStarted || this.isPaused) return;
|
||
|
|
||
|
//Finally move objects forward
|
||
|
for (var b of this.balls) b.move();
|
||
|
for (var i of this.items) i.move();
|
||
|
p.move();
|
||
|
}
|
||
|
|
||
|
|
||
|
this.createItem = function(b){
|
||
|
|
||
|
var item = floor(random(itemCount)) + 1;
|
||
|
|
||
|
var bx = b.x;
|
||
|
var by = b.y;
|
||
|
var bw = b.width;
|
||
|
var bh = b.height;
|
||
|
|
||
|
var x = bx + bw / 2;
|
||
|
var y = by + bh / 2;
|
||
|
var radius = (wHeight + wWidth) / 2 * 0.02;
|
||
|
|
||
|
this.items.push(new Item(x, y, radius, random(1, 6), item));
|
||
|
}
|
||
|
|
||
|
this.createBall = function(x, y, r, v, vx, vy){
|
||
|
|
||
|
var b = new Ball();
|
||
|
|
||
|
b.x = x;
|
||
|
b.y = y;
|
||
|
b.radius = r;
|
||
|
b.v = {mag: v, x: vx, y: vy};
|
||
|
|
||
|
this.balls.push(b);
|
||
|
}
|
||
|
|
||
|
|
||
|
this.gameLost = function(){
|
||
|
this.isPaused = true;
|
||
|
this.isLost = true;
|
||
|
if (!infoIsOpen) openInfo();
|
||
|
}
|
||
|
|
||
|
this.gameWon = function(){
|
||
|
this.isPaused = true;
|
||
|
this.isWon = true;
|
||
|
if (this.levelNum - 1 == levelReached){
|
||
|
levelReached++;
|
||
|
setCookie("levelReached", String(levelReached), 10);
|
||
|
checkLevelButtons(this.levelNum);
|
||
|
}
|
||
|
if (this.currentTime < getRecordTime(this.levelNum)){
|
||
|
setRecordTime(this.levelNum, this.currentTime);
|
||
|
}
|
||
|
if (!infoIsOpen) openInfo();
|
||
|
}
|
||
|
|
||
|
this.restart = function(){this.setDefault();}
|
||
|
|
||
|
this.pause = function(paused){
|
||
|
if (this.isWon || this.isLost) return;
|
||
|
if (paused){
|
||
|
pauseAnimation(true);
|
||
|
this.isPaused = true;
|
||
|
} else {
|
||
|
pauseAnimation(false);
|
||
|
this.isPaused = false;
|
||
|
if (infoIsOpen) closeInfo();
|
||
|
}
|
||
|
}
|
||
|
this.start = function(){
|
||
|
this.isStarted = true;
|
||
|
if (infoIsOpen) closeInfo();
|
||
|
}
|
||
|
|
||
|
this.lastTime = new Date().getTime();
|
||
|
|
||
|
this.renderTime = function(){
|
||
|
var d = new Date().getTime();
|
||
|
var passed = d - this.lastTime;
|
||
|
this.lastTime = d;
|
||
|
|
||
|
if (!this.isPaused && this.isStarted){
|
||
|
this.currentTime += passed;
|
||
|
setTotalTimePlayed(getTotalTimePlayed() + passed);
|
||
|
}
|
||
|
|
||
|
var timeString = toTimeString(this.currentTime);
|
||
|
|
||
|
$("#timeDiv span").html(timeString);
|
||
|
}
|
||
|
}
|