Complete restructuring of code: adjusting it to OOP + language and layout improvements
This commit is contained in:
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');
|
||||
const context = canvas.getContext('2d');
|
||||
this.player = new Player(this, game);
|
||||
|
||||
const canvasBg = document.getElementById('tetris-background');
|
||||
const contextBg = canvasBg.getContext('2d');
|
||||
this.canvas = document.getElementById('tetris');
|
||||
this.context = this.canvas.getContext('2d');
|
||||
|
||||
const canvasHold = document.getElementById('tetris-hold');
|
||||
const contextHold = canvasHold.getContext('2d');
|
||||
this.canvasBg = document.getElementById('tetris-background');
|
||||
this.contextBg = this.canvasBg.getContext('2d');
|
||||
|
||||
const canvasUpcoming = document.getElementById('tetris-upcoming');
|
||||
const contextUpcoming = canvasUpcoming.getContext('2d');
|
||||
this.canvasHold = document.getElementById('tetris-hold');
|
||||
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 = [
|
||||
null,
|
||||
@@ -23,118 +382,17 @@ const colors = [
|
||||
'#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 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 timeElement = document.getElementById("time");
|
||||
let timePassed = 0;
|
||||
|
||||
|
||||
let upcomingTiles = [];
|
||||
|
||||
|
||||
if (typeof console === "undefined") {
|
||||
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) {
|
||||
let offsetX = 0;
|
||||
let offsetY = 0;
|
||||
@@ -168,10 +426,6 @@ function centerOffset(matrix) {
|
||||
return {x: offsetX, y: offsetY};
|
||||
}
|
||||
|
||||
function clearScreen() {
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
|
||||
function collide(arena, player) {
|
||||
const [m, o] = [player.matrix, player.pos];
|
||||
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) {
|
||||
let r1 = r,
|
||||
r2 = r,
|
||||
@@ -312,67 +537,11 @@ function drawRoundRect(ctx, x, y, w, h, r) {
|
||||
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) {
|
||||
const d = new Date(1000 * Math.round(millis / 1000));
|
||||
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) {
|
||||
if (document.cookie === "") {
|
||||
return;
|
||||
@@ -400,79 +569,25 @@ function getCookies() {
|
||||
}
|
||||
}
|
||||
|
||||
function merge(arena, player) {
|
||||
player.matrix.forEach((row, y) => {
|
||||
row.forEach((value, x) => {
|
||||
if (value !== 0) {
|
||||
arena[y + player.pos.y][x + player.pos.x] = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
drawArena();
|
||||
}
|
||||
function move(ctx = context, matrix, startX, startY, diffX, diffY, duration) {
|
||||
let x = startX;
|
||||
let y = startY;
|
||||
const speedX = diffX / (duration / 1000);
|
||||
const speedY = diffY / (duration / 1000);
|
||||
let startTime = Date.now();
|
||||
// const frames = duration / 60;
|
||||
const ani = setInterval(frame, 16.6);
|
||||
|
||||
function playerDrop() {
|
||||
player.pos.y++;
|
||||
if (collide(arena, player)) {
|
||||
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;
|
||||
function frame() {
|
||||
if (Date.now() - startTime >= duration) {
|
||||
clearInterval(ani);
|
||||
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() {
|
||||
if (getCookie("highscore").value < player.score) {
|
||||
document.cookie = "highscore=" + player.score + "; max-age=" + 60 * 60 * 24 * 365 * 1000 + "; path=/;";
|
||||
}
|
||||
}
|
||||
const game = new Game();
|
||||
|
||||
function startGame() {
|
||||
arena = createMatrix(fieldSize.x, fieldSize.y);
|
||||
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();
|
||||
game.start();
|
||||
}
|
Reference in New Issue
Block a user