main v2.0
Benjamin Kraft 2 years ago
commit f8fc83424e
  1. 3
      .gitignore
  2. 244
      public/index.html
  3. BIN
      public/pictures/favicon.ico
  4. 379
      public/scripts/Level.js
  5. 116
      public/scripts/Main.js
  6. 76
      public/scripts/Objects.js
  7. 69
      public/scripts/Stats.js
  8. 168
      public/scripts/Switcher.js
  9. 61
      public/scripts/WindowEvents.js
  10. 354
      public/scripts/lib/BenjoLibrary.js
  11. 173
      public/scripts/sketch.js
  12. 290
      public/stylesheets/styles.css
  13. BIN
      public/thumbnail.png

3
.gitignore vendored

@ -0,0 +1,3 @@
.idea
.env
node_modules

@ -0,0 +1,244 @@
<html>
<head>
<meta charset="utf-8">
<script src="/lib/p5/p5.min.js" type="text/javascript"></script>
<script src="/lib/jquery/jquery.min.js" type="text/javascript"></script>
<script src="scripts/lib/BenjoLibrary.js" type="text/javascript"></script>
<script src="scripts/Main.js" type="text/javascript"></script>
<script src="scripts/sketch.js" type="text/javascript"></script>
<script src="scripts/Objects.js" type="text/javascript"></script>
<script src="scripts/Level.js" type="text/javascript"></script>
<script src="scripts/Switcher.js" type="text/javascript"></script>
<script src="scripts/WindowEvents.js" type="text/javascript"></script>
<script src="scripts/Stats.js" type="text/javascript"></script>
<link href="stylesheets/styles.css" rel="stylesheet">
<link href="pictures/favicon.ico" rel="icon" type="image/x-icon">
<title>Bricks v3.1 JS</title>
</head>
<body>
<div id="info">
<input id="closeButton" onclick="closeInfo(this)" type="button" value="X">
<div id="levelSelector">
<span id="levelLabel">Level:</span>
<input id="levelUp" onclick="addLevel(this, 1)" type="button" value="&uarr;">
<span id="currentLevel"></span>
<input id="levelDown" onclick="addLevel(this, -1)" type="button" value="&darr;">
</div>
<div id="rekordInfo">
<center>
<table>
<tr>
<td>Gesamtspielzeit:</td>
<td id="totalTimePlayed"></td>
</tr>
<tr>
<td>Gesamtanzahl Blöcke:</td>
<td id="totalBricksDestroyed"></td>
</tr>
</table>
<table>
<tr>
<td>Blöcke</td>
<td>Level</td>
<td>Rekordzeit</td>
</tr>
</table>
</center>
</div>
<div id="controlsInfo">
<table>
<tr>
<td>Start / Stop:</td>
<td>SPACE</td>
</tr>
<tr>
<td>Bewegen:</td>
<td>&larr; &rarr;</td>
</tr>
<tr>
<td>Neustart:</td>
<td>SHIFT + R</td>
</tr>
<tr>
<td>Daten löschen:</td>
<td>SHIFT + D</td>
</tr>
<tr>
<td>Interface Aus/An:</td>
<td>ESC / TAB</td>
</tr>
<tr>
<td colspan="2">
<input id="infoButton" onclick="openInstructions(); this.blur();" type="button" value="Anleitung">
</td>
</tr>
</table>
</div>
</div>
<div id="openButton">
<input onclick="openInfo(this)" type="button" value=">>>">
</div>
<div id="timeDiv">
<span></span>
</div>
<div id="instructions">
<div id="instructionsWrapper">
<h1 id="instructionsHeader">Anleitung Bricks v3.1</h1>
<div id="instructionsContent">
<h2><u>Über das Spiel:</u></h2>
<p>
Die Aufgabe in dem Spiel besteht darin, jeden farbigen Block auf dem Spielfeld
mithilfe des Paddleboards zu zerstören!
Spezielle Items können helfen...oder nicht :D
</p>
<p>
Alle deine Statistiken und Fortschritte werden in Cookies gespeichert,
also stelle sicher, dass dein Browser Cookies zulässt und diese nicht
automatisch löscht.
</p>
<p>
Ein Level ist gewonnen wenn alle farbigen Blöcke zerstört wurden
und es ist verloren wenn alle Bälle aus dem Spielfeld verschwinden. Aber keine Sorge,
du hast eine unendliche Anzahl an Zügen :)<br>
Jedes mal, wenn du ein Level gewinnst, bist du in der Lage das Nächsthöhere zu starten.
</p>
<h2><u>Gameplay → Blöcke:</u></h2>
<p>
Bis jetzt gibt es 9 verschiedene Arten von Blöcken:
</p>
<table id="colors">
<tr>
<td>1</td>
<td>Dunkelgrün</td>
<td></td>
</tr>
<tr>
<td>2</td>
<td>Hellgrün</td>
<td></td>
</tr>
<tr>
<td>3</td>
<td>Hellblau</td>
<td></td>
</tr>
<tr>
<td>4</td>
<td>Dunkelblau</td>
<td></td>
</tr>
<tr>
<td>5</td>
<td>Violett</td>
<td></td>
</tr>
<tr>
<td>6</td>
<td>Rot</td>
<td></td>
</tr>
<tr>
<td>7</td>
<td>Orange</td>
<td></td>
</tr>
<tr>
<td>8</td>
<td>Gelb</td>
<td></td>
</tr>
<tr>
<td>(9)</td>
<td>Grau</td>
<td></td>
</tr>
</table>
<p>
Jeder Treffer auf einen Block verringert dessen Status um 1,
bis dieser 0 ist, denn dann ist der Block "tot" und verschwindet.
<br>
Die grauen Blöcke mit dem Wert 9 bzw. -1 sind eine Ausnahme, da sie unzerstörbar sind.
</p>
<h2><u>Gameplay → Items:</u></h2>
<p>
Ab und zu entsteht ein Item, nachdem ein Block zerstört wurde, um
es aufzusammeln, benutzt du ganz einfach dein Paddleboard -
Deine Bälle können sie nicht aufsammeln.
Je höher dein Level, desto häufiger entstehen Items, du wirst sie
anfangs also nur sehr selten antreffen.
</p>
<p>
Hier sind alle Items gelistet:
</p>
<table id="items">
<tr>
<td>Ball</td>
<td>→ Boost</td>
<td></td>
</tr>
<tr>
<td>Paddle</td>
<td>→ Boost</td>
<td></td>
</tr>
<tr>
<td>Ball</td>
<td>→ Slow</td>
<td></td>
</tr>
<tr>
<td>Paddle</td>
<td>→ Slow</td>
<td></td>
</tr>
<tr>
<td>Ball</td>
<td>→ Creator</td>
<td></td>
</tr>
<tr>
<td>Brick</td>
<td>→ Repair</td>
<td></td>
</tr>
</table>
<p>
Ein Boost gibt dem Objekt einen permanenten Geschwindigkeitsschub,
während ein Slow das Gegenteil verursacht.<br>
Der Ball-Creator fügt dem Spiel einen neuen Ball hinzu.
</p>
<p>
Pass auf bei dem Repair-Item,
denn das macht <b>jeden</b> Block im aktuellen Spiel
eine Stufe stärker.
</p>
<h2><u>Weitere Informationen:</u></h2>
<p>
Dieses Spiel wurde nicht fürs Handy programmiert, dort sind viele Bugs anzutreffen.
Alle nötigen Hotkeys sind links in der Info-Box aufgelistet.
</p>
<p>
Ich benutze für dieses Spiel JavaScript in Kombination mit der Processing
Library p5 von Lauren McCarthy und der sehr nützlichen auf HTML-DOM arbeitenden Library jQuery.
</p>
<h2><u>Changelog:</u></h2>
<p>
<b>Version 3.0:</b><br>
Erste eigene Web-Version von "Bricks"
</p>
<p>
<b>Version 3.1:</b><br>
Die ersten 5 Level hinzugefügt. Viel Spaß!
</p>
<p style="font-size: 20px; margin-top: 50px;">
Erstellt und veröffentlicht von BenjoCraeft,<br>
Gamer, Programmierer
</p>
<p style="font-size: 20px; float: right;">
Schließe diese Box mit ESC
</p>
</div>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

