From d5cd080abaa0874e0667e48c3ed235b7017fb8a4 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 18 Feb 2018 12:45:54 +0100 Subject: [PATCH] Add new retro theme & fix touch input problem --- .gitignore | 2 +- index.html | 4 +++ js/arena.js | 1 + js/game.js | 15 +++++++++-- js/language.js | 2 ++ js/menu.js | 33 ++++++----------------- js/tetris.js | 64 +++++++++++++++++++++++++++++++++++++++++++++ js/touch-control.js | 12 ++++----- style.css | 24 ++++++++++++++++- 9 files changed, 122 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 1c2d52b..62c8935 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -.idea/* +.idea/ \ No newline at end of file diff --git a/index.html b/index.html index fbc4c88..c8aadf2 100644 --- a/index.html +++ b/index.html @@ -31,6 +31,10 @@ +
+ + +
diff --git a/js/arena.js b/js/arena.js index d95615d..175d3bf 100644 --- a/js/arena.js +++ b/js/arena.js @@ -2,6 +2,7 @@ class Arena { constructor(gameInfo, game) { this.g = gameInfo; this.game = game; + this.p = this.g.player; this.field = createMatrix(this.g.fieldSize.x, this.g.fieldSize.y); } diff --git a/js/game.js b/js/game.js index 0227e35..e0754e1 100644 --- a/js/game.js +++ b/js/game.js @@ -18,6 +18,8 @@ class Game { } drawHolding() { + if (this.p.holdingTile === null) + return; 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; @@ -35,8 +37,7 @@ class Game { }); } - drawTile(x, y, offset, color, matrix, useContext = this.g.context) { - const ctx = useContext; + drawTile(x, y, offset, color, matrix, ctx = this.g.context) { switch (this.g.theme) { case "default": ctx.fillStyle = color; @@ -74,6 +75,9 @@ class Game { } drawRoundRect(ctx, x + offset.x, y + offset.y, 1, 1, [r1, r2, r3, r4]); break; + case "retro": + drawReliefRect(ctx, x + offset.x, y + offset.y, 1, 1, .15, color); + break; default: this.g.theme = "default"; this.drawTile(x, y, offset, color, matrix, ctx); @@ -115,6 +119,13 @@ class Game { this.drawArena(); } + redrawScreen() { + this.draw(); + this.drawArena(); + this.drawHolding(); + this.drawUpcoming(); + } + registerListeners() { // Keyboard controls document.addEventListener('keydown', event => { diff --git a/js/language.js b/js/language.js index 68fd030..d04076e 100644 --- a/js/language.js +++ b/js/language.js @@ -13,6 +13,7 @@ const en = { counterTime: "Time: ", themeDefault: "Default", themeModern: "Modern", + themeRetro: "Retro", themeSnakes: "Snakes", titleAppearance: "Appearance", titleControls: "Controls", @@ -36,6 +37,7 @@ const de = { counterTime: "Zeit: ", themeDefault: "Standard", themeModern: "Modern", + themeRetro: "Retro", themeSnakes: "Schlangen", titleAppearance: "Aussehen", titleControls: "Steuerung", diff --git a/js/menu.js b/js/menu.js index 34ba95a..f3ad597 100644 --- a/js/menu.js +++ b/js/menu.js @@ -7,10 +7,7 @@ let escState = 1; window.onresize = () => { scaleWindow(); - game.draw(); - game.drawArena(); - game.drawUpcoming(); - game.drawHolding(); + game.redrawScreen(); }; function scaleWindow() { @@ -93,7 +90,8 @@ document.getElementById("game-reset").addEventListener("click", () => { document.getElementsByName("theme").forEach((el) => { el.addEventListener("change", (e) => { - game.theme = e.target.getAttribute("data-theme"); + game.g.theme = e.target.getAttribute("data-theme"); + game.redrawScreen(); }); }); @@ -185,25 +183,10 @@ function fadeBlurOut() { const scoreEl = document.getElementById("score"); const nativeTransform = getComputedStyle(scoreEl).transform; function scoreUpdateAni() { - const scale = 1.5; - const finalScale = 1; - let currentScale = 1; - let upscaling = true; - - const id = setInterval(frame, 5); - - function frame() { - if(currentScale <= scale && upscaling) { - currentScale += 0.02; - scoreEl.style.transform = nativeTransform + " scale(" + currentScale + ")"; - } else if (currentScale >= finalScale) { - upscaling = false; - currentScale -= 0.02; - scoreEl.style.transform = nativeTransform + " scale(" + currentScale + ")"; - } else { - clearInterval(id); - } - } + scoreEl.classList.add("update"); + setTimeout(() => { + scoreEl.classList.remove("update"); + }, 1500); } function showMenu() { @@ -235,7 +218,7 @@ function hideMenu() { game.g.lastTimeUpdate = Date.now(); fadeBlurOut(); if(!firstRun) { - game.update(lastTime); + game.update(game.g.lastTime); } } diff --git a/js/tetris.js b/js/tetris.js index 79af12b..778210e 100644 --- a/js/tetris.js +++ b/js/tetris.js @@ -164,6 +164,47 @@ function drawRoundRect(ctx, x, y, w, h, r) { ctx.fill(); } +function drawReliefRect(ctx, x, y, w, h, l, clr) { + ctx.fillStyle = clr; + ctx.fillRect(x + l, y + l, w - (2 * l), h - (2 * l)); + + ctx.fillStyle = colorLuminance(clr, .6); + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x + w, y); + ctx.lineTo(x + w - l, y + l); + ctx.lineTo(x + l, y + l); + ctx.fill(); + ctx.closePath(); + + ctx.fillStyle = colorLuminance(clr, .3); + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x, y + h); + ctx.lineTo(x + l, y + h - l); + ctx.lineTo(x + l, y + l); + ctx.fill(); + ctx.closePath(); + + ctx.fillStyle = colorLuminance(clr, -.6); + ctx.beginPath(); + ctx.moveTo(x, y + h); + ctx.lineTo(x + w, y + h); + ctx.lineTo(x + w - l, y + h - l); + ctx.lineTo(x + l, y + h - l); + ctx.fill(); + ctx.closePath(); + + ctx.fillStyle = colorLuminance(clr, -.3); + ctx.beginPath(); + ctx.moveTo(x + w, y); + ctx.lineTo(x + w, y + h); + ctx.lineTo(x + w - l, y + h - l); + ctx.lineTo(x + w - l, y + l); + ctx.fill(); + ctx.closePath(); +} + 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(); @@ -242,4 +283,27 @@ const game = new Game(); function startGame() { game.start(); +} + +/** + * @return {string} + */ +function colorLuminance(hex, lum) { + + // validate hex string + hex = String(hex).replace(/[^0-9a-f]/gi, ''); + if (hex.length < 6) { + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + lum = lum || 0; + + // convert to decimal and change luminosity + let rgb = "#", c, i; + for (i = 0; i < 3; i++) { + c = parseInt(hex.substr(i * 2, 2), 16); + c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16); + rgb += ("00" + c).substr(c.length); + } + + return rgb; } \ No newline at end of file diff --git a/js/touch-control.js b/js/touch-control.js index 57ad34a..7f99870 100644 --- a/js/touch-control.js +++ b/js/touch-control.js @@ -1,27 +1,27 @@ const hammertime = new Hammer(document.getElementById("tetris")); hammertime.on('swipeleft', (e) => { - keys.left.action(); + game.g.keys.left.action(); }); hammertime.on('swiperight', (e) => { - keys.right.action(); + game.g.keys.right.action(); }); hammertime.on('swipeup', () => { - keys.holdTile.action(); + game.g.keys.holdTile.action(); }); hammertime.on('pandown swipedown', (e) => { - keys.down.action(); + game.g.keys.down.action(); }); hammertime.on('tap', (e) => { if (e.tapCount >= 2) { - keys.rotateRight.action(); + game.g.keys.rotateRight.action(); } }); hammertime.on('press', () => { - keys.down.action(); + game.g.keys.down.action(); }); \ No newline at end of file diff --git a/style.css b/style.css index 33adaea..b81bf40 100644 --- a/style.css +++ b/style.css @@ -212,11 +212,29 @@ body { #score { font-weight: 900; - bottom: 0; + bottom: initial; top: 2.5vh; font-size: 5vh; } +#score.update { + animation: scoreUpdate .5s; +} + +@keyframes scoreUpdate { + 0% { + transform: translateX(-50%) scale(1); + } + + 50% { + transform: translateX(-50%) scale(1.5); + } + + 100% { + transform: translateX(-50%) scale(1); + } +} + #time:before, #score:before { content: attr(data-prefix); } @@ -230,6 +248,10 @@ body { max-width: 20vw; } +.game-over #score { + top: 50%; +} + #footer { position: absolute; bottom: 10px;