Complete restructuring of code: adjusting it to OOP + language and layout improvements
This commit is contained in:
40
index.html
40
index.html
@@ -17,23 +17,44 @@
|
|||||||
<div id="menu">
|
<div id="menu">
|
||||||
<div id="menu-content">
|
<div id="menu-content">
|
||||||
<div id="language-selector">
|
<div id="language-selector">
|
||||||
|
<h3 data-string="titleLanguage">Sprache</h3>
|
||||||
<div id="lang-en" class="lang active" data-lang="en">English</div>
|
<div id="lang-en" class="lang active" data-lang="en">English</div>
|
||||||
<div id="lang-de" class="lang" data-lang="de">Deutsch</div>
|
<div id="lang-de" class="lang" data-lang="de">Deutsch</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="theme-selector">
|
<div id="theme-selector">
|
||||||
|
<h3 data-string="titleAppearance">Aussehen</h3>
|
||||||
<div class="radio">
|
<div class="radio">
|
||||||
<input id="theme-default" name="theme" data-theme="default" type="radio" checked>
|
<input id="theme-default" name="theme" data-theme="default" type="radio" checked>
|
||||||
<label for="theme-default" class="radio-label">Default</label>
|
<label for="theme-default" class="radio-label" data-string="themeDefault">Default</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="radio">
|
<div class="radio">
|
||||||
<input id="theme-modern" name="theme" data-theme="modern" type="radio">
|
<input id="theme-modern" name="theme" data-theme="modern" type="radio">
|
||||||
<label for="theme-modern" class="radio-label">Modern</label>
|
<label for="theme-modern" class="radio-label" data-string="themeModern">Modern</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="radio">
|
<div class="radio">
|
||||||
<input id="theme-snakes" name="theme" data-theme="snakes" type="radio">
|
<input id="theme-snakes" name="theme" data-theme="snakes" type="radio">
|
||||||
<label for="theme-snakes" class="radio-label">Snakes</label>
|
<label for="theme-snakes" class="radio-label" data-string="themeSnakes">Snakes</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="help-controls">
|
||||||
|
<h3 data-string="titleControls">Steuerung</h3>
|
||||||
|
<dl>
|
||||||
|
<dt><code>A</code> / <code>←</code></dt>
|
||||||
|
<dd data-string="controlsLeft">Nach links bewegen</dd>
|
||||||
|
<dt><code>D</code> / <code>→</code></dt>
|
||||||
|
<dd data-string="controlsRight">Nach rechts bewegen</dd>
|
||||||
|
<dt><code>Q</code></dt>
|
||||||
|
<dd data-string="controlsTLeft">Nach links drehen</dd>
|
||||||
|
<dt><code>E</code></dt>
|
||||||
|
<dd data-string="controlsTRight">Nach rechts drehen</dd>
|
||||||
|
<dt><code>S</code> / <code>↓</code></dt>
|
||||||
|
<dd data-string="controlsDown">Fallen beschleunigen</dd>
|
||||||
|
<dt><code>W</code> / <code>↑</code></dt>
|
||||||
|
<dd data-string="controlsHold">Halten</dd>
|
||||||
|
<dt><code>␛</code> / <code>␣</code></dt>
|
||||||
|
<dd data-string="controlsPause">Pausieren</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="menu-opener">
|
<div id="menu-opener">
|
||||||
@@ -43,8 +64,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="background" class="blurred">
|
<div id="background" class="blurred">
|
||||||
<div id="game-stats">
|
<div id="game-stats">
|
||||||
<div id="time">00:00</div>
|
<div id="time" data-string="counterTime" data-string-type="prefix">00:00</div>
|
||||||
<div id="score" data-prefix="Score: ">0</div>
|
<div id="score" data-string="counterScore" data-string-type="prefix">0</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="canvas-container">
|
<div id="canvas-container">
|
||||||
<canvas id="tetris-hold" width="100" height="100"></canvas>
|
<canvas id="tetris-hold" width="100" height="100"></canvas>
|
||||||
@@ -52,14 +73,11 @@
|
|||||||
<canvas id="tetris" width="240" height="400"></canvas>
|
<canvas id="tetris" width="240" height="400"></canvas>
|
||||||
<canvas id="tetris-upcoming" width="100" height="300"></canvas>
|
<canvas id="tetris-upcoming" width="100" height="300"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<div id="controls">
|
|
||||||
<div id="control-text"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<h1 id="game-title">Tetris.js</h1>
|
<h1 id="game-title" data-string="titlePaused" data-string-first-run="titleGame">Tetris.js</h1>
|
||||||
<button id="game-play">Play!</button>
|
<button id="game-play" data-string="btnResume" data-string-first-run="btnPlay">Play!</button>
|
||||||
<button id="game-reset">Reset</button>
|
<button id="game-reset" data-string="btnReset">Reset</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<span id="version-author">v0.0.2a - by KingOfDog</span>
|
<span id="version-author">v0.0.2a - by KingOfDog</span>
|
||||||
|
101
js/language.js
101
js/language.js
@@ -1,38 +1,46 @@
|
|||||||
const en = {
|
const en = {
|
||||||
controls: "Controls:" +
|
btnPlay: "Play!",
|
||||||
"<br>" +
|
btnReset: "Reset",
|
||||||
"Left+Right/A+D -> Move left/right" +
|
btnResume: "Resume",
|
||||||
"<br>" +
|
controlsDown: "Accelerate falling",
|
||||||
"Q/E -> Rotate the tile" +
|
controlsHold: "Hold",
|
||||||
"<br>" +
|
controlsLeft: "Move left",
|
||||||
"Down/S -> Drop the tile faster" +
|
controlsPause: "Pause",
|
||||||
"<br>" +
|
controlsRight: "Move right",
|
||||||
"Space/Esc -> Pause the game",
|
controlsTLeft: "Rotate to the left",
|
||||||
play: "Play!",
|
controlsTRight: "Rotate to the right",
|
||||||
time: "Time: ",
|
counterScore: "Score: ",
|
||||||
score: "Score: ",
|
counterTime: "Time: ",
|
||||||
paused: "Paused",
|
themeDefault: "Default",
|
||||||
resume: "Resume",
|
themeModern: "Modern",
|
||||||
title: "Tetris.js",
|
themeSnakes: "Snakes",
|
||||||
reset: "Reset"
|
titleAppearance: "Appearance",
|
||||||
|
titleControls: "Controls",
|
||||||
|
titleGame: "Tetris.js",
|
||||||
|
titleLanguage: "Language",
|
||||||
|
titlePaused: "Paused"
|
||||||
};
|
};
|
||||||
|
|
||||||
const de = {
|
const de = {
|
||||||
controls: "Steuerung:" +
|
btnPlay: "Spielen!",
|
||||||
"<br>" +
|
btnReset: "Zurücksetzen",
|
||||||
"Links+Rechts/A+D -> Objekt nach links/rechts bewegen" +
|
btnResume: "Weiterspielen",
|
||||||
"<br>" +
|
controlsDown: "Fallen beschleunigen",
|
||||||
"Q/E -> Objekt drehen" +
|
controlsHold: "Halten",
|
||||||
"<br>" +
|
controlsLeft: "Nach links bewegen",
|
||||||
"Unten/S -> Objekt schneller fallen lassen" +
|
controlsPause: "Pausieren",
|
||||||
"<br>" +
|
controlsRight: "Nach rechts bewegen",
|
||||||
"Leertaste/Esc -> Pausiere das Spiel",
|
controlsTLeft: "Nach links drehen",
|
||||||
play: "Spielen!",
|
controlsTRight: "Nach rechts drehen",
|
||||||
time: "Zeit: ",
|
counterScore: "Punkte: ",
|
||||||
score: "Punkte: ",
|
counterTime: "Zeit: ",
|
||||||
paused: "Pausiert",
|
themeDefault: "Standard",
|
||||||
resume: "Weiterspielen",
|
themeModern: "Modern",
|
||||||
reset: "Zurücksetzen"
|
themeSnakes: "Schlangen",
|
||||||
|
titleAppearance: "Aussehen",
|
||||||
|
titleControls: "Steuerung",
|
||||||
|
titleLanguage: "Sprache",
|
||||||
|
titlePaused: "Pausiert"
|
||||||
};
|
};
|
||||||
|
|
||||||
let currentLang = ["de", "en"].includes(navigator.language || navigator.userLanguage) ? navigator.language || navigator.userLanguage : "en";
|
let currentLang = ["de", "en"].includes(navigator.language || navigator.userLanguage) ? navigator.language || navigator.userLanguage : "en";
|
||||||
@@ -59,17 +67,28 @@ class Language {
|
|||||||
function switchLang(lang) {
|
function switchLang(lang) {
|
||||||
currentLang = lang;
|
currentLang = lang;
|
||||||
const l = new Language(currentLang);
|
const l = new Language(currentLang);
|
||||||
document.getElementById("score").setAttribute("data-prefix", l.getStr("score"));
|
|
||||||
document.getElementById("time").setAttribute("data-prefix", l.getStr("time"));
|
const elements = document.querySelectorAll('[data-string]');
|
||||||
document.getElementById("control-text").innerHTML = l.getStr("controls");
|
for (let i = 0; i < elements.length; i++) {
|
||||||
if(firstRun) {
|
let el = elements[i];
|
||||||
document.getElementById("game-title").innerHTML = l.getStr("title");
|
let str = l.getStr(el.getAttribute("data-string"));
|
||||||
document.getElementById("game-play").innerHTML = l.getStr("play");
|
if (el.getAttribute("data-string-first-run") != null && firstRun) {
|
||||||
} else {
|
str = l.getStr(el.getAttribute("data-string-first-run"));
|
||||||
document.getElementById("game-title").innerHTML = l.getStr("paused");
|
}
|
||||||
document.getElementById("game-play").innerHTML = l.getStr("resume");
|
if (el.getAttribute("data-string-type")) {
|
||||||
document.getElementById("game-reset").innerHTML = l.getStr("reset");
|
switch (el.getAttribute("data-string-type")) {
|
||||||
|
case "prefix":
|
||||||
|
el.setAttribute("data-prefix", str);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
el.innerHTML = str;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
el.innerHTML = str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switchActiveSelector(currentLang)
|
switchActiveSelector(currentLang)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
41
js/menu.js
41
js/menu.js
@@ -17,21 +17,26 @@ function scaleWindow() {
|
|||||||
canvasContainer.height = height;
|
canvasContainer.height = height;
|
||||||
canvasContainer.width = width + 200;
|
canvasContainer.width = width + 200;
|
||||||
|
|
||||||
canvasBg.height = height;
|
game.g.canvasBg.height = height;
|
||||||
canvasBg.width = width;
|
game.g.canvasBg.width = width;
|
||||||
contextBg.scale(width / fieldSize.x, height / fieldSize.y);
|
game.g.contextBg.scale(width / game.g.fieldSize.x, height / game.g.fieldSize.y);
|
||||||
|
|
||||||
canvas.height = height;
|
game.g.canvas.height = height;
|
||||||
canvas.width = width;
|
game.g.canvas.width = width;
|
||||||
context.scale(width / fieldSize.x, height / fieldSize.y);
|
game.g.context.scale(width / game.g.fieldSize.x, height / game.g.fieldSize.y);
|
||||||
|
|
||||||
canvasHold.height = height / fieldSize.y * 4;
|
game.g.canvasHold.height = height / game.g.fieldSize.y * 4;
|
||||||
canvasHold.width = canvasHold.height;
|
game.g.canvasHold.width = game.g.canvasHold.height;
|
||||||
canvasHold.style.transform = "translateX(-" + ((width / 2) + canvasHold.height) + "px) translate(-.4em, -.2em)";
|
game.g.canvasHold.style.transform = "translateX(-" + ((width / 2) + game.g.canvasHold.width) + "px) translate(-.4em, -.2em)";
|
||||||
contextHold.scale(canvasHold.width / 6, canvasHold.width / 6);
|
game.g.contextHold.scale(game.g.canvasHold.width / 6, game.g.canvasHold.width / 6);
|
||||||
|
|
||||||
if(!firstRun && isPaused) {
|
game.g.canvasUpcoming.width = height / game.g.fieldSize.y * 4;
|
||||||
draw();
|
game.g.canvasUpcoming.height = game.g.canvasUpcoming.width * 3;
|
||||||
|
game.g.canvasUpcoming.style.transform = "translateX(" + ((width / 2) + game.g.canvasHold.width) + "px) translate(.4em, -.2em)";
|
||||||
|
game.g.contextUpcoming.scale(game.g.canvasUpcoming.width / 6, game.g.canvasUpcoming.width / 6);
|
||||||
|
|
||||||
|
if (!firstRun && game.g.isPaused) {
|
||||||
|
game.draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +73,7 @@ document.getElementById("game-play").addEventListener("click", () => {
|
|||||||
|
|
||||||
document.getElementById("game-reset").addEventListener("click", () => {
|
document.getElementById("game-reset").addEventListener("click", () => {
|
||||||
firstRun = true;
|
firstRun = true;
|
||||||
clearScreen();
|
game.clearScreen();
|
||||||
hideMenu();
|
hideMenu();
|
||||||
switchLang(currentLang);
|
switchLang(currentLang);
|
||||||
showMenu();
|
showMenu();
|
||||||
@@ -76,7 +81,7 @@ document.getElementById("game-reset").addEventListener("click", () => {
|
|||||||
|
|
||||||
document.getElementsByName("theme").forEach((el) => {
|
document.getElementsByName("theme").forEach((el) => {
|
||||||
el.addEventListener("change", (e) => {
|
el.addEventListener("change", (e) => {
|
||||||
theme = e.target.getAttribute("data-theme");
|
game.theme = e.target.getAttribute("data-theme");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -190,7 +195,7 @@ function scoreUpdateAni() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showMenu() {
|
function showMenu() {
|
||||||
isPaused = true;
|
game.g.isPaused = true;
|
||||||
escState = 1;
|
escState = 1;
|
||||||
document.getElementById("game-title").style.display = "block";
|
document.getElementById("game-title").style.display = "block";
|
||||||
document.getElementById("game-play").style.display = "block";
|
document.getElementById("game-play").style.display = "block";
|
||||||
@@ -205,7 +210,7 @@ function showMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hideMenu() {
|
function hideMenu() {
|
||||||
isPaused = false;
|
game.g.isPaused = false;
|
||||||
escState = 0;
|
escState = 0;
|
||||||
document.getElementById("game-title").style.opacity = "0";
|
document.getElementById("game-title").style.opacity = "0";
|
||||||
document.getElementById("game-play").style.opacity = "0";
|
document.getElementById("game-play").style.opacity = "0";
|
||||||
@@ -215,10 +220,10 @@ function hideMenu() {
|
|||||||
document.getElementById("game-play").style.display = "none";
|
document.getElementById("game-play").style.display = "none";
|
||||||
document.getElementById("game-reset").style.display = "none";
|
document.getElementById("game-reset").style.display = "none";
|
||||||
}, 500);
|
}, 500);
|
||||||
lastTimeUpdate = Date.now();
|
game.g.lastTimeUpdate = Date.now();
|
||||||
fadeBlurOut();
|
fadeBlurOut();
|
||||||
if(!firstRun) {
|
if(!firstRun) {
|
||||||
update(lastTime);
|
game.update(lastTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
701
js/tetris.js
701
js/tetris.js
@@ -1,16 +1,375 @@
|
|||||||
let arena = createMatrix(fieldSize.x, fieldSize.y);
|
class GameInfo {
|
||||||
|
constructor(game) {
|
||||||
|
this.fieldSize = {x: 12, y: 20};
|
||||||
|
this.arena = new Arena(this, game);
|
||||||
|
|
||||||
const canvas = document.getElementById('tetris');
|
this.player = new Player(this, game);
|
||||||
const context = canvas.getContext('2d');
|
|
||||||
|
|
||||||
const canvasBg = document.getElementById('tetris-background');
|
this.canvas = document.getElementById('tetris');
|
||||||
const contextBg = canvasBg.getContext('2d');
|
this.context = this.canvas.getContext('2d');
|
||||||
|
|
||||||
const canvasHold = document.getElementById('tetris-hold');
|
this.canvasBg = document.getElementById('tetris-background');
|
||||||
const contextHold = canvasHold.getContext('2d');
|
this.contextBg = this.canvasBg.getContext('2d');
|
||||||
|
|
||||||
const canvasUpcoming = document.getElementById('tetris-upcoming');
|
this.canvasHold = document.getElementById('tetris-hold');
|
||||||
const contextUpcoming = canvasUpcoming.getContext('2d');
|
this.contextHold = this.canvasHold.getContext('2d');
|
||||||
|
|
||||||
|
this.canvasUpcoming = document.getElementById('tetris-upcoming');
|
||||||
|
this.contextUpcoming = this.canvasUpcoming.getContext('2d');
|
||||||
|
|
||||||
|
this.isPaused = true;
|
||||||
|
|
||||||
|
this.dropCounter = 0;
|
||||||
|
this.dropInterval = 1000;
|
||||||
|
|
||||||
|
this.keys = {
|
||||||
|
down: {
|
||||||
|
keys: [40, 83],
|
||||||
|
action: () => this.player.drop()
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
keys: [37, 65],
|
||||||
|
action: () => this.player.move(-1)
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
keys: [39, 68],
|
||||||
|
action: () => this.player.move(1)
|
||||||
|
},
|
||||||
|
rotateLeft: {
|
||||||
|
keys: [81],
|
||||||
|
action: () => this.player.rotate(-1)
|
||||||
|
},
|
||||||
|
rotateRight: {
|
||||||
|
keys: [69],
|
||||||
|
action: () => this.player.rotate(1)
|
||||||
|
},
|
||||||
|
holdTile: {
|
||||||
|
keys: [38, 87],
|
||||||
|
action: () => this.player.hold()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.prevUpdateScore = 0;
|
||||||
|
|
||||||
|
this.lastScore = 0;
|
||||||
|
this.lastTime = 0;
|
||||||
|
this.lastTimeUpdate = Date.now();
|
||||||
|
|
||||||
|
this.startTime = 0;
|
||||||
|
|
||||||
|
this.upcomingTiles = [];
|
||||||
|
|
||||||
|
/*
|
||||||
|
default -> plain squares
|
||||||
|
retro -> original look
|
||||||
|
modern -> rounded corners
|
||||||
|
snake -> all tiles are connected
|
||||||
|
*/
|
||||||
|
this.theme = 'default';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Game {
|
||||||
|
constructor() {
|
||||||
|
this.g = new GameInfo(this);
|
||||||
|
this.p = this.g.player;
|
||||||
|
|
||||||
|
this.registerListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {
|
||||||
|
this.g.context.clearRect(0, 0, this.g.canvas.width, this.g.canvas.height);
|
||||||
|
this.drawMatrix(this.p.matrix, this.p.pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawArena() {
|
||||||
|
this.g.contextBg.fillStyle = '#000';
|
||||||
|
this.g.contextBg.fillRect(0, 0, this.g.canvas.width, this.g.canvas.height);
|
||||||
|
this.drawMatrix(this.g.arena.field, {x: 0, y: 0}, this.g.contextBg);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawHolding() {
|
||||||
|
this.g.contextHold.clearRect(0, 0, this.g.canvasHold.width, this.g.canvasHold.height);
|
||||||
|
const offset = centerOffset(this.p.holdingTile);
|
||||||
|
const x = 3 - (this.p.holdingTile[0].length / 2) + offset.x;
|
||||||
|
const y = 3 - (this.p.holdingTile.length / 2) + offset.y;
|
||||||
|
this.drawMatrix(this.p.holdingTile, {x: x, y: y}, this.g.contextHold);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawMatrix(matrix, offset, useContext = this.g.context) {
|
||||||
|
matrix.forEach((row, y) => {
|
||||||
|
row.forEach((value, x) => {
|
||||||
|
if (value !== 0) {
|
||||||
|
this.drawTile(x, y, offset, colors[value], matrix, useContext);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
drawTile(x, y, offset, color, matrix, useContext = this.g.context) {
|
||||||
|
const ctx = useContext;
|
||||||
|
switch (this.g.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:
|
||||||
|
this.g.theme = "default";
|
||||||
|
this.drawTile(x, y, offset, color, matrix, ctx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawUpcoming() {
|
||||||
|
this.g.contextUpcoming.clearRect(0, 0, this.g.canvasUpcoming.width, this.g.canvasUpcoming.height);
|
||||||
|
let offsetY = 0;
|
||||||
|
let offset;
|
||||||
|
this.g.upcomingTiles.forEach((tile) => {
|
||||||
|
offset = centerOffset(tile);
|
||||||
|
const x = 3 - (tile[0].length / 2) + offset.x;
|
||||||
|
const y = offsetY + 3 - (tile.length / 2) + offset.y;
|
||||||
|
this.drawMatrix(tile, {x: x, y: y}, this.g.contextUpcoming);
|
||||||
|
offsetY += 6;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
gameOver() {
|
||||||
|
this.g.arena.field.forEach(row => row.fill(0));
|
||||||
|
timePassed = 0;
|
||||||
|
this.g.lastTimeUpdate = Date.now();
|
||||||
|
this.updateTime();
|
||||||
|
this.p.score = 0;
|
||||||
|
this.g.dropInterval = 1000;
|
||||||
|
this.updateScore();
|
||||||
|
}
|
||||||
|
|
||||||
|
merge(arena, player) {
|
||||||
|
player.matrix.forEach((row, y) => {
|
||||||
|
row.forEach((value, x) => {
|
||||||
|
if (value !== 0) {
|
||||||
|
arena.field[y + player.pos.y][x + player.pos.x] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.drawArena();
|
||||||
|
}
|
||||||
|
|
||||||
|
registerListeners() {
|
||||||
|
// Keyboard controls
|
||||||
|
document.addEventListener('keydown', event => {
|
||||||
|
Object.keys(this.g.keys).map((objKey) => {
|
||||||
|
const keyBind = this.g.keys[objKey];
|
||||||
|
if (keyBind.keys.includes(event.keyCode)) {
|
||||||
|
keyBind.action();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
saveHighscore() {
|
||||||
|
if (getCookie("highscore").value < this.p.score) {
|
||||||
|
document.cookie = "highscore=" + this.p.score + "; max-age=" + 60 * 60 * 24 * 365 * 1000 + "; path=/;";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.drawArena();
|
||||||
|
this.p.addTile();
|
||||||
|
this.p.addTile();
|
||||||
|
this.p.addTile();
|
||||||
|
this.p.reset();
|
||||||
|
this.g.startTime = Date.now();
|
||||||
|
this.update();
|
||||||
|
this.updateScore();
|
||||||
|
}
|
||||||
|
|
||||||
|
update(time = 0) {
|
||||||
|
if (!this.g.isPaused) {
|
||||||
|
const deltaTime = time - this.g.lastTime;
|
||||||
|
this.g.lastTime = time;
|
||||||
|
|
||||||
|
this.g.dropCounter += deltaTime;
|
||||||
|
if (this.g.dropCounter > this.g.dropInterval) {
|
||||||
|
this.p.drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateTime();
|
||||||
|
|
||||||
|
this.draw();
|
||||||
|
requestAnimationFrame(this.update.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateScore() {
|
||||||
|
if (this.g.lastScore !== this.p.score) {
|
||||||
|
scoreUpdateAni();
|
||||||
|
this.g.lastScore = this.p.score;
|
||||||
|
this.saveHighscore();
|
||||||
|
}
|
||||||
|
document.getElementById('score').innerText = this.p.score.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTime() {
|
||||||
|
timePassed += Date.now() - this.g.lastTimeUpdate;
|
||||||
|
timeElement.innerHTML = formatMillis(timePassed);
|
||||||
|
this.g.lastTimeUpdate = Date.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Arena {
|
||||||
|
constructor(gameInfo, game) {
|
||||||
|
this.g = gameInfo;
|
||||||
|
this.game = game;
|
||||||
|
this.field = createMatrix(this.g.fieldSize.x, this.g.fieldSize.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearScreen() {
|
||||||
|
this.g.context.clearRect(0, 0, this.g.canvas.width, this.g.canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
sweep() {
|
||||||
|
let rowCount = 1;
|
||||||
|
outer: for (let y = this.field.length - 1; y > 0; --y) {
|
||||||
|
for (let x = 0; x < this.field[y].length; ++x) {
|
||||||
|
if (this.field[y][x] === 0) {
|
||||||
|
continue outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = this.field.splice(y, 1)[0].fill(0);
|
||||||
|
this.field.unshift(row);
|
||||||
|
++y;
|
||||||
|
|
||||||
|
this.p.score += rowCount * 10;
|
||||||
|
rowCount *= 2;
|
||||||
|
}
|
||||||
|
if (this.p.score - this.g.prevUpdateScore > 50) {
|
||||||
|
this.g.dropInterval -= 20;
|
||||||
|
this.g.dropInterval = this.g.dropInterval > 100 ? this.g.dropInterval : 100;
|
||||||
|
this.g.prevUpdateScore = this.p.score;
|
||||||
|
}
|
||||||
|
this.game.drawArena();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Player {
|
||||||
|
constructor(gameInfo, game) {
|
||||||
|
this.g = gameInfo;
|
||||||
|
this.game = game;
|
||||||
|
this.a = this.g.arena;
|
||||||
|
this.pos = {x: 0, y: 0};
|
||||||
|
this.matrix = null;
|
||||||
|
this.score = 0;
|
||||||
|
|
||||||
|
this.isHolding = false;
|
||||||
|
this.holdingTile = null;
|
||||||
|
|
||||||
|
this.a.p = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
addTile() {
|
||||||
|
this.g.upcomingTiles.push(createPiece(pieces[pieces.length * Math.random() | 0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
drop() {
|
||||||
|
this.pos.y++;
|
||||||
|
if (collide(this.a.field, this)) {
|
||||||
|
this.pos.y--;
|
||||||
|
this.game.merge(this.a, this);
|
||||||
|
this.reset();
|
||||||
|
this.a.sweep();
|
||||||
|
this.game.updateScore();
|
||||||
|
}
|
||||||
|
this.g.dropCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hold() {
|
||||||
|
if (this.isHolding)
|
||||||
|
return;
|
||||||
|
if (this.holdingTile === null) {
|
||||||
|
this.holdingTile = this.matrix;
|
||||||
|
this.reset(true);
|
||||||
|
} else {
|
||||||
|
this.holdingTile = [this.matrix, this.matrix = this.holdingTile][0];
|
||||||
|
this.reset(true, false);
|
||||||
|
}
|
||||||
|
this.game.drawHolding();
|
||||||
|
}
|
||||||
|
|
||||||
|
move(dir) {
|
||||||
|
this.pos.x += dir;
|
||||||
|
if (collide(this.a.field, this)) {
|
||||||
|
this.pos.x -= dir;
|
||||||
|
}
|
||||||
|
this.g.dropCounter *= .75;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(resetHold = false, newTile = true) {
|
||||||
|
this.isHolding = resetHold;
|
||||||
|
if (newTile) {
|
||||||
|
this.matrix = this.g.upcomingTiles[0];
|
||||||
|
this.g.upcomingTiles.splice(0, 1);
|
||||||
|
this.addTile();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pos.y = 0;
|
||||||
|
this.pos.x = (this.a.field[0].length / 2 | 0) - (this.matrix[0].length / 2 | 0);
|
||||||
|
|
||||||
|
this.game.drawUpcoming();
|
||||||
|
|
||||||
|
if (collide(this.a.field, this)) {
|
||||||
|
this.game.gameOver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rotate(dir) {
|
||||||
|
rotate(this.matrix, dir);
|
||||||
|
|
||||||
|
const pos = this.pos.x;
|
||||||
|
let offset = 1;
|
||||||
|
while (collide(this.a.field, this)) {
|
||||||
|
this.pos.x += offset;
|
||||||
|
offset = -(offset + (offset > 0 ? 1 : -1));
|
||||||
|
if (offset > this.matrix[0].length) {
|
||||||
|
rotate(this.matrix, -dir);
|
||||||
|
this.pos.x = pos;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const colors = [
|
const colors = [
|
||||||
null,
|
null,
|
||||||
@@ -23,118 +382,17 @@ const colors = [
|
|||||||
'#3877FF',
|
'#3877FF',
|
||||||
];
|
];
|
||||||
|
|
||||||
let dropCounter = 0;
|
|
||||||
let dropInterval = 1000;
|
|
||||||
|
|
||||||
const fieldSize = {x: 12, y: 20};
|
|
||||||
|
|
||||||
let holdingTile = null;
|
|
||||||
|
|
||||||
let isPaused = true;
|
|
||||||
let isHolding = false;
|
|
||||||
|
|
||||||
const keys = {
|
|
||||||
down: {
|
|
||||||
keys: [40, 83],
|
|
||||||
action: () => playerDrop()
|
|
||||||
},
|
|
||||||
left: {
|
|
||||||
keys: [37, 65],
|
|
||||||
action: () => playerMove(-1)
|
|
||||||
},
|
|
||||||
right: {
|
|
||||||
keys: [39, 68],
|
|
||||||
action: () => playerMove(1)
|
|
||||||
},
|
|
||||||
rotateLeft: {
|
|
||||||
keys: [81],
|
|
||||||
action: () => playerRotate(-1)
|
|
||||||
},
|
|
||||||
rotateRight: {
|
|
||||||
keys: [69],
|
|
||||||
action: () => playerRotate(1)
|
|
||||||
},
|
|
||||||
holdTile: {
|
|
||||||
keys: [38, 87],
|
|
||||||
action: () => playerHold()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let lastScore = 0;
|
|
||||||
let lastTime = 0;
|
|
||||||
let lastTimeUpdate = Date.now();
|
|
||||||
|
|
||||||
const pieces = 'IJLOSTZ';
|
const pieces = 'IJLOSTZ';
|
||||||
|
|
||||||
const player = {
|
|
||||||
pos: {x: 0, y: 0},
|
|
||||||
matrix: null,
|
|
||||||
score: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
let prevUpdateScore = 0;
|
|
||||||
|
|
||||||
let startTime = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
default -> plain squares
|
|
||||||
retro -> original look
|
|
||||||
modern -> rounded corners
|
|
||||||
snake -> all tiles are connected
|
|
||||||
*/
|
|
||||||
let theme = 'default';
|
|
||||||
|
|
||||||
const tileGap = .05;
|
const tileGap = .05;
|
||||||
|
|
||||||
const timeElement = document.getElementById("time");
|
const timeElement = document.getElementById("time");
|
||||||
let timePassed = 0;
|
let timePassed = 0;
|
||||||
|
|
||||||
|
|
||||||
let upcomingTiles = [];
|
|
||||||
|
|
||||||
|
|
||||||
if (typeof console === "undefined") {
|
if (typeof console === "undefined") {
|
||||||
console = {};
|
console = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keyboard controls
|
|
||||||
document.addEventListener('keydown', event => {
|
|
||||||
Object.keys(keys).map((objKey, index) => {
|
|
||||||
const keyBind = keys[objKey];
|
|
||||||
if (keyBind.keys.includes(event.keyCode)) {
|
|
||||||
keyBind.action();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function addTile() {
|
|
||||||
upcomingTiles.push(createPiece(pieces[pieces.length * Math.random() | 0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
function arenaSweep() {
|
|
||||||
let rowCount = 1;
|
|
||||||
outer: for (let y = arena.length - 1; y > 0; --y) {
|
|
||||||
for (let x = 0; x < arena[y].length; ++x) {
|
|
||||||
if (arena[y][x] === 0) {
|
|
||||||
continue outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const row = arena.splice(y, 1)[0].fill(0);
|
|
||||||
arena.unshift(row);
|
|
||||||
++y;
|
|
||||||
|
|
||||||
player.score += rowCount * 10;
|
|
||||||
rowCount *= 2;
|
|
||||||
}
|
|
||||||
if (player.score - prevUpdateScore > 50) {
|
|
||||||
dropInterval -= 20;
|
|
||||||
dropInterval = dropInterval > 100 ? dropInterval : 100;
|
|
||||||
prevUpdateScore = player.score;
|
|
||||||
}
|
|
||||||
drawArena();
|
|
||||||
}
|
|
||||||
|
|
||||||
function centerOffset(matrix) {
|
function centerOffset(matrix) {
|
||||||
let offsetX = 0;
|
let offsetX = 0;
|
||||||
let offsetY = 0;
|
let offsetY = 0;
|
||||||
@@ -168,10 +426,6 @@ function centerOffset(matrix) {
|
|||||||
return {x: offsetX, y: offsetY};
|
return {x: offsetX, y: offsetY};
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearScreen() {
|
|
||||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
function collide(arena, player) {
|
function collide(arena, player) {
|
||||||
const [m, o] = [player.matrix, player.pos];
|
const [m, o] = [player.matrix, player.pos];
|
||||||
for (let y = 0; y < m.length; ++y) {
|
for (let y = 0; y < m.length; ++y) {
|
||||||
@@ -239,35 +493,6 @@ function createPiece(type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw() {
|
|
||||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
drawMatrix(player.matrix, player.pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawArena() {
|
|
||||||
contextBg.fillStyle = '#000';
|
|
||||||
contextBg.fillRect(0, 0, canvas.width, canvas.height);
|
|
||||||
drawMatrix(arena, {x: 0, y: 0}, contextBg);
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawHolding() {
|
|
||||||
contextHold.clearRect(0, 0, canvasHold.width, canvasHold.height);
|
|
||||||
const offset = centerOffset(holdingTile);
|
|
||||||
const x = 3 - (holdingTile[0].length / 2) + offset.x;
|
|
||||||
const y = 3 - (holdingTile.length / 2) + offset.y;
|
|
||||||
drawMatrix(holdingTile, {x: x, y: y}, contextHold);
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawMatrix(matrix, offset, useContext = context) {
|
|
||||||
matrix.forEach((row, y) => {
|
|
||||||
row.forEach((value, x) => {
|
|
||||||
if (value !== 0) {
|
|
||||||
drawTile(x, y, offset, colors[value], matrix, useContext);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawRoundRect(ctx, x, y, w, h, r) {
|
function drawRoundRect(ctx, x, y, w, h, r) {
|
||||||
let r1 = r,
|
let r1 = r,
|
||||||
r2 = r,
|
r2 = r,
|
||||||
@@ -312,67 +537,11 @@ function drawRoundRect(ctx, x, y, w, h, r) {
|
|||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawTile(x, y, offset, color, matrix, useContext = context) {
|
|
||||||
const ctx = useContext;
|
|
||||||
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:
|
|
||||||
theme = "default";
|
|
||||||
drawTile(x, y, offset, color, matrix, useContext);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatMillis(millis) {
|
function formatMillis(millis) {
|
||||||
const d = new Date(1000 * Math.round(millis / 1000));
|
const d = new Date(1000 * Math.round(millis / 1000));
|
||||||
return (d.getUTCMinutes() < 10 ? "0" : "") + d.getUTCMinutes() + ":" + (d.getUTCSeconds() < 10 ? "0" : "") + d.getUTCSeconds();
|
return (d.getUTCMinutes() < 10 ? "0" : "") + d.getUTCMinutes() + ":" + (d.getUTCSeconds() < 10 ? "0" : "") + d.getUTCSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
function gameOver() {
|
|
||||||
arena.forEach(row => row.fill(0));
|
|
||||||
timePassed = 0;
|
|
||||||
lastTimeUpdate = Date.now();
|
|
||||||
updateTime();
|
|
||||||
player.score = 0;
|
|
||||||
dropInterval = 1000;
|
|
||||||
updateScore();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCookie(name) {
|
function getCookie(name) {
|
||||||
if (document.cookie === "") {
|
if (document.cookie === "") {
|
||||||
return;
|
return;
|
||||||
@@ -400,79 +569,25 @@ function getCookies() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function merge(arena, player) {
|
function move(ctx = context, matrix, startX, startY, diffX, diffY, duration) {
|
||||||
player.matrix.forEach((row, y) => {
|
let x = startX;
|
||||||
row.forEach((value, x) => {
|
let y = startY;
|
||||||
if (value !== 0) {
|
const speedX = diffX / (duration / 1000);
|
||||||
arena[y + player.pos.y][x + player.pos.x] = value;
|
const speedY = diffY / (duration / 1000);
|
||||||
}
|
let startTime = Date.now();
|
||||||
});
|
// const frames = duration / 60;
|
||||||
});
|
const ani = setInterval(frame, 16.6);
|
||||||
drawArena();
|
|
||||||
}
|
|
||||||
|
|
||||||
function playerDrop() {
|
function frame() {
|
||||||
player.pos.y++;
|
if (Date.now() - startTime >= duration) {
|
||||||
if (collide(arena, player)) {
|
clearInterval(ani);
|
||||||
player.pos.y--;
|
|
||||||
merge(arena, player);
|
|
||||||
playerReset();
|
|
||||||
arenaSweep();
|
|
||||||
updateScore();
|
|
||||||
}
|
|
||||||
dropCounter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function playerHold() {
|
|
||||||
if (isHolding)
|
|
||||||
return;
|
|
||||||
if (holdingTile === null) {
|
|
||||||
holdingTile = player.matrix;
|
|
||||||
playerReset(true);
|
|
||||||
} else {
|
|
||||||
holdingTile = [player.matrix, player.matrix = holdingTile][0];
|
|
||||||
playerReset(true, false);
|
|
||||||
}
|
|
||||||
drawHolding();
|
|
||||||
}
|
|
||||||
|
|
||||||
function playerMove(dir) {
|
|
||||||
player.pos.x += dir;
|
|
||||||
if (collide(arena, player)) {
|
|
||||||
player.pos.x -= dir;
|
|
||||||
}
|
|
||||||
dropCounter *= .75;
|
|
||||||
}
|
|
||||||
|
|
||||||
function playerReset(resetHold = false, newTile = true) {
|
|
||||||
isHolding = resetHold;
|
|
||||||
if (newTile) {
|
|
||||||
player.matrix = upcomingTiles[0];
|
|
||||||
upcomingTiles.splice(0, 1);
|
|
||||||
addTile();
|
|
||||||
}
|
|
||||||
|
|
||||||
player.pos.y = 0;
|
|
||||||
player.pos.x = (arena[0].length / 2 | 0) - (player.matrix[0].length / 2 | 0);
|
|
||||||
|
|
||||||
if (collide(arena, player)) {
|
|
||||||
gameOver();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function playerRotate(dir) {
|
|
||||||
rotate(player.matrix, dir);
|
|
||||||
|
|
||||||
const pos = player.pos.x;
|
|
||||||
let offset = 1;
|
|
||||||
while (collide(arena, player)) {
|
|
||||||
player.pos.x += offset;
|
|
||||||
offset = -(offset + (offset > 0 ? 1 : -1));
|
|
||||||
if (offset > player.matrix[0].length) {
|
|
||||||
rotate(player.matrix, -dir);
|
|
||||||
player.pos.x = pos;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// ctx.clearRect(x, y, matrix[0].length, matrix.length);
|
||||||
|
x += speedX * (Date.now() - startTime) / 1000;
|
||||||
|
y += speedY * (Date.now() - startTime) / 1000;
|
||||||
|
ctx.fillStyle = "#fff";
|
||||||
|
ctx.rect(x, y, matrix[0].length, matrix.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,52 +611,8 @@ function rotate(matrix, dir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveHighscore() {
|
const game = new Game();
|
||||||
if (getCookie("highscore").value < player.score) {
|
|
||||||
document.cookie = "highscore=" + player.score + "; max-age=" + 60 * 60 * 24 * 365 * 1000 + "; path=/;";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function startGame() {
|
function startGame() {
|
||||||
arena = createMatrix(fieldSize.x, fieldSize.y);
|
game.start();
|
||||||
drawArena();
|
|
||||||
addTile();
|
|
||||||
addTile();
|
|
||||||
addTile();
|
|
||||||
playerReset();
|
|
||||||
update();
|
|
||||||
updateScore();
|
|
||||||
startTime = Date.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
function update(time = 0) {
|
|
||||||
if(!isPaused) {
|
|
||||||
const deltaTime = time - lastTime;
|
|
||||||
lastTime = time;
|
|
||||||
|
|
||||||
dropCounter += deltaTime;
|
|
||||||
if (dropCounter > dropInterval) {
|
|
||||||
playerDrop();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateTime();
|
|
||||||
|
|
||||||
draw();
|
|
||||||
requestAnimationFrame(update);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateScore() {
|
|
||||||
if(lastScore !== player.score) {
|
|
||||||
scoreUpdateAni();
|
|
||||||
lastScore = player.score;
|
|
||||||
saveHighscore();
|
|
||||||
}
|
|
||||||
document.getElementById('score').innerText = player.score.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateTime() {
|
|
||||||
timePassed += Date.now() - lastTimeUpdate;
|
|
||||||
timeElement.innerHTML = formatMillis(timePassed);
|
|
||||||
lastTimeUpdate = Date.now();
|
|
||||||
}
|
}
|
33
style.css
33
style.css
@@ -50,6 +50,7 @@ body {
|
|||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
font-size: .6em;
|
font-size: .6em;
|
||||||
|
width: 20%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#menu-content > * {
|
#menu-content > * {
|
||||||
@@ -57,6 +58,34 @@ body {
|
|||||||
border-bottom: 1px solid #444;
|
border-bottom: 1px solid #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#menu-content h3 {
|
||||||
|
margin: 0 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#help-controls dl {
|
||||||
|
height: 273px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#help-controls dt {
|
||||||
|
float: left;
|
||||||
|
width: 30%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#help-controls dt code {
|
||||||
|
background: rgba(255, 255, 255, 1);
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#help-controls dd {
|
||||||
|
float: left;
|
||||||
|
width: 70%;
|
||||||
|
margin: 0 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-open #menu {
|
.menu-open #menu {
|
||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
@@ -168,8 +197,8 @@ body {
|
|||||||
|
|
||||||
#tetris-upcoming {
|
#tetris-upcoming {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 50%;
|
||||||
transform: translateX(.2em);
|
border: solid .2em #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#game-stats {
|
#game-stats {
|
||||||
|
Reference in New Issue
Block a user