@ -0,0 +1,379 @@
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);
}
}

@ -0,0 +1,116 @@
var currentGame = null;
var infoIsMoving = false;
var infoIsOpen = true;
var instructionsOpen = false;
var testMode = false;
var animationDuration = 300;
function addLevel(HTMLInputElement, add){
HTMLInputElement.blur();
var currentLevelNum = parseInt($("#currentLevel").html());
var newLevelNum = currentLevelNum + add;
$("#currentLevel").html(newLevelNum);
checkLevelButtons(newLevelNum);
currentGame = new Level(newLevelNum);
}
function setRekordInfo(){
for (var i = 1; i <= levelCount; i++){
var bricks = getTotalBricksDestroyed(i);
var time = getRecordTime(i);
time = time == Infinity ? "---" : toTimeString(time);
$("#rekordInfo table:eq(1) tr:eq(" + i + ") td:eq(0)").text(bricks);
$("#rekordInfo table:eq(1) tr:eq(" + i + ") td:eq(2)").text(time);
}
var time = toTimeString(getTotalTimePlayed(), true);
var bricks = getTotalBricksDestroyedGlobal();
$("#totalTimePlayed").text(time);
$("#totalBricksDestroyed").text(bricks);
}
function checkLevelButtons(level) {
$("#levelUp").removeAttr("disabled");
$("#levelUp").css("cursor", "pointer");
$("#levelDown").removeAttr("disabled");
$("#levelDown").css("cursor", "pointer");
if (level == levelCount || level == levelReached + 1){
$("#levelUp").attr("disabled", "disabled");
$("#levelUp").css("cursor", "auto");
}
if (level == 1){
$("#levelDown").attr("disabled", "disabled");
$("#levelDown").css("cursor", "auto");
}
}
function setInfoStyles(){
$("#levelLabel, #currentLevel").css("font-size", String($("#levelSelector").outerHeight() * 0.25) + "px");
$("#levelUp, #levelDown").css("font-size", String($("#levelSelector").outerHeight() * 0.2) + "px");
$("#closeButton").css({
"width": String($("#closeButton").outerHeight()) + "px",
"font-size": String($("#closeButton").outerHeight() * 0.6) + "px"
});
$("#controlsInfo table tr td").css("font-size", String($("#controlsInfo table tr td").innerHeight() * 0.3) + "px");
}
function closeInfo(HTMLInputElement){
try {HTMLInputElement.blur();}catch(e){}
if (infoIsMoving) return;
infoIsMoving = true;
$("#info *").hide();
$("#info").animate({
width: 0
}, animationDuration, function(){
$("#openButton").show();
$("#openButton").animate({
width: 60
}, animationDuration, function(){
infoIsMoving = false;
infoIsOpen = false;
});
});
}
function openInfo(HTMLInputElement){
try {HTMLInputElement.blur();} catch(e) {}
if (infoIsMoving){
return;
}
infoIsMoving = true;
$("#openButton").animate({
width: 0
}, animationDuration, function() {
$("#openButton").hide();
$("#info").animate({
width: 450
}, animationDuration, function() {
$("#info *").show();
infoIsMoving = false;
infoIsOpen = true;
});
});
}
function pauseAnimation(paused){
//TODO
}
function openInstructions(){
$("#instructions").show();
instructionsOpen = true;
}
function closeInstructions(){
$("#instructions").hide();
instructionsOpen = false;
}
function toggleTestMode(){
testMode = !testMode;
}

