Add holding canvas and improve UI layouts
This commit is contained in:
33
index.html
33
index.html
@@ -15,12 +15,25 @@
|
|||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
<div id="menu">
|
<div id="menu">
|
||||||
<div id="language-selector">
|
<div id="menu-content">
|
||||||
<div id="lang-en" class="lang active" data-lang="en">English</div>
|
<div id="language-selector">
|
||||||
<div id="lang-de" class="lang" data-lang="de">Deutsch</div>
|
<div id="lang-en" class="lang active" data-lang="en">English</div>
|
||||||
</div>
|
<div id="lang-de" class="lang" data-lang="de">Deutsch</div>
|
||||||
<div id="theme-selector">
|
</div>
|
||||||
|
<div id="theme-selector">
|
||||||
|
<div class="radio">
|
||||||
|
<input id="theme-default" name="theme" type="radio" checked>
|
||||||
|
<label for="theme-default" class="radio-label">Default</label>
|
||||||
|
</div>
|
||||||
|
<div class="radio">
|
||||||
|
<input id="theme-modern" name="theme" type="radio">
|
||||||
|
<label for="theme-modern" class="radio-label">Modern</label>
|
||||||
|
</div>
|
||||||
|
<div class="radio">
|
||||||
|
<input id="theme-snakes" name="theme" type="radio">
|
||||||
|
<label for="theme-snakes" class="radio-label">Snakes</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="menu-opener">
|
<div id="menu-opener">
|
||||||
@@ -33,8 +46,12 @@
|
|||||||
<div id="time">00:00</div>
|
<div id="time">00:00</div>
|
||||||
<div id="score" data-prefix="Score: ">0</div>
|
<div id="score" data-prefix="Score: ">0</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="tetris-background" width="240" height="400"></canvas>
|
<div id="canvas-container">
|
||||||
<canvas id="tetris" width="240" height="400"></canvas>
|
<canvas id="tetris-hold" width="100" height="100"></canvas>
|
||||||
|
<canvas id="tetris-background" width="240" height="400"></canvas>
|
||||||
|
<canvas id="tetris" width="240" height="400"></canvas>
|
||||||
|
<canvas id="tetris-upcoming" width="100" height="300"></canvas>
|
||||||
|
</div>
|
||||||
<div id="controls">
|
<div id="controls">
|
||||||
<div id="control-text"></div>
|
<div id="control-text"></div>
|
||||||
</div>
|
</div>
|
||||||
|
24
js/menu.js
24
js/menu.js
@@ -3,13 +3,25 @@ window.onresize = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function scaleWindow() {
|
function scaleWindow() {
|
||||||
bgCanvas.height = window.innerHeight - 40;
|
const canvasContainer = document.getElementById("canvas-container");
|
||||||
bgCanvas.width = bgCanvas.height / (5 / 3);
|
const height = window.innerHeight - 40;
|
||||||
bgContext.scale(bgCanvas.width / fieldSize.x, bgCanvas.height / fieldSize.y);
|
const width = height / (5 / 3);
|
||||||
|
|
||||||
canvas.height = window.innerHeight - 40;
|
canvasContainer.height = height;
|
||||||
canvas.width = canvas.height / (5 / 3);
|
canvasContainer.width = width + 200;
|
||||||
context.scale(canvas.width / fieldSize.x, canvas.height / fieldSize.y);
|
|
||||||
|
bgCanvas.height = height;
|
||||||
|
bgCanvas.width = width;
|
||||||
|
bgContext.scale(width / fieldSize.x, height / fieldSize.y);
|
||||||
|
|
||||||
|
canvas.height = height;
|
||||||
|
canvas.width = width;
|
||||||
|
context.scale(width / fieldSize.x, height / fieldSize.y);
|
||||||
|
|
||||||
|
holdCanvas.height = height / fieldSize.y * 4;
|
||||||
|
holdCanvas.width = holdCanvas.height;
|
||||||
|
holdCanvas.style.transform = "translateX(-" + ((width / 2) + holdCanvas.height) + "px) translate(-.4em, -.2em)";
|
||||||
|
holdContext.scale(holdCanvas.width / 6, holdCanvas.width / 6);
|
||||||
|
|
||||||
if(!firstRun && isPaused) {
|
if(!firstRun && isPaused) {
|
||||||
draw();
|
draw();
|
||||||
|
69
js/tetris.js
69
js/tetris.js
@@ -4,6 +4,12 @@ const context = canvas.getContext('2d');
|
|||||||
const bgCanvas = document.getElementById('tetris-background');
|
const bgCanvas = document.getElementById('tetris-background');
|
||||||
const bgContext = bgCanvas.getContext('2d');
|
const bgContext = bgCanvas.getContext('2d');
|
||||||
|
|
||||||
|
const holdCanvas = document.getElementById('tetris-hold');
|
||||||
|
const holdContext = holdCanvas.getContext('2d');
|
||||||
|
|
||||||
|
const upcomingCanvas = document.getElementById('tetris-upcoming');
|
||||||
|
const upcomingContext = upcomingCanvas.getContext('2d');
|
||||||
|
|
||||||
const fieldSize = {x: 12, y: 20};
|
const fieldSize = {x: 12, y: 20};
|
||||||
const tileGap = .05;
|
const tileGap = .05;
|
||||||
|
|
||||||
@@ -134,26 +140,32 @@ function createPiece(type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
// bgContext.fillStyle = '#000';
|
|
||||||
// bgContext.fillRect(0, 0, canvas.width, canvas.height);
|
|
||||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
// clearScreen();
|
|
||||||
|
|
||||||
// drawMatrix(arena, {x: 0, y: 0}, true);
|
|
||||||
drawMatrix(player.matrix, player.pos);
|
drawMatrix(player.matrix, player.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawArena() {
|
function drawArena() {
|
||||||
bgContext.fillStyle = '#000';
|
bgContext.fillStyle = '#000';
|
||||||
bgContext.fillRect(0, 0, canvas.width, canvas.height);
|
bgContext.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
drawMatrix(arena, {x: 0, y: 0}, true);
|
drawMatrix(arena, {x: 0, y: 0}, bgContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawMatrix(matrix, offset, isBg) {
|
function drawHolding() {
|
||||||
|
holdContext.clearRect(0, 0, holdCanvas.width, holdCanvas.height);
|
||||||
|
console.log(holdingTile, holdingTile.length, holdCanvas.width / (holdingTile.length + 2));
|
||||||
|
// holdContext.scale(holdCanvas.width / (holdingTile.length + 2), holdCanvas.width / (holdingTile.length + 2));
|
||||||
|
const tile = removeEmpty(holdingTile);
|
||||||
|
const x = 3 - (tile[0].length / 2);
|
||||||
|
const y = 3 - (tile.length / 2);
|
||||||
|
console.log(x, y);
|
||||||
|
drawMatrix(tile, {x: x, y: y}, holdContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawMatrix(matrix, offset, useContext = context) {
|
||||||
matrix.forEach((row, y) => {
|
matrix.forEach((row, y) => {
|
||||||
row.forEach((value, x) => {
|
row.forEach((value, x) => {
|
||||||
if (value !== 0) {
|
if (value !== 0) {
|
||||||
drawTile(x, y, offset, colors[value], matrix, isBg);
|
drawTile(x, y, offset, colors[value], matrix, useContext);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -203,13 +215,12 @@ function drawRoundRect(ctx, x, y, w, h, r) {
|
|||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawTile(x, y, offset, color, matrix, isBg) {
|
function drawTile(x, y, offset, color, matrix, useContext = context) {
|
||||||
let ctx = context;
|
const ctx = useContext;
|
||||||
if (isBg) {
|
|
||||||
ctx = bgContext;
|
|
||||||
}
|
|
||||||
switch (theme) {
|
switch (theme) {
|
||||||
case "default":
|
case "default":
|
||||||
|
if (ctx === holdContext)
|
||||||
|
console.log(ctx, color, x + offset.x + tileGap / 2, y + offset.y + tileGap / 2, 1 - tileGap, 1 - tileGap);
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
ctx.fillRect(x + offset.x + tileGap / 2, y + offset.y + tileGap / 2, 1 - tileGap, 1 - tileGap);
|
ctx.fillRect(x + offset.x + tileGap / 2, y + offset.y + tileGap / 2, 1 - tileGap, 1 - tileGap);
|
||||||
break;
|
break;
|
||||||
@@ -218,6 +229,7 @@ function drawTile(x, y, offset, color, matrix, isBg) {
|
|||||||
drawRoundRect(ctx, x + offset.x + tileGap / 2, y + offset.y + tileGap / 2, 1 - tileGap, 1 - tileGap, .15);
|
drawRoundRect(ctx, x + offset.x + tileGap / 2, y + offset.y + tileGap / 2, 1 - tileGap, 1 - tileGap, .15);
|
||||||
break;
|
break;
|
||||||
case "snakes":
|
case "snakes":
|
||||||
|
console.log(ctx);
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
let r1 = .15, // top right
|
let r1 = .15, // top right
|
||||||
r2 = .15, // bottom right
|
r2 = .15, // bottom right
|
||||||
@@ -246,6 +258,8 @@ function drawTile(x, y, offset, color, matrix, isBg) {
|
|||||||
drawRoundRect(ctx, x + offset.x, y + offset.y, 1, 1, [r1, r2, r3, r4]);
|
drawRoundRect(ctx, x + offset.x, y + offset.y, 1, 1, [r1, r2, r3, r4]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
theme = "default";
|
||||||
|
drawTile(x, y, offset, color, matrix, useContext);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,6 +334,7 @@ function playerHold() {
|
|||||||
holdingTile = [player.matrix, player.matrix = holdingTile][0];
|
holdingTile = [player.matrix, player.matrix = holdingTile][0];
|
||||||
playerReset(true, false);
|
playerReset(true, false);
|
||||||
}
|
}
|
||||||
|
drawHolding();
|
||||||
}
|
}
|
||||||
|
|
||||||
function playerMove(dir) {
|
function playerMove(dir) {
|
||||||
@@ -385,6 +400,34 @@ function prerenderPieces() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeEmpty(matrix) {
|
||||||
|
const tempMatrix = rotate(matrix, 1);
|
||||||
|
matrix.forEach((row, y) => {
|
||||||
|
let onlyZeroes = true;
|
||||||
|
row.forEach((value, x) => {
|
||||||
|
if (value > 0) {
|
||||||
|
onlyZeroes = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (onlyZeroes) {
|
||||||
|
matrix.splice(y, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tempMatrix.forEach((col, x) => {
|
||||||
|
let onlyZeroes = true;
|
||||||
|
col.forEach((value, y) => {
|
||||||
|
if (value > 0) {
|
||||||
|
onlyZeroes = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (onlyZeroes)
|
||||||
|
matrix.forEach((row, y) => {
|
||||||
|
matrix[y].splice(x, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
function rotate(matrix, dir) {
|
function rotate(matrix, dir) {
|
||||||
for (let y = 0; y < matrix.length; ++y) {
|
for (let y = 0; y < matrix.length; ++y) {
|
||||||
for (let x = 0; x < y; ++x) {
|
for (let x = 0; x < y; ++x) {
|
||||||
|
188
style.css
188
style.css
@@ -8,13 +8,64 @@ body {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#language-selector {
|
.menu {
|
||||||
|
-webkit-transition: 0.1s -webkit-transform linear;
|
||||||
|
transition: 0.1s -webkit-transform linear;
|
||||||
|
transition: 0.1s transform linear;
|
||||||
|
transition: 0.1s transform linear, 0.1s -webkit-transform linear;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 15px;
|
background: 0;
|
||||||
top: 20px;
|
float: left;
|
||||||
font-size: 14px;
|
height: 2.7rem;
|
||||||
font-weight: 300;
|
width: 3.5rem;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
outline: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
-webkit-transform: scale(.5);
|
||||||
|
-moz-transform: scale(.5);
|
||||||
|
-ms-transform: scale(.5);
|
||||||
|
-o-transform: scale(.5);
|
||||||
|
transform: scale(.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu {
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, .75);
|
||||||
|
transform: translateX(-100%);
|
||||||
|
-webkit-transition: transform .5s;
|
||||||
|
-moz-transition: transform .5s;
|
||||||
|
-ms-transition: transform .5s;
|
||||||
|
-o-transition: transform .5s;
|
||||||
|
transition: transform .5s;
|
||||||
|
z-index: 100;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-content {
|
||||||
|
position: fixed;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-size: .6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-content > * {
|
||||||
|
padding: 20px;
|
||||||
|
border-bottom: 1px solid #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-open #menu {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu-opener {
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: 10px;
|
||||||
|
z-index: 101;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lang {
|
.lang {
|
||||||
@@ -81,6 +132,15 @@ body {
|
|||||||
filter: url(#f1);
|
filter: url(#f1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#canvas-container {
|
||||||
|
height: 936px;
|
||||||
|
width: 761px;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
#tetris, #tetris-background {
|
#tetris, #tetris-background {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@@ -100,6 +160,18 @@ body {
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tetris-hold {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
border: solid .2em #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tetris-upcoming {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
transform: translateX(.2em);
|
||||||
|
}
|
||||||
|
|
||||||
#game-stats {
|
#game-stats {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@@ -122,6 +194,7 @@ body {
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%) translateX(30vw);
|
transform: translate(-50%, -50%) translateX(30vw);
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
max-width: 20vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
#footer {
|
#footer {
|
||||||
@@ -160,31 +233,6 @@ body {
|
|||||||
color: rgba(255, 255, 255, 1);
|
color: rgba(255, 255, 255, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#menu-opener {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu {
|
|
||||||
-webkit-transition: 0.1s -webkit-transform linear;
|
|
||||||
transition: 0.1s -webkit-transform linear;
|
|
||||||
transition: 0.1s transform linear;
|
|
||||||
transition: 0.1s transform linear, 0.1s -webkit-transform linear;
|
|
||||||
position: absolute;
|
|
||||||
background: 0;
|
|
||||||
float: left;
|
|
||||||
height: 2.7rem;
|
|
||||||
width: 3.5rem;
|
|
||||||
z-index: 1;
|
|
||||||
outline: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
-webkit-transform: scale(.5);
|
|
||||||
-moz-transform: scale(.5);
|
|
||||||
-ms-transform: scale(.5);
|
|
||||||
-o-transform: scale(.5);
|
|
||||||
transform: scale(.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar, .bar::before, .bar::after {
|
.bar, .bar::before, .bar::after {
|
||||||
-webkit-transition: 0.2s background linear 0.1s, 0.2s top linear 0.2s, 0.2s -webkit-transform linear;
|
-webkit-transition: 0.2s background linear 0.1s, 0.2s top linear 0.2s, 0.2s -webkit-transform linear;
|
||||||
transition: 0.2s background linear 0.1s, 0.2s top linear 0.2s, 0.2s -webkit-transform linear;
|
transition: 0.2s background linear 0.1s, 0.2s top linear 0.2s, 0.2s -webkit-transform linear;
|
||||||
@@ -293,31 +341,57 @@ body {
|
|||||||
#control-text {
|
#control-text {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#menu {
|
|
||||||
position: fixed;
|
/*
|
||||||
width: 100%;
|
Radio Buttons
|
||||||
height: 100%;
|
*/
|
||||||
background: rgba(0, 0, 0, .75);
|
|
||||||
transform: translateX(-100%);
|
.radio {
|
||||||
-webkit-transition: transform .5s;
|
margin: 0.5rem;
|
||||||
-moz-transition: transform .5s;
|
}
|
||||||
-ms-transition: transform .5s;
|
|
||||||
-o-transition: transform .5s;
|
.radio input[type="radio"] {
|
||||||
transition: transform .5s;
|
position: absolute;
|
||||||
z-index: 100;
|
opacity: 0;
|
||||||
top: 0;
|
}
|
||||||
}
|
|
||||||
|
.radio input[type="radio"] + .radio-label:before {
|
||||||
.menu-open #menu {
|
content: '';
|
||||||
transform: none;
|
background: #f4f4f4;
|
||||||
}
|
border-radius: 100%;
|
||||||
|
border: 1px solid #b4b4b4;
|
||||||
#menu-opener {
|
display: inline-block;
|
||||||
position: absolute;
|
width: 1.4em;
|
||||||
display: block;
|
height: 1.4em;
|
||||||
left: 10px;
|
position: relative;
|
||||||
top: 10px;
|
top: -0.2em;
|
||||||
z-index: 101;
|
margin-right: 1em;
|
||||||
}
|
vertical-align: top;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
-webkit-transition: all 250ms ease;
|
||||||
|
transition: all 250ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio input[type="radio"]:checked + .radio-label:before {
|
||||||
|
background-color: #3197EE;
|
||||||
|
-webkit-box-shadow: inset 0 0 0 4px #f4f4f4;
|
||||||
|
box-shadow: inset 0 0 0 4px #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio input[type="radio"]:focus + .radio-label:before {
|
||||||
|
outline: none;
|
||||||
|
border-color: #3197EE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio input[type="radio"]:disabled + .radio-label:before {
|
||||||
|
-webkit-box-shadow: inset 0 0 0 4px #f4f4f4;
|
||||||
|
box-shadow: inset 0 0 0 4px #f4f4f4;
|
||||||
|
border-color: #b4b4b4;
|
||||||
|
background: #b4b4b4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio input[type="radio"] + .radio-label:empty:before {
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
Reference in New Issue
Block a user