/* style.css */
html, body {
height: 100%;
}
body {
margin: 0;
display: flex;
/* This centers our sketch horizontally. */
justify-content: center;
/* This centers our sketch vertically. */
align-items: center;
background-color: black;
}
var gridSpace = 30;
var fallingPiece;
var gridPieces = [];
var lineFades = [];
var gridWorkers = [];
var currentScore = 0;
var currentLevel = 1;
var linesCleared = 0;
var ticks = 0;
var updateEvery = 15;
var updateEveryCurrent = 15;
var fallSpeed = gridSpace * 0.5;
var pauseGame = false;
var gameOver = false;
var gameEdgeLeft = 150;
var gameEdgeRight = 450;
var colors = [
'#ecb5ff',
'#ffa0ab',
'#8cffb4',
'#ff8666',
'#80c3f5',
'#c2e77d',
'#fdf9a1',
];
function setup() {
createCanvas(600, 540);
fallingPiece = new playPiece();
fallingPiece.resetPiece();
textFont('Trebuchet MS');
}
function draw() {
var colorDark = "#071820",
colorLight = "#344c57",
colorBackground = "#ecf4cb";
background(colorBackground);
//Right side info
fill(25);
noStroke();
rect(gameEdgeRight, 0, 150, height);
//Left side info
rect(0, 0, gameEdgeLeft, height);
fill(colorBackground);
//Score rectangle
rect(450, 50, 150, 70);
//Next piece rectangle
rect(460, 300, 130, 130, 5, 5);
//Level rectangle
rect(460, 130, 130, 60, 5, 5);
//Lines rectangle
rect(460, 200, 130, 60, 5, 5);
fill(colorLight);
//Score lines
rect(450, 55, 150, 20);
rect(450, 80, 150, 4);
rect(450, 110, 150, 4);
fill(colorBackground);
//Score banner
rect(460, 30, 130, 35, 5, 5);
strokeWeight(3);
noFill();
stroke(colorLight);
//Score banner inner rectangle
rect(465, 35, 120, 25, 5, 5);
//Next piece inner rectangle
stroke(colorLight);
rect(465, 305, 120, 120, 5, 5);
//Level inner rectangle
rect(465, 135, 120, 50, 5, 5);
//Lines inner rectangle
rect(465, 205, 120, 50, 5, 5);
//Draw the info labels
fill(25);
noStroke();
textSize(24);
textAlign(CENTER);
text("Score", 525, 55);
text("Level", 525, 158);
text("Lines", 525, 228);
//Draw the actual info
textSize(24);
textAlign(RIGHT);
//The score
text(currentScore, 560, 105);
text(currentLevel, 560, 180);
text(linesCleared, 560, 250);
stroke(colorDark);
line(gameEdgeRight, 0, gameEdgeRight, height);
fallingPiece.show();
if(keyIsDown(DOWN_ARROW)) {
updateEvery = 2;
} else {
updateEvery = updateEveryCurrent;
}
if(!pauseGame) {
ticks++;
if(ticks >= updateEvery) {
ticks = 0;
fallingPiece.fall(fallSpeed);
}
}
for(let i = 0; i < gridPieces.length; i++) {
gridPieces[i].show();
}
for(let i = 0; i < lineFades.length; i++) {
lineFades[i].show();
}
if(gridWorkers.length > 0) {
gridWorkers[0].work();
}
//Explain the controls
textAlign(CENTER);
fill(255);
noStroke();
textSize(14);
text("Controls:\n↑\n← ↓ →\n", 75, 175);
text("Left and Right:\nmove side to side", 75, 250);
text("Up:\nrotate", 75, 300);
text("Down:\nfall faster", 75, 350);
//Game over text
if(gameOver) {
fill(colorDark);
textSize(64);
textAlign(CENTER);
text("Game\nOver!", 300, 270);
}
}
function lineBar(y, index) {
this.pos = new p5.Vector(gameEdgeLeft, y)
this.width = gameEdgeRight - gameEdgeLeft;
this.index = index;
this.show = function() {
fill(255);
noStroke();
rect(this.pos.x, this.pos.y, this.width, gridSpace);
if(this.width + this.pos.x > this.pos.x) {
this.width -= 10;
this.pos.x += 5;
} else {
lineFades.splice(this.index, 1);
//shiftGridDown(this.pos.y, gridSpace);
gridWorkers.push(new worker(this.pos.y, gridSpace));
}
}
}
function keyPressed() {
if(!pauseGame) {
if(keyCode === LEFT_ARROW) {
fallingPiece.input(LEFT_ARROW);
} else if(keyCode === RIGHT_ARROW) {
fallingPiece.input(RIGHT_ARROW);
}
if(keyCode === UP_ARROW) {
fallingPiece.input(UP_ARROW);
}
}
}
function playPiece() {
this.pos = new p5.Vector(0, 0);
this.rotation = 0;
this.nextPieceType = Math.floor(Math.random() * 7);
this.nextPieces = [];
this.pieceType = 0;
this.pieces = [];
this.orientation = [];
this.fallen = false;
this.nextPiece = function() {
this.nextPieceType = pseudoRandom(this.pieceType);
this.nextPieces = [];
var points = orientPoints(this.nextPieceType, 0);
var xx = 525, yy = 365;
if(this.nextPieceType != 0 && this.nextPieceType != 3) {
xx += (gridSpace * 0.5);
}
this.nextPieces.push(new square(xx + points[0][0] * gridSpace, yy + points[0][1] * gridSpace, this.nextPieceType));
this.nextPieces.push(new square(xx + points[1][0] * gridSpace, yy + points[1][1] * gridSpace, this.nextPieceType));
this.nextPieces.push(new square(xx + points[2][0] * gridSpace, yy + points[2][1] * gridSpace, this.nextPieceType));
this.nextPieces.push(new square(xx + points[3][0] * gridSpace, yy + points[3][1] * gridSpace, this.nextPieceType));
}
this.fall = function(amount) {
if(!this.futureCollision(0, amount, this.rotation)) {
this.addPos(0, amount);
this.fallen = true;
} else {
//WE HIT SOMETHING D:
if(!this.fallen) {
//Game over aka pause forever
pauseGame = true;
gameOver = true;
} else {
this.commitShape();
}
}
}
this.resetPiece = function() {
this.rotation = 0;
this.fallen = false;
this.pos.x = 330;
this.pos.y = -60;
this.pieceType = this.nextPieceType;
this.nextPiece();
this.newPoints();
}
this.newPoints = function() {
var points = orientPoints(this.pieceType, this.rotation);
this.orientation = points;
this.pieces = [];
this.pieces.push(new square(this.pos.x + points[0][0] * gridSpace, this.pos.y + points[0][1] * gridSpace, this.pieceType));
this.pieces.push(new square(this.pos.x + points[1][0] * gridSpace, this.pos.y + points[1][1] * gridSpace, this.pieceType));
this.pieces.push(new square(this.pos.x + points[2][0] * gridSpace, this.pos.y + points[2][1] * gridSpace, this.pieceType));
this.pieces.push(new square(this.pos.x + points[3][0] * gridSpace, this.pos.y + points[3][1] * gridSpace, this.pieceType));
}
//Whenever the piece gets rotated, this gets the new positions of the squares
this.updatePoints = function() {
if(this.pieces) {
var points = orientPoints(this.pieceType, this.rotation);
this.orientation = points;
for(var i = 0; i < 4; i++) {
this.pieces[i].pos.x = this.pos.x + points[i][0] * gridSpace;
this.pieces[i].pos.y = this.pos.y + points[i][1] * gridSpace;
}
}
}
//Adds to the position of the piece and it's square objects
this.addPos = function(x, y) {
this.pos.x += x;
this.pos.y += y;
if(this.pieces) {
for(var i = 0; i < 4; i++) {
this.pieces[i].pos.x += x;
this.pieces[i].pos.y += y;
}
}
}
//Checks for collisions after adding the x and y to the current positions and also applying the given rotation
this.futureCollision = function(x, y, rotation) {
var xx, yy, points = 0;
if(rotation != this.rotation) {
//Gets a new point orientation to check against
points = orientPoints(this.pieceType, rotation);
}
for(var i = 0; i < this.pieces.length; i++) {
if(points) {
xx = this.pos.x + points[i][0] * gridSpace;
yy = this.pos.y + points[i][1] * gridSpace;
} else {
xx = this.pieces[i].pos.x + x;
yy = this.pieces[i].pos.y + y;
}
//Check against walls and bottom
if(xx < gameEdgeLeft || xx + gridSpace > gameEdgeRight || yy + gridSpace > height) {
return true;
}
//Check against all pieces in the main gridPieces array (stationary pieces)
for(var j = 0; j < gridPieces.length; j++) {
if(xx === gridPieces[j].pos.x) {
if(yy >= gridPieces[j].pos.y && yy < gridPieces[j].pos.y + gridSpace) {
return true;
}
if(yy + gridSpace > gridPieces[j].pos.y && yy + gridSpace <= gridPieces[j].pos.y + gridSpace) {
return true;
}
}
}
}
}
//Handles input ;)
this.input = function(key) {
switch(key) {
case LEFT_ARROW:
if(!this.futureCollision(-gridSpace, 0, this.rotation)) {
this.addPos(-gridSpace, 0);
}
break;
case RIGHT_ARROW:
if(!this.futureCollision(gridSpace, 0, this.rotation)) {
this.addPos(gridSpace, 0);
}
break;
case UP_ARROW:
var rotation = this.rotation + 1;
if(rotation > 3) {
rotation = 0;
}
if(!this.futureCollision(gridSpace, 0, rotation)) {
this.rotate();
}
break;
}
}
//Rotates the piece by one
this.rotate = function() {
this.rotation += 1;
if(this.rotation > 3) {
this.rotation = 0;
}
this.updatePoints();
}
//Displays the piece's square objects
this.show = function() {
for(var i = 0; i < this.pieces.length; i++) {
this.pieces[i].show();
}
for(var i = 0; i < this.nextPieces.length; i++) {
this.nextPieces[i].show();
}
}
//Add the pieces to the gridPieces
this.commitShape = function() {
for(var i = 0; i < this.pieces.length; i++) {
gridPieces.push(this.pieces[i])
}
this.resetPiece();
analyzeGrid();
}
}
function square(x, y, type) {
this.pos = new p5.Vector(x, y);
this.type = type;
this.show = function() {
strokeWeight(2);
var colorDark = "#092e1d",
colorMid = colors[this.type];
fill(colorMid);
stroke(25);
rect(this.pos.x, this.pos.y, gridSpace - 1, gridSpace - 1);
noStroke();
fill(255);
rect(this.pos.x + 6, this.pos.y + 6, 18, 2);
rect(this.pos.x + 6, this.pos.y + 6, 2, 16);
fill(25);
rect(this.pos.x + 6, this.pos.y + 20, 18, 2);
rect(this.pos.x + 22, this.pos.y + 6, 2, 16);
}
}
//Basically random with a bias against the same piece twice
function pseudoRandom(previous) {
var roll = Math.floor(Math.random() * 8);
if(roll === previous || roll === 7) {
roll = Math.floor(Math.random() * 7);
}
return roll;
}
//Checks until it can no longer find any horizontal staights
function analyzeGrid() {
var score = 0;
while(checkLines()) {
score += 100;
linesCleared += 1;
if(linesCleared % 10 === 0) {
currentLevel += 1;
//Increase speed here
if(updateEveryCurrent > 4) {
updateEveryCurrent -= 1;
}
}
}
if(score > 100) {
score *= 2;
}
currentScore += score;
}
function checkLines() {
var count = 0;
var runningY = -1;
var runningIndex = -1;
gridPieces.sort(function(a, b) {
return a.pos.y - b.pos.y;
});
for(var i = 0; i < gridPieces.length; i++) {
if(gridPieces[i].pos.y === runningY) {
count++;
if(count === 10) {
//YEEHAW
gridPieces.splice(runningIndex, 10);
lineFades.push(new lineBar(runningY));
return true;
}
} else {
runningY = gridPieces[i].pos.y;
count = 1;
runningIndex = i;
}
}
return false;
}
function worker(y, amount) {
this.amountActual = 0;
this.amountTotal = amount;
this.yVal = y;
this.work = function() {
if(this.amountActual < this.amountTotal) {
for(var j = 0; j < gridPieces.length; j++) {
if(gridPieces[j].pos.y < y) {
gridPieces[j].pos.y += 5;
}
}
this.amountActual += 5;
} else {
gridWorkers.shift();
}
}
}
//Sorts out the block positions for a given type and rotation
function orientPoints(pieceType, rotation) {
var results = [];
switch(pieceType) {
case 0:
switch(rotation) {
case 0:
results = [
[-2, 0],
[-1, 0],
[ 0, 0],
[ 1, 0]
];
break;
case 1:
results = [
[0, -1],
[0, 0],
[0, 1],
[0, 2]
];
break;
case 2:
results = [
[-2, 1],
[-1, 1],
[ 0, 1],
[ 1, 1]
];
break;
case 3:
results = [
[-1, -1],
[-1, 0],
[-1, 1],
[-1, 2]
];
break;
}
break;
case 1:
switch(rotation) {
case 0:
results = [
[-2, -1],
[-2, 0],
[-1, 0],
[ 0, 0]
];
break;
case 1:
results = [
[-1, -1],
[-1, 0],
[-1, 1],
[ 0, -1]
];
break;
case 2:
results = [
[-2, 0],
[-1, 0],
[ 0, 0],
[ 0, 1]
];
break;
case 3:
results = [
[-1, -1],
[-1, 0],
[-1, 1],
[-2, 1]
];
break;
}
break;
case 2:
switch(rotation) {
case 0:
results = [
[-2, 0],
[-1, 0],
[ 0, 0],
[ 0, -1]
];
break;
case 1:
results = [
[-1, -1],
[-1, 0],
[-1, 1],
[ 0, 1]
];
break;
case 2:
results = [
[-2, 0],
[-2, 1],
[-1, 0],
[ 0, 0]
];
break;
case 3:
results = [
[-2, -1],
[-1, -1],
[-1, 0],
[-1, 1]
];
break;
}
break;
case 3:
results = [
[-1, -1],
[ 0, -1],
[-1, 0],
[ 0, 0]
];
break;
case 4:
switch(rotation) {
case 0:
results = [
[-1, -1],
[-2, 0],
[-1, 0],
[ 0, -1]
];
break;
case 1:
results = [
[-1, -1],
[-1, 0],
[ 0, 0],
[ 0, 1]
];
break;
case 2:
results = [
[-1, 0],
[-2, 1],
[-1, 1],
[ 0, 0]
];
break;
case 3:
results = [
[-2, -1],
[-2, 0],
[-1, 0],
[-1, 1]
];
break;
}
break;
case 5:
switch(rotation) {
case 0:
results = [
[-2, 0],
[-1, 0],
[-1, -1],
[ 0, 0]
];
break;
case 1:
results = [
[-1, -1],
[-1, 0],
[-1, 1],
[ 0, 0]
];
break;
case 2:
results = [
[-2, 0],
[-1, 0],
[ 0, 0],
[-1, 1]
];
break;
case 3:
results = [
[-2, 0],
[-1, -1],
[-1, 0],
[-1, 1]
];
break;
}
break;
case 6:
switch(rotation) {
case 0:
results = [
[-2, -1],
[-1, -1],
[-1, 0],
[ 0, 0]
];
break;
case 1:
results = [
[-1, 0],
[-1, 1],
[ 0, 0],
[ 0, -1]
];
break;
case 2:
results = [
[-2, 0],
[-1, 0],
[-1, 1],
[ 0, 1]
];
break;
case 3:
results = [
[-2, 0],
[-2, 1],
[-1, 0],
[-1, -1]
];
break;
}
break;
}
return results;
}
This Pen doesn't use any external CSS resources.