@ -0,0 +1,76 @@
function Paddle(){
this.isRectangle = true;
this.isPaddle = true;
this.move = function(){
if (keyIsDown(LEFT_ARROW) && this.x - strokePadding > 0) this.x -= this.v;
if (keyIsDown(RIGHT_ARROW) && this.x + this.width + strokePadding < wWidth) this.x += this.v;
}
}
var itemCount = 6; //Change if necessary
var FastBall = 1;
var FastPaddle = 2;
var SlowBall = 3;
var SlowPaddle = 4;
var CreateBall = 5;
var UpgradeBricks = 6;
function Item(x, y, radius, v, item){
this.isItem = true;
this.isEllipse = true;
this.x = x;
this.y = y;
this.radius = radius;
this.v = v;
this.item = item;
this.move = function() {this.y += this.v}
}
function Brick(){
this.isRectangle = true;
this.isBrick = true;
}
function Frameborder(x, y, width, height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.isRectangle = true;
this.isFrameborder = true;
this.isBrick = false;
}
function Ball(){
this.isEllipse = true;
this.calcVelocityX = function(p, vx){
var divider = (this.x - (p.x - this.radius)) / (p.width + this.radius * 2 + strokePadding * 4); //Number between 0 and 1
var range = divider - 0.5; //Number between -0.5 and 0.5
range = range * this.v.mag / 0.5; //Number between -magnitude and magnitude
range += vx; //Number between -(magnitude+abs(vx)) and magnitude+abs(vx)
newVx = range * this.v.mag / (this.v.mag + abs(vx)); //Number between -magnitude and magnitude
return newVx;
}
this.calcVelocityY = function(){
var vy = sqrt(pow(this.v.mag, 2) - pow(this.v.x, 2)); //Pythagoras to keep velocity constant
return vy;
}
this.isLost = function(){
var b = this;
if (b.y - b.radius > wHeight) return true;
return false;
}
this.move = function(){
this.x += this.v.x;
this.y += this.v.y;
}
}

@ -0,0 +1,69 @@
//Only change if added more cases in LevelSwitcher
var levelCount = 5;
//Global: Amount of reached levels
var levelReached = null;
//Global: Erases every Cookie and starts Level 1 with 0 levelReached
function deleteMemory(){
clearStorage();
currentGame.totalBricksDestroyed = getTotalBricksDestroyed(currentGame.levelNum);
currentGame.recordTime = getRecordTime(currentGame.levelNum);
setRekordInfo();
$("#currentLevel").text("1");
checkLevelButtons(1);
currentGame = new Level(1);
}
//Level: Returns the shortest time ever played on that level
function getRecordTime(level){
var time = getItem("rekordTime" + level);
time = time == null ? Infinity : parseInt(time);
return time;
}
//Global: Returns the total time played from every level
function getTotalTimePlayed(){
var time = getItem("totalTimePlayed");
time = time == null ? 0 : parseInt(time);
return time;
}
//Level: Returns the total amount of destroyed bricks of that level
function getTotalBricksDestroyed(level){
var bricks = getItem("totalBricksDestroyed" + level);
bricks = bricks == null ? 0 : parseInt(bricks);
return bricks;
}
//Global: Returns the total global amount of destroyed bricks
function getTotalBricksDestroyedGlobal(){
var totalBricks = 0;
for (var i = 1; i <= levelCount; i++){
var bricks = getItem("totalBricksDestroyed" + i);
bricks = bricks == null ? 0 : parseInt(bricks);
totalBricks += bricks;
}
return totalBricks;
}
//Level: Sets a new record time for a specific level
function setRecordTime(level, time){
//storeItem("rekordTime" + level, String(time), 10);
time = toTimeString(time);
$("#rekordInfo table:eq(1) tr:eq(" + level + ") td:eq(2)").text(time);
}
//Global: Sets the total time played from every level
function setTotalTimePlayed(time){
//storeItem("totalTimePlayed", String(time), 10);
time = toTimeString(time, true);
$("#totalTimePlayed").text(time);
}
//Level: Sets the total amount of destroyed bricks for a specific level
function setTotalBricksDestroyed(level, bricks){
//storeItem("totalBricksDestroyed" + level, String(bricks), 10);
$("#rekordInfo table:eq(1) tr:eq(" + level + ") td:eq(0)").text(bricks);
$("#totalBricksDestroyed").text(getTotalBricksDestroyedGlobal());
}

