Add different themes (no selection option yet) + huge performange improvements
This commit is contained in:
@@ -9,9 +9,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||
<defs>
|
||||
<filter id="f1" x="0" y="0">
|
||||
<feGaussianBlur in="SourceGraphic" stdDeviation="15"/>
|
||||
<feGaussianBlur in="SourceGraphic" stdDeviation="15"></feGaussianBlur>
|
||||
</filter>
|
||||
</defs>
|
||||
<!--<animate id="animate1" xlink:href="#f1" attributeName="stdDeviation" from="15" to="0" begin="" dur="1s" />-->
|
||||
</svg>
|
||||
<div id="language-selector">
|
||||
<div id="lang-en" class="lang active" data-lang="en">English</div>
|
||||
@@ -20,6 +21,7 @@
|
||||
<div id="background" class="blurred">
|
||||
<div id="time">00:00</div>
|
||||
<div id="score" data-prefix="Score: ">0</div>
|
||||
<canvas id="tetris-background" width="240" height="400"></canvas>
|
||||
<canvas id="tetris" width="240" height="400"></canvas>
|
||||
<div id="controls">
|
||||
<div id="control-text"></div>
|
||||
|
18
menu.js
18
menu.js
@@ -3,9 +3,14 @@ window.onresize = () => {
|
||||
};
|
||||
|
||||
function scaleWindow() {
|
||||
bgCanvas.height = window.innerHeight - 40;
|
||||
bgCanvas.width = bgCanvas.height / (5 / 3);
|
||||
bgContext.scale(bgCanvas.width / fieldSize.x, bgCanvas.height / fieldSize.y);
|
||||
|
||||
canvas.height = window.innerHeight - 40;
|
||||
canvas.width = canvas.height / (5 / 3);
|
||||
context.scale(canvas.width / fieldSize.x, canvas.height / fieldSize.y);
|
||||
|
||||
if(!firstRun && isPaused) {
|
||||
draw();
|
||||
}
|
||||
@@ -60,20 +65,20 @@ function fadeBlurIn() {
|
||||
const finalVal = 15;
|
||||
let currentVal = 0;
|
||||
|
||||
const id = setInterval(frame, 1);
|
||||
const id = setInterval(frame, 16);
|
||||
function frame() {
|
||||
if(currentVal >= finalVal) {
|
||||
clearInterval(id);
|
||||
} else {
|
||||
currentVal += 0.1;
|
||||
currentVal += 1.6;
|
||||
blurEl.setAttribute("stdDeviation", currentVal);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
blurEl.setAttribute("stdDeviation", finalVal);
|
||||
clearInterval(id);
|
||||
if (currentVal < finalVal) {
|
||||
blurEl.setAttribute("stdDeviation", finalVal);
|
||||
clearInterval(id);
|
||||
console.log("Performance Issues: system couldn't hold up");
|
||||
}
|
||||
}, 1000);
|
||||
@@ -84,12 +89,12 @@ function fadeBlurOut() {
|
||||
const finalVal = 0;
|
||||
let currentVal = 15;
|
||||
|
||||
const id = setInterval(frame, 1);
|
||||
const id = setInterval(frame, 16);
|
||||
function frame() {
|
||||
if(currentVal <= finalVal) {
|
||||
clearInterval(id);
|
||||
} else {
|
||||
currentVal -= 0.1;
|
||||
currentVal -= 1.6;
|
||||
blurEl.setAttribute("stdDeviation", currentVal);
|
||||
}
|
||||
}
|
||||
@@ -154,4 +159,5 @@ function initGame() {
|
||||
startGame();
|
||||
firstRun = false;
|
||||
switchLang(currentLang);
|
||||
|
||||
}
|
13
style.css
13
style.css
@@ -74,14 +74,14 @@ body {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
filter: none;
|
||||
filter: url(#f2);
|
||||
}
|
||||
|
||||
#background.blurred {
|
||||
filter: url(#f1);
|
||||
}
|
||||
|
||||
#tetris {
|
||||
#tetris, #tetris-background {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
@@ -91,6 +91,13 @@ body {
|
||||
-o-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
border: solid .2em #fff;
|
||||
z-index: 1;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#tetris-background {
|
||||
border: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
#score, #controls {
|
||||
@@ -155,7 +162,7 @@ body {
|
||||
}
|
||||
|
||||
@media (max-width: 1400px) {
|
||||
#tetris {
|
||||
#tetris, #tetris-background {
|
||||
height: 75%;
|
||||
}
|
||||
|
||||
|
191
tetris.js
191
tetris.js
@@ -1,14 +1,33 @@
|
||||
const canvas = document.getElementById('tetris');
|
||||
const context = canvas.getContext('2d');
|
||||
|
||||
const bgCanvas = document.getElementById('tetris-background');
|
||||
const bgContext = bgCanvas.getContext('2d');
|
||||
|
||||
const fieldSize = {x: 12, y: 20};
|
||||
const tileGap = .05;
|
||||
|
||||
/*
|
||||
default -> plain squares
|
||||
retro -> original look
|
||||
modern -> rounded corners
|
||||
snake -> all tiles are connected
|
||||
*/
|
||||
let theme = 'default';
|
||||
|
||||
let isPaused = true;
|
||||
|
||||
let startTime = 0;
|
||||
let prevUpdateScore = 0;
|
||||
|
||||
if (typeof console === "undefined") {
|
||||
console = {};
|
||||
}
|
||||
|
||||
let prerenders = [];
|
||||
const prerenderWidth = canvas.width / fieldSize.x * 4;
|
||||
const prerenderHeight = canvas.height / fieldSize.y * 4;
|
||||
|
||||
function arenaSweep() {
|
||||
let rowCount = 1;
|
||||
outer: for (let y = arena.length - 1; y > 0; --y) {
|
||||
@@ -26,10 +45,11 @@ function arenaSweep() {
|
||||
rowCount *= 2;
|
||||
}
|
||||
if (player.score - prevUpdateScore > 50) {
|
||||
dropInterval -= -20;
|
||||
dropInterval -= 20;
|
||||
dropInterval = dropInterval > 100 ? dropInterval : 100;
|
||||
prevUpdateScore = player.score;
|
||||
}
|
||||
drawArena();
|
||||
}
|
||||
|
||||
function clearScreen() {
|
||||
@@ -104,24 +124,122 @@ function createPiece(type) {
|
||||
}
|
||||
|
||||
function draw() {
|
||||
context.fillStyle = '#000';
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
// bgContext.fillStyle = '#000';
|
||||
// bgContext.fillRect(0, 0, canvas.width, canvas.height);
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
// clearScreen();
|
||||
|
||||
drawMatrix(arena, {x: 0, y: 0});
|
||||
// drawMatrix(arena, {x: 0, y: 0}, true);
|
||||
drawMatrix(player.matrix, player.pos);
|
||||
}
|
||||
|
||||
function drawMatrix(matrix, offset) {
|
||||
function drawArena() {
|
||||
bgContext.fillStyle = '#000';
|
||||
bgContext.fillRect(0, 0, canvas.width, canvas.height);
|
||||
drawMatrix(arena, {x: 0, y: 0}, true);
|
||||
}
|
||||
|
||||
function drawMatrix(matrix, offset, isBg) {
|
||||
matrix.forEach((row, y) => {
|
||||
row.forEach((value, x) => {
|
||||
if (value !== 0) {
|
||||
context.fillStyle = colors[value];
|
||||
context.fillRect(x + offset.x + tileGap / 2, y + offset.y + tileGap / 2, 1 - tileGap, 1 - tileGap);
|
||||
drawTile(x, y, offset, colors[value], matrix, isBg);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function drawRoundRect(ctx, x, y, w, h, r) {
|
||||
let r1 = r,
|
||||
r2 = r,
|
||||
r3 = r,
|
||||
r4 = r;
|
||||
if (typeof r === "number") {
|
||||
if (w < 2 * r) r = w / 2;
|
||||
if (h < 2 * r) r = h / 2;
|
||||
} else {
|
||||
r.forEach((corner, index) => {
|
||||
if (w < 2 * r[index]) r[index] = w / 2;
|
||||
if (h < 2 * r[index]) r[index] = h / 2;
|
||||
});
|
||||
r1 = r[0];
|
||||
r2 = r[1];
|
||||
r3 = r[2];
|
||||
r4 = r[3];
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + r1, y);
|
||||
if (r1 > 0) {
|
||||
ctx.arcTo(x + w, y, x + w, y + h, r1);
|
||||
} else {
|
||||
ctx.lineTo(x + w, y);
|
||||
}
|
||||
if (r2 > 0) {
|
||||
ctx.arcTo(x + w, y + h, x, y + h, r2);
|
||||
} else {
|
||||
ctx.lineTo(x + w, y + h);
|
||||
}
|
||||
if (r3 > 0) {
|
||||
ctx.arcTo(x, y + h, x, y, r3);
|
||||
} else {
|
||||
ctx.lineTo(x, y + h);
|
||||
}
|
||||
if (r4 > 0) {
|
||||
ctx.arcTo(x, y, x + w, y, r4);
|
||||
} else {
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
function drawTile(x, y, offset, color, matrix, isBg) {
|
||||
let ctx = context;
|
||||
if (isBg) {
|
||||
ctx = bgContext;
|
||||
}
|
||||
switch (theme) {
|
||||
case "default":
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(x + offset.x + tileGap / 2, y + offset.y + tileGap / 2, 1 - tileGap, 1 - tileGap);
|
||||
break;
|
||||
case "modern":
|
||||
ctx.fillStyle = color;
|
||||
drawRoundRect(ctx, x + offset.x + tileGap / 2, y + offset.y + tileGap / 2, 1 - tileGap, 1 - tileGap, .15);
|
||||
break;
|
||||
case "snakes":
|
||||
ctx.fillStyle = color;
|
||||
let r1 = .15, // top right
|
||||
r2 = .15, // bottom right
|
||||
r3 = .15, // bottom left
|
||||
r4 = .15; // top left
|
||||
// Is there a tile to the left?
|
||||
if (matrix[y][x - 1] > 0) {
|
||||
r3 = 0;
|
||||
r4 = 0;
|
||||
}
|
||||
// Is there a tile to the right?
|
||||
if (matrix[y][x + 1] > 0) {
|
||||
r1 = 0;
|
||||
r2 = 0;
|
||||
}
|
||||
// Is there a tile to the top?
|
||||
if (matrix[y - 1] !== undefined && matrix[y - 1][x] > 0) {
|
||||
r1 = 0;
|
||||
r4 = 0;
|
||||
}
|
||||
// Is there a tile to the bottom?
|
||||
if (matrix[y + 1] !== undefined && matrix[y + 1][x] > 0) {
|
||||
r2 = 0;
|
||||
r3 = 0;
|
||||
}
|
||||
drawRoundRect(ctx, x + offset.x, y + offset.y, 1, 1, [r1, r2, r3, r4]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function gameOver() {
|
||||
arena.forEach(row => row.fill(0));
|
||||
passedTime = 0;
|
||||
@@ -132,6 +250,33 @@ function gameOver() {
|
||||
updateScore();
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
if (document.cookie === "") {
|
||||
return;
|
||||
}
|
||||
const cookies = document.cookie.split(";");
|
||||
for (let i = 0; i < cookies.length; i++) {
|
||||
let biscuit = (cookies[i]).split("=");
|
||||
if (biscuit[0] === name)
|
||||
return {name: biscuit[0], value: biscuit[1]};
|
||||
}
|
||||
}
|
||||
|
||||
function getCookies() {
|
||||
if (document.cookie === "") {
|
||||
return;
|
||||
}
|
||||
const cookies = document.cookie.split(";");
|
||||
const cookieList = [];
|
||||
for (let i = 0; i < cookies.length; i++) {
|
||||
let biscuit = (cookies[i]).split("=");
|
||||
cookieList.push({
|
||||
name: biscuit[0],
|
||||
value: biscuit[1]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function merge(arena, player) {
|
||||
player.matrix.forEach((row, y) => {
|
||||
row.forEach((value, x) => {
|
||||
@@ -140,6 +285,7 @@ function merge(arena, player) {
|
||||
}
|
||||
});
|
||||
});
|
||||
drawArena();
|
||||
}
|
||||
|
||||
function playerDrop() {
|
||||
@@ -189,6 +335,29 @@ function playerRotate(dir) {
|
||||
}
|
||||
}
|
||||
|
||||
function prerenderPiece(type, preContext) {
|
||||
createPiece(type).forEach((row, y) => {
|
||||
row.forEach((value, x) => {
|
||||
if (value !== 0) {
|
||||
preContext.fillStyle = colors[value];
|
||||
preContext.fillRect(x + tileGap / 2, y + tileGap / 2, 1 - tileGap, 1 - tileGap);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function prerenderPieces() {
|
||||
const preCanvas = document.createElement('canvas');
|
||||
preCanvas.width = prerenderWidth;
|
||||
preCanvas.height = prerenderHeight;
|
||||
const preContext = preCanvas.getContext("2d");
|
||||
prerenderPiece("I", preContext);
|
||||
prerenders.push({
|
||||
canvas: preCanvas,
|
||||
context: preContext
|
||||
});
|
||||
}
|
||||
|
||||
function rotate(matrix, dir) {
|
||||
for (let y = 0; y < matrix.length; ++y) {
|
||||
for (let x = 0; x < y; ++x) {
|
||||
@@ -209,6 +378,12 @@ function rotate(matrix, dir) {
|
||||
}
|
||||
}
|
||||
|
||||
function saveHighscore() {
|
||||
if (getCookie("highscore").value < player.score) {
|
||||
document.cookie = "highscore=" + player.score + "; max-age=" + 60 * 60 * 24 * 365 * 1000 + "; path=/;";
|
||||
}
|
||||
}
|
||||
|
||||
let dropCounter = 0;
|
||||
let dropInterval = 1000;
|
||||
|
||||
@@ -241,6 +416,7 @@ function updateScore() {
|
||||
if(lastScore !== player.score) {
|
||||
scoreUpdateAni();
|
||||
lastScore = player.score;
|
||||
saveHighscore();
|
||||
}
|
||||
document.getElementById('score').innerText = player.score.toString();
|
||||
}
|
||||
@@ -309,6 +485,7 @@ document.addEventListener('keydown', event => {
|
||||
|
||||
function startGame() {
|
||||
arena = createMatrix(fieldSize.x, fieldSize.y);
|
||||
drawArena();
|
||||
playerReset();
|
||||
update();
|
||||
updateScore();
|
||||
|
Reference in New Issue
Block a user