@ -0,0 +1,168 @@
var stateCount = 9;
function colorSwitch(state){
switch (state){
case -1: return "#373737"; //Gray - Invincible
case 0: return false; //No brick
case 1: return "#008800"; //Dark green
case 2: return "#33FF33"; //Light green
case 3: return "#99BBFF"; //Light blue
case 4: return "#0000BB"; //Dark blue
case 5: return "#AA00DD"; //Purple
case 6: return "#FF0000"; //Red
case 7: return "#FF7800"; //Orange
case 8: return "#FFFF00"; //Yellow
//Add new colors here
default: return "#373737";
}
}
function tableSwitch(levelNum, level){
var c = 0, r = 0;
switch (levelNum){
case 1:
case 2:
c = 5;
r = 10;
break;
case 3:
case 4:
c = 7;
r = 12;
break;
case 5:
case 6:
c = 9;
r = 14;
break;
case 7:
case 8:
c = 11;
r = 16;
break;
case 9:
case 10:
c = 13;
r = 18;
break;
case 11:
case 12:
c = 15;
r = 20;
break;
case 13:
case 14:
c = 17;
r = 22;
break;
case 15:
case 16:
c = 19;
r = 24;
break;
case 17:
case 18:
c = 21;
r = 26;
break;
case 19:
case 20:
c = 23;
r = 28;
break;
}
return {cols: c, rows: r};
}
function designSwitch(levelNum, c, r){
var state = 0
switch (levelNum) {
case 1:
if (r == 3 || r == 6 || r == 9) state = 1;
break;
case 2:
if ((c == 1 || c == 3 || c == 5) && r % 2 == 0) state = 1;
break;
case 3:
if (r == 5 || r == 9){
if (c == 4) state = -1;
else if (c == 3 || c == 5) state = 2;
else state = 1;
}
break;
case 4:
if (r == 9 && c > 2 && c < 6) state = -1;
if (r == 8 && c == 4 || r == 7 && c > 2 && c < 6 || r == 6 && c > 1 && c < 7 || r == 5 && c > 2 && c < 6 || r == 4 && c == 4) state = 2;
break;
case 5:
if (r == 1 || r == 14){
if (c == 1 || c == 9) state = 3;
if (c == 2 || c == 3 || c == 7 || c == 8) state = 2;
if (c > 3 && c < 7) state = 1;
}
if (r == 2 || r == 13){
if (c < 3 || c > 7) state = 2;
}
if (r == 3 || r == 12){
if (c == 1 || c == 9) state = 2;
}
if (r > 3 && r < 12){
if (c == 1 || c == 9) state = 1;
if (r > 6 && r < 9 && c > 3 && c < 7) state = -1;
}
break;
case 6:
break;
case 7:
break;
case 8:
break;
case 9:
break;
case 10:
break;
case 11:
break;
case 12:
break;
case 13:
break;
case 14:
break;
case 15:
break;
case 16:
break;
case 17:
break;
case 18:
break;
case 19:
break;
case 20:
break;
}
return state;
}

@ -0,0 +1,61 @@
window.onkeydown = function(e){
var key = e.keyCode ? e.keyCode : e.which;
if (instructionsOpen){
if (key == ESCAPE){
closeInstructions();
e.preventDefault();
}
return;
}
switch (key) {
case ESCAPE:
e.preventDefault();
closeInfo(null);
break;
case TAB:
e.preventDefault();
openInfo(null);
break;
case 32: //Space
e.preventDefault();
if (currentGame.isPaused){
currentGame.pause(false);
} else if (currentGame.isStarted && !currentGame.isPaused) {
currentGame.pause(true);
}
if (!currentGame.isStarted){
currentGame.start();
}
break;
case SHIFT:
e.preventDefault();
if (keyIsDown(68)){
//Shift + D
deleteMemory();
} else if (keyIsDown(82)){
//Shift + R
currentGame.restart();
} else if (keyIsDown(78)){
//Shift + N
toggleNotifications();
}
break;
case 68: //D
e.preventDefault();
if (keyIsDown(SHIFT)){
//D + Shift
deleteMemory();
}
break;
case 82: //R
e.preventDefault();
if (keyIsDown(SHIFT)){
//R + Shift
currentGame.restart();
}
break;
}
}

@ -0,0 +1,354 @@
var TOP = 1;
var RIGHT = 2
var BOTTOM = 3;
var LEFT = 4;
var TOP_RIGHT = 5;
var BOTTOM_RIGHT = 6;
var BOTTOM_LEFT = 7;
var TOP_LEFT = 8;
var wWidth = window.innerWidth;
var wHeight = window.innerHeight;
var oldWHeight;
var oldWWidth;
function updateVars(){
oldWWidth = wWidth;
oldWHeight = wHeight;
wWidth = window.innerWidth;
wHeight = window.innerHeight;
}
function collisionDetection(obj0, obj1){
var sp = strokePadding;
if (obj0.isEllipse && obj1.isRectangle){
//Ball
var b = obj0;
//Rectangle
var r = obj1;
for (var i = 0; i < TWO_PI; i += PI / 32){
/* Check every borderpoint of the ball beginning
at the top in clock direction up to top again */
// Ball Center X
var bcx = b.x;
// Ball Center Y
var bcy = b.y;
// Ball Border X
var bbx = b.x + sin(i) * b.radius;
// Ball Border Y inverted because Y = 0 is the TOP of the screen
var bby = b.y - cos(i) * b.radius;
// Rectangle Width
var rW = r.width + 2 * sp;
// Rectangle Height
var rH = r.height + 2 * sp;
// Rectangle Border X
var rX = r.x - sp;
// Rectangle Border Y
var rY = r.y - sp;
// Objects touch
if (bbx > rX && bbx < rX + rW
&& bby > rY && bby < rY + rH){
// STRAIGHT FACES //
//Top/Bottom touch
if (bcx > rX && bcx < rX + rW){
//Top touch
if (b.v.y > 0) return {isTouching: true, location: TOP};
//Bottom touch
if (b.v.y < 0) return {isTouching: true, location: BOTTOM};
}
//Left/Right touch
if (bcy > rY && bcy < rY + rH){
//Left touch
if (b.v.x > 0) return {isTouching: true, location: LEFT};
//Right touch
if (b.v.x < 0) return {isTouching: true, location: RIGHT};
}
// CORNERS //
// BOTTOM Left/Right
if (i > 0 && i <= PI / 2) return {isTouching: true, location: BOTTOM_LEFT};
//LEFT Bottom/Top
if (i > PI / 2 && i <= PI) return {isTouching: true, location: TOP_LEFT};
//TOP Left/Right
if (i > PI && i <= PI + PI / 2) return {isTouching: true, location: TOP_RIGHT};
//RIGHT Bottom/Top
if (i > PI + PI / 2 && i <= TWO_PI) return {isTouching: true, location: BOTTOM_RIGHT};
}
}
}
if (obj0.isEllipse && obj1.isEllipse){
//Ball 1
var b1 = obj0;
//Ball 2
var b2 = obj1;
//Balls are close to each other
if (b1.x + b1.radius > b2.x - b2.radius
&& b1.x - b1.radius < b2.x + b2.radius
&& b1.y + b1.radius > b2.y - b2.radius
&& b1.y - b1.radius < b2.y + b2.radius){
var distance = sqrt(pow(b1.x - b2.x, 2) + pow(b1.y - b2.y, 2));
if (distance < b1.radius + b2.radius) return {isTouching: true};
}
}
return {isTouching: false, location: 0};
}
function performCollision(obj0, obj1, collision){
if (obj0.isEllipse){
var ball = obj0;
//Ball collides with frameborder
if (obj1.isFrameborder){
switch (collision.location){
case BOTTOM:
ball.v.y *= -1;
break;
case LEFT:
case RIGHT:
ball.v.x *= -1;
break;
}
if (testMode && collision.location == TOP) ball.v.y *= -1;
ball.move();
}
//Ball collides with any brick
if (obj1.isBrick){
switch (collision.location){
case TOP:
case BOTTOM:
ball.v.y *= -1;
ball.move();
return;
case LEFT:
case RIGHT:
ball.v.x *= -1;
ball.move();
return;
case TOP_LEFT:
var cornerX = obj1.x;
var cornerY = obj1.y;
break;
case TOP_RIGHT:
var cornerX = obj1.x + obj1.width;
var cornerY = obj1.y;
break;
case BOTTOM_LEFT:
var cornerX = obj1.x;
var cornerY = obj1.y + obj1.height;
break;
case BOTTOM_RIGHT:
var cornerX = obj1.x + obj1.width;
var cornerY = obj1.y + obj1.height;
break;
}
var nx = ball.x - cornerX;
var ny = ball.y - cornerY;
var length = sqrt(nx * nx + ny * ny);
nx /= length;
ny /= length;
var projection = ball.v.x * nx + ball.v.y * ny;
ball.v.x = ball.v.x - 2 * projection * nx;
ball.v.y = ball.v.y - 2 * projection * ny;
ball.move();
}
//Ball collides with paddleboard
if (obj1.isPaddle){
switch (collision.location){
case TOP:
case TOP_LEFT:
case TOP_RIGHT:
ball.v.x = ball.calcVelocityX(obj1, ball.v.x);
ball.v.y = -ball.calcVelocityY();
ball.move();
return;
case LEFT:
case RIGHT:
ball.v.x *= -1;
ball.move();
return;
case BOTTOM_LEFT:
var cornerX = obj1.x;
var cornerY = obj1.y + obj1.height;
break;
case BOTTOM_RIGHT:
var cornerX = obj1.x + obj1.width;
var cornerY = obj1.y + obj1.height;
break;
}
var nx = ball.x - cornerX;
var ny = ball.y - cornerY;
var length = sqrt(nx * nx + ny * ny);
nx /= length;
ny /= length;
var projection = ball.v.x * nx + ball.v.y * ny;
ball.v.x = ball.v.x - 2 * projection * nx;
ball.v.y = ball.v.y - 2 * projection * ny;
ball.move();
}
//Ball collides with other ball
if (obj1.isEllipse){
//Ball 1
var b1 = obj0;
//Ball 2
var b2 = obj1;
//Set mass equal to radius of each ball
b1.mass = b1.radius;
b2.mass = b2.radius;
//Colliding angle of ball 1 to ball 2 using arc tan of both x and y differences
var collisionAngle = atan2((b2.y - b1.y), (b2.x - b1.x));
//Converting directions of velocity vector of balls into angles
var d1 = atan2(b1.v.y, b1.v.x);
var d2 = atan2(b2.v.y, b2.v.x);
//Ignoring mass effects new velocites are simply magnitude multiplied with value of angle differences
var newXspeed1 = b1.v.mag * cos(d1 - collisionAngle);
var newYspeed1 = b1.v.mag * sin(d1 - collisionAngle);
var newXspeed2 = b2.v.mag * cos(d2 - collisionAngle);
var newYspeed2 = b2.v.mag * sin(d2 - collisionAngle);
//According to the principle of linear momentum, kinetic energy stays the same after collision, so velocities are now related to masses
var finalXspeed1 = ((b1.mass - b2.mass) * newXspeed1 + b2.mass * 2 * newXspeed2) / (b1.mass + b2.mass);
var finalYspeed1 = newYspeed1;
var finalXspeed2 = (b1.mass * 2 * newXspeed1 + (b2.mass - b1.mass) * newXspeed2) / (b1.mass + b2.mass);
var finalYspeed2 = newYspeed2;
//Values of collisionAngle
var cosAngle = cos(collisionAngle);
var sinAngle = sin(collisionAngle);
//To also keep velocites relative to pure collisionAngle, subtract sin*x from cos*x and add sin*y to cos*y because coordSystem has y = 0 on the top
var u1x = cosAngle * finalXspeed1 - sinAngle * finalYspeed1;
var u1y = sinAngle * finalXspeed1 + cosAngle * finalYspeed1;
var u2x = cosAngle * finalXspeed2 - sinAngle * finalYspeed2;
var u2y = sinAngle * finalXspeed2 + cosAngle * finalYspeed2;
//Set new velocities to both balls
b1.v.x = u1x;
b1.v.y = u1y;
b2.v.x = u2x;
b2.v.y = u2y;
//Update magnitude
b1.v.mag = sqrt(pow(b1.v.x, 2) + pow(b1.v.y, 2));
b2.v.mag = sqrt(pow(b2.v.x, 2) + pow(b2.v.y, 2));
//Move balls one vx/vy forward to avoid double inverting collision detection
b1.x += b1.v.x;
b1.y += b1.v.y;
b2.x += b2.v.x;
b2.y += b2.v.y;
}
}
}
function toTimeString(time, hoursWanted){
var time = floor(time / 10);
var hs = String(floor(time % 100));
var fs = String(floor((time / 100) % 60));
if (hoursWanted){
var min = String(floor(((time / 100) / 60) % 60));
var hr = String(floor(((time / 100) / 60) / 60));
if (hs.length < 2) hs = "0" + hs;
if (fs.length < 2) fs = "0" + fs;
if (min.length < 2) min = "0" + min;
if (hr.length < 2) hr = "0" + hr;
var timeString = hr + ":" + min + ":" + fs + ":" + hs;
} else {
var min = String(floor(((time / 100) / 60) % 60));
if (hs.length < 2) hs = "0" + hs;
if (fs.length < 2) fs = "0" + fs;
if (min.length < 2) min = "0" + min;
var timeString = min + ":" + fs + ":" + hs;
}
return timeString;
}
function setCookie(name, value, years){
var expires = "";
if (years){
var date = new Date();
date.setTime(date.getTime() + (years * 365 * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + value + expires + "; path=/";
}
function getCookie(name){
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++){
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function deleteCookies(){
for (var i = 0; i < arguments.length; i++){
setCookie(arguments[i], "", -1);
}
}

@ -0,0 +1,173 @@
var lr;
function setup(){
lr = getItem("levelReached");
lr = lr == null ? 0 : parseInt(lr);
levelReached = lr
createCanvas(window.innerWidth, window.innerHeight);
//Layout Setup
$("#openButton").hide();
setInfoStyles();
for (var i = 1; i <= levelCount; i++){
$("#rekordInfo table:eq(1)").append("<tr><td></td><td>" + i + "</td><td></td></tr>");
var bgColor;
var fgColor;
if (i % 2 == 0){
bgColor = "rgba(200, 0, 0, 0.5)";
fgColor = "#FFF";
}
if (i % 2 != 0){
bgColor = "rgba(0, 200, 0, 0.5)";
fgColor = "#000";
}
$("#rekordInfo table:eq(1) tr:eq(" + i + ")").css({
"background-color": bgColor,
"color": fgColor
});
}
setRekordInfo();
for (var i = 0; i < stateCount; i++){
$("#colors tr:eq(" + i + ") td:eq(2)").html("<canvas id=\"brick" + i + "\"></canvas>");
$("#brick" + i).attr({
"width": String(wWidth * 0.3 * 0.6),
"height": String($("#colors").css("font-size").slice(0, 2) * 2)
});
$("#brick" + i).css({
"border": strokePadding * 2 + "px solid #000",
"border-radius": strokePadding * 2
});
var c = document.getElementById("brick" + i);
var ctx = c.getContext("2d");
ctx.fillStyle = colorSwitch(i + 1);
ctx.fillRect(0, 0, c.width, c.height);
}
for (var i = 0; i < itemCount; i++){
$("#items tr:eq(" + i + ") td:eq(2)").html("<canvas id=\"item" + i + "\"></canvas>");
$("#item" + i).attr({
"width": String(wWidth * 0.3 * 0.3),
"height": String($("#items").css("font-size").slice(0, 2) * 3)
});
var c = document.getElementById("item" + i);
var ctx = c.getContext("2d");
var ballX = c.width / 2;
var ballY = c.height / 2;
var ballR = c.height / 2;
var lw = ballR * 0.2;
ctx.beginPath();
ctx.fillStyle = "#000000";
ctx.arc(ballX, ballY, ballR, 0, TWO_PI);
ctx.fill();
ctx.closePath();
var rectX = ballX - ballR * sin(5 * PI / 8) + lw;
var rectY = ballY + ballR * cos(5 * PI / 8) + lw;
var rectW = ballR * 2 * sin(5 * PI / 8) - lw * 2;
var rectH = ballR * 2 * abs(cos(5 * PI / 8)) - lw * 2;
ctx.beginPath();
ctx.lineJoin = "round";
switch (i + 1){
case FastBall:
ctx.fillStyle = "#00FF00";
ctx.arc(ballX, ballY, ballR * 0.625, 0, TWO_PI);
ctx.fill();
break;
case FastPaddle:
ctx.strokeStyle = "#00FF00";
ctx.fillStyle = "#00FF00";
ctx.moveTo(rectX, rectY);
ctx.lineTo(rectX + rectW, rectY);
ctx.lineTo(rectX + rectW, rectY + rectH);
ctx.lineTo(rectX, rectY + rectH);
ctx.lineTo(rectX, rectY);
ctx.lineTo(rectX + rectW, rectY);
ctx.lineTo(rectX, rectY);
ctx.stroke();
ctx.fill();
break;
case SlowBall:
ctx.fillStyle = "#FF0000";
ctx.arc(ballX, ballY, ballR * 0.625, 0, TWO_PI);
ctx.fill();
break;
case SlowPaddle:
ctx.strokeStyle = "#FF0000";
ctx.fillStyle = "#FF0000";
ctx.moveTo(rectX, rectY);
ctx.lineTo(rectX + rectW, rectY);
ctx.lineTo(rectX + rectW, rectY + rectH);
ctx.lineTo(rectX, rectY + rectH);
ctx.lineTo(rectX, rectY);
ctx.lineTo(rectX + rectW, rectY);
ctx.lineTo(rectX, rectY);
ctx.stroke();
ctx.fill();
break;
case CreateBall:
var lineLength = ballR * 0.5;
ctx.lineWidth = lw;
ctx.strokeStyle = "#00FF00";
ctx.moveTo(ballX, ballY);
ctx.lineTo(ballX + lineLength, ballY);
ctx.lineTo(ballX - lineLength, ballY);
ctx.lineTo(ballX, ballY);
ctx.moveTo(ballX, ballY);
ctx.lineTo(ballX, ballY + lineLength);
ctx.lineTo(ballX, ballY - lineLength);
ctx.lineTo(ballX, ballY);
ctx.stroke();
break;
case UpgradeBricks:
var lineLength = ballR * 0.5;
ctx.lineWidth = lw;
ctx.strokeStyle = "#FF0000";
ctx.moveTo(ballX, ballY);
ctx.lineTo(ballX + lineLength, ballY);
ctx.lineTo(ballX - lineLength, ballY);
ctx.lineTo(ballX, ballY);
ctx.moveTo(ballX, ballY);
ctx.lineTo(ballX, ballY + lineLength);
ctx.lineTo(ballX, ballY - lineLength);
ctx.lineTo(ballX, ballY);
ctx.stroke();
break;
case UpgradeBricks:
}
ctx.closePath();
}
//Level Setup
var level = levelReached + 1;
if (level > levelCount) level = levelCount;
currentGame = new Level(level);
$("#currentLevel").html(level);
checkLevelButtons(level);
openInstructions();
}
function draw(){
currentGame.drawShapes();
currentGame.renderTime();
}

@ -0,0 +1,290 @@
/* General Styles*/
body
{
margin: 0;
padding: 0;
}
canvas
{
vertical-align: top;
}
input
{
cursor: pointer;
}
/* Infolable Styles*/
#info
{
display: block;
position: absolute;
height: 80%;
width: 450px;
top: 5%;
background-color: rgba(50, 50, 50, 0.6);
border-radius: 0 0 40px 0;
box-shadow: 10px 20px 20px #000;
color: #FFF;
}
#info *
{
position: absolute;
}
#levelSelector, #rekordInfo, #controlsInfo
{
left: 12.5%;
width: 75%;
background-color: rgba(50, 50, 50, 0.6);
border-radius: 10px;
border: 4px solid #000;
}
#closeButton
{
right: 0;
height: 5%;
background-color: #000;
border-color: #000;
color: #FFF;
border-radius: 0 0 0 10px;
}
#openButton
{
display: block;
position: absolute;
width: 0px;
height: 50px;
top: 5%;
border-radius: 0 5px 5px 0;
background-color: rgba(50, 50, 50, 0.5);
box-shadow: 5px 5px 5px #000;
}
#openButton input
{
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0);
border-color: rgba(50, 50, 50, 0.6);
border-left: none;
font-size: 20px;
}
#levelSelector
{
top: 5%;
height: 17.5%;
}
#levelLabel, #currentLevel, #levelUp, #levelDown
{
width: 50%;
height: 33%;
text-align: center;
}
#levelLabel
{
top: 33%;
left: 0;
}
#currentLevel
{
top: 33%;
left: 50%;
}
#levelUp
{
top: 0;
left: 50%;
background-color: lightgreen;
border-color: lightgreen;
border-radius: 0 10px 0 0;
}
#levelDown
{
top: 66%;
left: 50%;
background-color: lightcoral;
border-color: lightcoral;
border-radius: 0 0 10px 0;
}
#rekordInfo
{
top: 25%;
height: 30%;
overflow-y: scroll;
}
#rekordInfo *
{
position: relative;
}
#rekordInfo table
{
width: 95%;
margin-top: 5%;
}
#rekordInfo table:nth-child(1) tr td
{
padding: 5%;
color: #FFF;
}
#rekordInfo table:nth-child(2)
{
text-align: center;
border-collapse: collapse;
border: 5px solid #000;
}
#rekordInfo table:nth-child(2) tr td
{
width: 33%;
padding: 0;
}
#rekordInfo table:nth-child(2) tr:nth-child(1) td
{
height: 50px;
background-color: rgba(100, 100, 255, 0.5);
font-weight: bold;
}
#controlsInfo
{
top: 57.5%;
height: 37.5%;
}
#controlsInfo *
{
position: relative;
}
#controlsInfo table
{
color: #FFF;
left: 5%;
height: 100%;
width: 90%;
}
#infoButton
{
width: 100%;
height: 75%;
font-size: inherit;
background-color: #FFFF99;
}
/* Instructions */
#instructions
{
position: absolute;
display: none;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
}
#instructions p
{
font-size: 23px;
}
#instructionsWrapper
{
position: absolute;
width: 30%;
height: 80%;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
background-color: #888;
padding: 5%;
border-radius: 50px;
}
#instructionsHeader
{
position: absolute;
text-align: center;
margin: 0;
top: 5%;
left: 0;
width: 100%;
}
#instructionsContent
{
position: relative;
height: 100%;
width: 100%;
padding-right: 2.5%;
overflow-y: auto;
}
#colors, #items
{
width: 100%;
font-size: 25px;
}
#colors td, #items td
{
width: 33%;
}
#colors td:first-child
{
text-align: center;
}
/* Other Stuff */
#timeDiv
{
display: block;
position: absolute;
right: 0;
bottom: 0;
width: 200px;
height: 30px;
font-size: 24px;
text-align: center;
color: #BBB;
background-color: rgb(50, 50, 50);
border-radius: 10px 0 0 0;
border-top: 5px solid #000;
border-left: 5px solid #000;
}
#testMode
{
display: block;
position: absolute;
right: 0;
top: 0;
height: 50px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Loading…
Cancel
Save