From c2c0b2ad5a48c307c5908c2c21f7d4ca8fac5ea4 Mon Sep 17 00:00:00 2001 From: JohnOnias Date: Tue, 6 Oct 2026 14:20:40 -0300 Subject: [PATCH 01/19] =?UTF-8?q?refactor:=20refatora=C3=A7=C3=A3o=20do=20?= =?UTF-8?q?codigo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 24 ++++++++ inde.html => script.js | 125 ++++++++++++++++++++++++++--------------- stats.js | 10 ---- styles.css | 18 ++++++ 4 files changed, 122 insertions(+), 55 deletions(-) create mode 100644 index.html rename inde.html => script.js (73%) delete mode 100644 stats.js create mode 100644 styles.css diff --git a/index.html b/index.html new file mode 100644 index 0000000..5b06c65 --- /dev/null +++ b/index.html @@ -0,0 +1,24 @@ + + + + Javascript Tetris + + + + +
+ + + Sorry, this example cannot be run because your browser does not support the <canvas> element + +
+ + + + + diff --git a/inde.html b/script.js similarity index 73% rename from inde.html rename to script.js index 87e71f8..9a9e578 100644 --- a/inde.html +++ b/script.js @@ -1,45 +1,83 @@ - - - - Javascript Tetris - - - - - -
- - - Sorry, this example cannot be run because your browser does not support the <canvas> element - -
- - - - - diff --git a/stats.js b/stats.js deleted file mode 100644 index 5d89bff..0000000 --- a/stats.js +++ /dev/null @@ -1,10 +0,0 @@ -// stats.js r6 - http://github.com/mrdoob/stats.js -var Stats=function(){function s(a,g,d){var f,c,e;for(c=0;c<30;c++)for(f=0;f<73;f++)e=(f+c*74)*4,a[e]=a[e+4],a[e+1]=a[e+5],a[e+2]=a[e+6];for(c=0;c<30;c++)e=(73+c*74)*4,c'+n+" MS ("+z+"-"+A+")";o.putImageData(B,0,0);F=j;if(j> -v+1E3){l=Math.round(u*1E3/(j-v));w=Math.min(w,l);x=Math.max(x,l);s(y.data,Math.min(30,30-l/100*30),"fps");d.innerHTML=''+l+" FPS ("+w+"-"+x+")";m.putImageData(y,0,0);if(t==3)p=performance.memory.usedJSHeapSize*9.54E-7,C=Math.min(C,p),D=Math.max(D,p),s(E.data,Math.min(30,30-p/2),"mb"),i.innerHTML=''+Math.round(p)+" MB ("+Math.round(C)+"-"+Math.round(D)+")",q.putImageData(E,0,0);v=j;u=0}}}}; - diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..56dd7a5 --- /dev/null +++ b/styles.css @@ -0,0 +1,18 @@ +body { font-family: Helvetica, sans-serif; } + #tetris { margin: 1em auto; padding: 1em; border: 4px solid black; border-radius: 10px; background-color: #F8F8F8; } + #stats { display: inline-block; vertical-align: top; } + #canvas { display: inline-block; vertical-align: top; background: url(texture.jpg); box-shadow: 10px 10px 10px #999; border: 2px solid #333; } + #menu { display: inline-block; vertical-align: top; position: relative; } + #menu p { margin: 0.5em 0; text-align: center; } + #menu p a { text-decoration: none; color: black; } + #upcoming { display: block; margin: 0 auto; background-color: #E0E0E0; } + #score { color: blue; font-weight: bold; vertical-align: middle; } + #rows { color: blue; font-weight: bold; vertical-align: middle; } + #stats { position: absolute; bottom: 0em; right: 1em; } + @media screen and (min-width: 0px) and (min-height: 0px) { #tetris { font-size: 0.75em; width: 250px; } #menu { width: 100px; height: 200px; } #upcoming { width: 50px; height: 50px; } #canvas { width: 100px; height: 200px; } } /* 10px chunks */ + @media screen and (min-width: 400px) and (min-height: 400px) { #tetris { font-size: 1.00em; width: 350px; } #menu { width: 150px; height: 300px; } #upcoming { width: 75px; height: 75px; } #canvas { width: 150px; height: 300px; } } /* 15px chunks */ + @media screen and (min-width: 500px) and (min-height: 500px) { #tetris { font-size: 1.25em; width: 450px; } #menu { width: 200px; height: 400px; } #upcoming { width: 100px; height: 100px; } #canvas { width: 200px; height: 400px; } } /* 20px chunks */ + @media screen and (min-width: 600px) and (min-height: 600px) { #tetris { font-size: 1.50em; width: 550px; } #menu { width: 250px; height: 500px; } #upcoming { width: 125px; height: 125px; } #canvas { width: 250px; height: 500px; } } /* 25px chunks */ + @media screen and (min-width: 700px) and (min-height: 700px) { #tetris { font-size: 1.75em; width: 650px; } #menu { width: 300px; height: 600px; } #upcoming { width: 150px; height: 150px; } #canvas { width: 300px; height: 600px; } } /* 30px chunks */ + @media screen and (min-width: 800px) and (min-height: 800px) { #tetris { font-size: 2.00em; width: 750px; } #menu { width: 350px; height: 700px; } #upcoming { width: 175px; height: 175px; } #canvas { width: 350px; height: 700px; } } /* 35px chunks */ + @media screen and (min-width: 900px) and (min-height: 900px) { #tetris { font-size: 2.25em; width: 850px; } #menu { width: 400px; height: 800px; } #upcoming { width: 200px; height: 200px; } #canvas { width: 400px; height: 800px; } } /* 40px chunks */ From a9d5a47bc10f53887b615e5f8bdfc052c314988d Mon Sep 17 00:00:00 2001 From: JohnOnias Date: Tue, 6 Oct 2026 14:55:09 -0300 Subject: [PATCH 02/19] feat(pause): adcionando o modal --- index.html | 16 +++ styles.css | 282 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 280 insertions(+), 18 deletions(-) diff --git a/index.html b/index.html index 5b06c65..95a7957 100644 --- a/index.html +++ b/index.html @@ -20,5 +20,21 @@ +
+
+ + + + + +
+ + +
+ + diff --git a/styles.css b/styles.css index 56dd7a5..cd36f3f 100644 --- a/styles.css +++ b/styles.css @@ -1,18 +1,264 @@ -body { font-family: Helvetica, sans-serif; } - #tetris { margin: 1em auto; padding: 1em; border: 4px solid black; border-radius: 10px; background-color: #F8F8F8; } - #stats { display: inline-block; vertical-align: top; } - #canvas { display: inline-block; vertical-align: top; background: url(texture.jpg); box-shadow: 10px 10px 10px #999; border: 2px solid #333; } - #menu { display: inline-block; vertical-align: top; position: relative; } - #menu p { margin: 0.5em 0; text-align: center; } - #menu p a { text-decoration: none; color: black; } - #upcoming { display: block; margin: 0 auto; background-color: #E0E0E0; } - #score { color: blue; font-weight: bold; vertical-align: middle; } - #rows { color: blue; font-weight: bold; vertical-align: middle; } - #stats { position: absolute; bottom: 0em; right: 1em; } - @media screen and (min-width: 0px) and (min-height: 0px) { #tetris { font-size: 0.75em; width: 250px; } #menu { width: 100px; height: 200px; } #upcoming { width: 50px; height: 50px; } #canvas { width: 100px; height: 200px; } } /* 10px chunks */ - @media screen and (min-width: 400px) and (min-height: 400px) { #tetris { font-size: 1.00em; width: 350px; } #menu { width: 150px; height: 300px; } #upcoming { width: 75px; height: 75px; } #canvas { width: 150px; height: 300px; } } /* 15px chunks */ - @media screen and (min-width: 500px) and (min-height: 500px) { #tetris { font-size: 1.25em; width: 450px; } #menu { width: 200px; height: 400px; } #upcoming { width: 100px; height: 100px; } #canvas { width: 200px; height: 400px; } } /* 20px chunks */ - @media screen and (min-width: 600px) and (min-height: 600px) { #tetris { font-size: 1.50em; width: 550px; } #menu { width: 250px; height: 500px; } #upcoming { width: 125px; height: 125px; } #canvas { width: 250px; height: 500px; } } /* 25px chunks */ - @media screen and (min-width: 700px) and (min-height: 700px) { #tetris { font-size: 1.75em; width: 650px; } #menu { width: 300px; height: 600px; } #upcoming { width: 150px; height: 150px; } #canvas { width: 300px; height: 600px; } } /* 30px chunks */ - @media screen and (min-width: 800px) and (min-height: 800px) { #tetris { font-size: 2.00em; width: 750px; } #menu { width: 350px; height: 700px; } #upcoming { width: 175px; height: 175px; } #canvas { width: 350px; height: 700px; } } /* 35px chunks */ - @media screen and (min-width: 900px) and (min-height: 900px) { #tetris { font-size: 2.25em; width: 850px; } #menu { width: 400px; height: 800px; } #upcoming { width: 200px; height: 200px; } #canvas { width: 400px; height: 800px; } } /* 40px chunks */ +body { + font-family: Helvetica, sans-serif; +} + +#tetris { + margin: 1em auto; + padding: 1em; + border: 4px solid black; + border-radius: 10px; + background-color: #F8F8F8; +} + +#stats { + display: inline-block; + vertical-align: top; +} + +#canvas { + display: inline-block; + vertical-align: top; + background: url(texture.jpg); + box-shadow: 10px 10px 10px #999; + border: 2px solid #333; +} + +#menu { + display: inline-block; + vertical-align: top; + position: relative; +} + +#menu p { + margin: 0.5em 0; + text-align: center; +} + +#menu p a { + text-decoration: none; + color: black; +} + +#upcoming { + display: block; + margin: 0 auto; + background-color: #E0E0E0; +} + +#score { + color: blue; + font-weight: bold; + vertical-align: middle; +} + +#rows { + color: blue; + font-weight: bold; + vertical-align: middle; +} + +#stats { + position: absolute; + bottom: 0em; + right: 1em; +} + +@media screen and (min-width: 0px) and (min-height: 0px) { + #tetris { + font-size: 0.75em; + width: 250px; + } + + #menu { + width: 100px; + height: 200px; + } + + #upcoming { + width: 50px; + height: 50px; + } + + #canvas { + width: 100px; + height: 200px; + } +} + +/* 10px chunks */ +@media screen and (min-width: 400px) and (min-height: 400px) { + #tetris { + font-size: 1.00em; + width: 350px; + } + + #menu { + width: 150px; + height: 300px; + } + + #upcoming { + width: 75px; + height: 75px; + } + + #canvas { + width: 150px; + height: 300px; + } +} + +/* 15px chunks */ +@media screen and (min-width: 500px) and (min-height: 500px) { + #tetris { + font-size: 1.25em; + width: 450px; + } + + #menu { + width: 200px; + height: 400px; + } + + #upcoming { + width: 100px; + height: 100px; + } + + #canvas { + width: 200px; + height: 400px; + } +} + +/* 20px chunks */ +@media screen and (min-width: 600px) and (min-height: 600px) { + #tetris { + font-size: 1.50em; + width: 550px; + } + + #menu { + width: 250px; + height: 500px; + } + + #upcoming { + width: 125px; + height: 125px; + } + + #canvas { + width: 250px; + height: 500px; + } +} + +/* 25px chunks */ +@media screen and (min-width: 700px) and (min-height: 700px) { + #tetris { + font-size: 1.75em; + width: 650px; + } + + #menu { + width: 300px; + height: 600px; + } + + #upcoming { + width: 150px; + height: 150px; + } + + #canvas { + width: 300px; + height: 600px; + } +} + +/* 30px chunks */ +@media screen and (min-width: 800px) and (min-height: 800px) { + #tetris { + font-size: 2.00em; + width: 750px; + } + + #menu { + width: 350px; + height: 700px; + } + + #upcoming { + width: 175px; + height: 175px; + } + + #canvas { + width: 350px; + height: 700px; + } +} + +/* 35px chunks */ +@media screen and (min-width: 900px) and (min-height: 900px) { + #tetris { + font-size: 2.25em; + width: 850px; + } + + #menu { + width: 400px; + height: 800px; + } + + #upcoming { + width: 200px; + height: 200px; + } + + #canvas { + width: 400px; + height: 800px; + } +} + +/* 40px chunks */ + + + +#container-pause{ + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + z-index: 1000; +} +#pause { + display: flex; + flex-direction: rom; + justify-content: center; + align-items: center; + background-color: #999; + color: #F8F8F8; + height: 350px; + width: 500px; + border-radius: 15px; + + +} + +#resume { + height: 100px; + width: 200px; + border: 1px solid; + border-radius: 15px; + font-size: 32px; + font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; + box-shadow: 5px 5px 1px black; + +} +#resume:hover{ + background-color: aqua; +} \ No newline at end of file From fd6541fa8044f514b9248734d7294ad5e02f65c8 Mon Sep 17 00:00:00 2001 From: Fidelixjv Date: Thu, 8 Oct 2026 14:05:39 -0300 Subject: [PATCH 03/19] feat: adiciona diferentes temas visuais ao jogo --- index.html | 50 ++- script.js | 1090 +++++++++++++++++++++++++++++----------------------- styles.css | 157 +++++++- 3 files changed, 789 insertions(+), 508 deletions(-) diff --git a/index.html b/index.html index 5b06c65..2a296b0 100644 --- a/index.html +++ b/index.html @@ -1,24 +1,58 @@ + Javascript Tetris - + +
+ + - Sorry, this example cannot be run because your browser does not support the <canvas> element + Sorry, this example cannot be run because your browser does not support the + <canvas> element +
- + - + + \ No newline at end of file diff --git a/script.js b/script.js index 9a9e578..6212082 100644 --- a/script.js +++ b/script.js @@ -1,493 +1,617 @@ - // stats.js r6 - http://github.com/mrdoob/stats.js var Stats = function () { - function s(a, g, d) { var f, c, e; for (c = 0; c < 30; c++)for (f = 0; f < 73; f++)e = (f + c * 74) * 4, a[e] = a[e + 4], a[e + 1] = a[e + 5], a[e + 2] = a[e + 6]; for (c = 0; c < 30; c++)e = (73 + c * 74) * 4, c < g ? (a[e] = b[d].bg.r, a[e + 1] = b[d].bg.g, a[e + 2] = b[d].bg.b) : (a[e] = b[d].fg.r, a[e + 1] = b[d].fg.g, a[e + 2] = b[d].fg.b) } var r = 0, t = 2, g, u = 0, j = (new Date).getTime(), F = j, v = j, l = 0, w = 1E3, x = 0, k, d, a, m, y, n = 0, z = 1E3, A = 0, f, c, o, B, p = 0, C = 1E3, D = 0, h, i, q, E, b = { - fps: { bg: { r: 16, g: 16, b: 48 }, fg: { r: 0, g: 255, b: 255 } }, ms: { bg: { r: 16, g: 48, b: 16 }, fg: { r: 0, g: 255, b: 0 } }, mb: { - bg: { - r: 48, g: 16, - b: 26 - }, fg: { r: 255, g: 0, b: 128 } - } - }; g = document.createElement("div"); - g.style.cursor = "pointer"; - g.style.width = "80px"; - g.style.opacity = "0.9"; - g.style.zIndex = "10001"; - g.addEventListener("click", function () { r++; r == t && (r = 0); - k.style.display = "none"; - f.style.display = "none"; - h.style.display = "none"; - switch (r) { case 0: k.style.display = "block"; - break; case 1: f.style.display = "block"; - break; case 2: h.style.display = "block" } }, !1); - k = document.createElement("div"); - k.style.backgroundColor = "rgb(" + Math.floor(b.fps.bg.r / 2) + "," + Math.floor(b.fps.bg.g / - 2) + "," + Math.floor(b.fps.bg.b / 2) + ")"; k.style.padding = "2px 0px 3px 0px"; - g.appendChild(k); - d = document.createElement("div"); - d.style.fontFamily = "Helvetica, Arial, sans-serif"; - d.style.textAlign = "left"; - d.style.fontSize = "9px"; - d.style.color = "rgb(" + b.fps.fg.r + "," + b.fps.fg.g + "," + b.fps.fg.b + ")"; - d.style.margin = "0px 0px 1px 3px"; d.innerHTML = 'FPS'; - k.appendChild(d); - a = document.createElement("canvas"); - a.width = 74; - a.height = 30; - a.style.display = "block"; - a.style.marginLeft = "3px"; - k.appendChild(a); - m = a.getContext("2d"); - m.fillStyle = "rgb(" + b.fps.bg.r + "," + b.fps.bg.g + "," + b.fps.bg.b + ")"; - m.fillRect(0, 0, a.width, a.height); - y = m.getImageData(0, 0, a.width, a.height); - f = document.createElement("div"); - f.style.backgroundColor = "rgb(" + Math.floor(b.ms.bg.r / 2) + "," + Math.floor(b.ms.bg.g / 2) + "," + Math.floor(b.ms.bg.b / 2) + ")"; - f.style.padding = "2px 0px 3px 0px"; f.style.display = "none"; - g.appendChild(f); c = document.createElement("div"); - c.style.fontFamily = "Helvetica, Arial, sans-serif"; - c.style.textAlign = "left"; c.style.fontSize = "9px"; - c.style.color = "rgb(" + b.ms.fg.r + "," + b.ms.fg.g + "," + b.ms.fg.b + ")"; - c.style.margin = "0px 0px 1px 3px"; c.innerHTML = 'MS'; - f.appendChild(c); a = document.createElement("canvas"); - a.width = 74; a.height = 30; a.style.display = "block"; a.style.marginLeft = "3px"; f.appendChild(a); - o = a.getContext("2d"); o.fillStyle = "rgb(" + b.ms.bg.r + "," + b.ms.bg.g + "," + b.ms.bg.b + ")"; - o.fillRect(0, 0, a.width, a.height); B = o.getImageData(0, 0, a.width, a.height); try { - performance && performance.memory && performance.memory.totalJSHeapSize && (t = 3) - } catch (G) { } h = document.createElement("div"); h.style.backgroundColor = "rgb(" + Math.floor(b.mb.bg.r / 2) + "," + Math.floor(b.mb.bg.g / 2) + "," + Math.floor(b.mb.bg.b / 2) + ")"; - h.style.padding = "2px 0px 3px 0px"; h.style.display = "none"; - g.appendChild(h); - i = document.createElement("div"); i.style.fontFamily = "Helvetica, Arial, sans-serif"; i.style.textAlign = "left"; i.style.fontSize = "9px"; i.style.color = "rgb(" + b.mb.fg.r + "," + b.mb.fg.g + "," + b.mb.fg.b + ")"; - i.style.margin = "0px 0px 1px 3px"; i.innerHTML = 'MB'; - h.appendChild(i); - a = document.createElement("canvas"); - a.width = 74; a.height = 30; a.style.display = "block"; a.style.marginLeft = "3px"; h.appendChild(a); - q = a.getContext("2d"); q.fillStyle = "#301010"; q.fillRect(0, 0, a.width, a.height); - E = q.getImageData(0, 0, a.width, a.height); return { - domElement: g, update: function () { - u++; j = (new Date).getTime(); n = j - F; z = Math.min(z, n); A = Math.max(A, n); s(B.data, Math.min(30, 30 - n / 200 * 30), "ms"); c.innerHTML = '' + n + " MS (" + z + "-" + A + ")"; - o.putImageData(B, 0, 0); - F = j; if (j > v + 1E3) { l = Math.round(u * 1E3 / (j - v)); w = Math.min(w, l); - x = Math.max(x, l); - s(y.data, Math.min(30, 30 - l / 100 * 30), "fps"); - d.innerHTML = '' + l + " FPS (" + w + "-" + x + ")"; - m.putImageData(y, 0, 0); if (t == 3) p = performance.memory.usedJSHeapSize * 9.54E-7, C = Math.min(C, p), D = Math.max(D, p), s(E.data, Math.min(30, 30 - p / 2), "mb"), i.innerHTML = '' + Math.round(p) + " MB (" + Math.round(C) + "-" + Math.round(D) + ")", q.putImageData(E, 0, 0); v = j; - u = 0 } - } - } -}; - - - - //------------------------------------------------------------------------- - // base helper methods - //------------------------------------------------------------------------- - - function get(id) { return document.getElementById(id); } - function hide(id) { get(id).style.visibility = 'hidden'; } - function show(id) { get(id).style.visibility = null; } - function html(id, html) { get(id).innerHTML = html; } - - function timestamp() { return new Date().getTime(); } - function random(min, max) { return (min + (Math.random() * (max - min))); } - function randomChoice(choices) { return choices[Math.round(random(0, choices.length-1))]; } - - if (!window.requestAnimationFrame) { // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ - window.requestAnimationFrame = window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function(callback, element) { - window.setTimeout(callback, 1000 / 60); - } - } - - //------------------------------------------------------------------------- - // game constants - //------------------------------------------------------------------------- - - var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 }, - DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, MIN: 0, MAX: 3 }, - stats = new Stats(), - canvas = get('canvas'), - ctx = canvas.getContext('2d'), - ucanvas = get('upcoming'), - uctx = ucanvas.getContext('2d'), - speed = { start: 0.6, decrement: 0.005, min: 0.1 }, // how long before piece drops by 1 row (seconds) - nx = 10, // width of tetris court (in blocks) - ny = 20, // height of tetris court (in blocks) - nu = 5; // width/height of upcoming preview (in blocks) - - //------------------------------------------------------------------------- - // game variables (initialized during reset) - //------------------------------------------------------------------------- - - var dx, dy, // pixel size of a single tetris block - blocks, // 2 dimensional array (nx*ny) representing tetris court - either empty block or occupied by a 'piece' - actions, // queue of user actions (inputs) - playing, // true|false - game is in progress - paused, // true|false - game is currently paued (to differentiate need for reset) - dt, // time since starting this game - current, // the current piece - next, // the next piece - score, // the current score - vscore, // the currently displayed score (it catches up to score in small chunks - like a spinning slot machine) - rows, // number of completed rows in the current game - step; // how long before current piece drops by 1 row - - //------------------------------------------------------------------------- - // tetris pieces - // - // blocks: each element represents a rotation of the piece (0, 90, 180, 270) - // each element is a 16 bit integer where the 16 bits represent - // a 4x4 set of blocks, e.g. j.blocks[0] = 0x44C0 - // - // 0100 = 0x4 << 3 = 0x4000 - // 0100 = 0x4 << 2 = 0x0400 - // 1100 = 0xC << 1 = 0x00C0 - // 0000 = 0x0 << 0 = 0x0000 - // ------ - // 0x44C0 - // - //------------------------------------------------------------------------- - - var i = { size: 4, blocks: [0x0F00, 0x2222, 0x00F0, 0x4444], color: 'purple' }; - var j = { size: 3, blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20], color: 'pink' }; - var l = { size: 3, blocks: [0x4460, 0x0E80, 0xC440, 0x2E00], color: 'salmon' }; - var o = { size: 2, blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00], color: 'lime' }; - var s = { size: 3, blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], color: 'teal' }; - var t = { size: 3, blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], color: 'coral' }; - var z = { size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'olive' }; - - //------------------------------------------------ - // do the bit manipulation and iterate through each - // occupied block (x,y) for a given piece - //------------------------------------------------ - function eachblock(type, x, y, dir, fn) { - var bit, result, row = 0, col = 0, blocks = type.blocks[dir]; - for(bit = 0x8000 ; bit > 0 ; bit = bit >> 1) { - if (blocks & bit) { - fn(x + col, y + row); - } - if (++col === 4) { - col = 0; - ++row; - } - } - } - - //----------------------------------------------------- - // check if a piece can fit into a position in the grid - //----------------------------------------------------- - function occupied(type, x, y, dir) { - var result = false - eachblock(type, x, y, dir, function(x, y) { - if ((x < 0) || (x >= nx) || (y < 0) || (y >= ny) || getBlock(x,y)) - result = true; - }); - return result; - } - - function unoccupied(type, x, y, dir) { - return !occupied(type, x, y, dir); - } - - //----------------------------------------- - // start with 4 instances of each piece and - // pick randomly until the 'bag is empty' - //----------------------------------------- - var pieces = []; - function randomPiece() { - if (pieces.length == 0) - pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z]; - var type = pieces.splice(random(0, pieces.length-1), 1)[0]; - return { type: type, dir: DIR.UP, x: Math.round(random(0, nx - type.size)), y: 0 }; - } - - - //------------------------------------------------------------------------- - // GAME LOOP - //------------------------------------------------------------------------- - - function run() { - - showStats(); // initialize FPS counter - addEvents(); // attach keydown and resize events - - var last = now = timestamp(); - function frame() { - now = timestamp(); - update(Math.min(1, (now - last) / 1000.0)); // using requestAnimationFrame have to be able to handle large delta's caused when it 'hibernates' in a background or non-visible tab - draw(); - stats.update(); - last = now; - requestAnimationFrame(frame, canvas); - } - - resize(); // setup all our sizing information - reset(); // reset the per-game variables - frame(); // start the first frame - - } - - function showStats() { - stats.domElement.id = 'stats'; - get('menu').appendChild(stats.domElement); - } - - function addEvents() { - document.addEventListener('keydown', keydown, false); - window.addEventListener('resize', resize, false); - } - - function resize(event) { - canvas.width = canvas.clientWidth; // set canvas logical size equal to its physical size - canvas.height = canvas.clientHeight; // (ditto) - ucanvas.width = ucanvas.clientWidth; - ucanvas.height = ucanvas.clientHeight; - dx = canvas.width / nx; // pixel size of a single tetris block - dy = canvas.height / ny; // (ditto) - invalidate(); - invalidateNext(); - } - - function keydown(ev) { - var handled = false; - if (playing) { - switch(ev.keyCode) { - case KEY.LEFT: actions.push(DIR.LEFT); handled = true; break; - case KEY.RIGHT: actions.push(DIR.RIGHT); handled = true; break; - case KEY.UP: actions.push(DIR.UP); handled = true; break; - case KEY.DOWN: actions.push(DIR.DOWN); handled = true; break; - case KEY.ESC: lose(); handled = true; break; - case KEY.SPACE: pause(); handled = true; break; - } - } - else if (ev.keyCode == KEY.SPACE) { - if(paused) { - restart(); - handled = true; - }else{ - play(); - handled = true; - } - } - if (handled) - ev.preventDefault(); // prevent arrow keys from scrolling the page (supported in IE9+ and all other browsers) - } - - //------------------------------------------------------------------------- - // GAME LOGIC - //------------------------------------------------------------------------- - - function play() { hide('start'); reset(); paused = false; playing = true; } - function pause() {show('start'); paused = true; playing = false;} - function restart() {hide('start'); paused = false; playing = true;} - function lose() { show('start'); setVisualScore(); playing = false; } - - function setVisualScore(n) { vscore = n || score; invalidateScore(); } - function setScore(n) { score = n; setVisualScore(n); } - function addScore(n) { score = score + n; } - function clearScore() { setScore(0); } - function clearRows() { setRows(0); } - function setRows(n) { rows = n; step = Math.max(speed.min, speed.start - (speed.decrement*rows)); invalidateRows(); } - function addRows(n) { setRows(rows + n); } - function getBlock(x,y) { return (blocks && blocks[x] ? blocks[x][y] : null); } - function setBlock(x,y,type) { blocks[x] = blocks[x] || []; blocks[x][y] = type; invalidate(); } - function clearBlocks() { blocks = []; invalidate(); } - function clearActions() { actions = []; } - function setCurrentPiece(piece) { current = piece || randomPiece(); invalidate(); } - function setNextPiece(piece) { next = piece || randomPiece(); invalidateNext(); } - - function reset() { - dt = 0; - clearActions(); - clearBlocks(); - clearRows(); - clearScore(); - setCurrentPiece(next); - setNextPiece(); - } - - function update(idt) { - if (playing) { - if (vscore < score) - setVisualScore(vscore + 1); - handle(actions.shift()); - dt = dt + idt; - if (dt > step) { - dt = dt - step; - drop(); - } + function s(a, g, d) { var f, c, e; for (c = 0; c < 30; c++)for (f = 0; f < 73; f++)e = (f + c * 74) * 4, a[e] = a[e + 4], a[e + 1] = a[e + 5], a[e + 2] = a[e + 6]; for (c = 0; c < 30; c++)e = (73 + c * 74) * 4, c < g ? (a[e] = b[d].bg.r, a[e + 1] = b[d].bg.g, a[e + 2] = b[d].bg.b) : (a[e] = b[d].fg.r, a[e + 1] = b[d].fg.g, a[e + 2] = b[d].fg.b) } var r = 0, t = 2, g, u = 0, j = (new Date).getTime(), F = j, v = j, l = 0, w = 1E3, x = 0, k, d, a, m, y, n = 0, z = 1E3, A = 0, f, c, o, B, p = 0, C = 1E3, D = 0, h, i, q, E, b = { + fps: { bg: { r: 16, g: 16, b: 48 }, fg: { r: 0, g: 255, b: 255 } }, ms: { bg: { r: 16, g: 48, b: 16 }, fg: { r: 0, g: 255, b: 0 } }, mb: { + bg: { + r: 48, g: 16, + b: 26 + }, fg: { r: 255, g: 0, b: 128 } } - } - - function handle(action) { - switch(action) { - case DIR.LEFT: move(DIR.LEFT); break; - case DIR.RIGHT: move(DIR.RIGHT); break; - case DIR.UP: rotate(); break; - case DIR.DOWN: drop(); break; - } - } - - function move(dir) { - var x = current.x, y = current.y; - switch(dir) { - case DIR.RIGHT: x = x + 1; break; - case DIR.LEFT: x = x - 1; break; - case DIR.DOWN: y = y + 1; break; - } - if (unoccupied(current.type, x, y, current.dir)) { - current.x = x; - current.y = y; - invalidate(); - return true; + }; g = document.createElement("div"); + g.style.cursor = "pointer"; + g.style.width = "80px"; + g.style.opacity = "0.9"; + g.style.zIndex = "10001"; + g.addEventListener("click", function () { r++; r == t && (r = 0); + k.style.display = "none"; + f.style.display = "none"; + h.style.display = "none"; + switch (r) { case 0: k.style.display = "block"; + break; case 1: f.style.display = "block"; + break; case 2: h.style.display = "block" } }, !1); + k = document.createElement("div"); + k.style.backgroundColor = "rgb(" + Math.floor(b.fps.bg.r / 2) + "," + Math.floor(b.fps.bg.g / + 2) + "," + Math.floor(b.fps.bg.b / 2) + ")"; k.style.padding = "2px 0px 3px 0px"; + g.appendChild(k); + d = document.createElement("div"); + d.style.fontFamily = "Helvetica, Arial, sans-serif"; + d.style.textAlign = "left"; + d.style.fontSize = "9px"; + d.style.color = "rgb(" + b.fps.fg.r + "," + b.fps.fg.g + "," + b.fps.fg.b + ")"; + d.style.margin = "0px 0px 1px 3px"; d.innerHTML = 'FPS'; + k.appendChild(d); + a = document.createElement("canvas"); + a.width = 74; + a.height = 30; + a.style.display = "block"; + a.style.marginLeft = "3px"; + k.appendChild(a); + m = a.getContext("2d"); + m.fillStyle = "rgb(" + b.fps.bg.r + "," + b.fps.bg.g + "," + b.fps.bg.b + ")"; + m.fillRect(0, 0, a.width, a.height); + y = m.getImageData(0, 0, a.width, a.height); + f = document.createElement("div"); + f.style.backgroundColor = "rgb(" + Math.floor(b.ms.bg.r / 2) + "," + Math.floor(b.ms.bg.g / 2) + "," + Math.floor(b.ms.bg.b / 2) + ")"; + f.style.padding = "2px 0px 3px 0px"; f.style.display = "none"; + g.appendChild(f); c = document.createElement("div"); + c.style.fontFamily = "Helvetica, Arial, sans-serif"; + c.style.textAlign = "left"; c.style.fontSize = "9px"; + c.style.color = "rgb(" + b.ms.fg.r + "," + b.ms.fg.g + "," + b.ms.fg.b + ")"; + c.style.margin = "0px 0px 1px 3px"; c.innerHTML = 'MS'; + f.appendChild(c); a = document.createElement("canvas"); + a.width = 74; a.height = 30; a.style.display = "block"; a.style.marginLeft = "3px"; f.appendChild(a); + o = a.getContext("2d"); o.fillStyle = "rgb(" + b.ms.bg.r + "," + b.ms.bg.g + "," + b.ms.bg.b + ")"; + o.fillRect(0, 0, a.width, a.height); B = o.getImageData(0, 0, a.width, a.height); try { + performance && performance.memory && performance.memory.totalJSHeapSize && (t = 3) + } catch (G) { } h = document.createElement("div"); h.style.backgroundColor = "rgb(" + Math.floor(b.mb.bg.r / 2) + "," + Math.floor(b.mb.bg.g / 2) + "," + Math.floor(b.mb.bg.b / 2) + ")"; + h.style.padding = "2px 0px 3px 0px"; h.style.display = "none"; + g.appendChild(h); + i = document.createElement("div"); i.style.fontFamily = "Helvetica, Arial, sans-serif"; i.style.textAlign = "left"; i.style.fontSize = "9px"; i.style.color = "rgb(" + b.mb.fg.r + "," + b.mb.fg.g + "," + b.mb.fg.b + ")"; + i.style.margin = "0px 0px 1px 3px"; i.innerHTML = 'MB'; + h.appendChild(i); + a = document.createElement("canvas"); + a.width = 74; a.height = 30; a.style.display = "block"; a.style.marginLeft = "3px"; h.appendChild(a); + q = a.getContext("2d"); q.fillStyle = "#301010"; q.fillRect(0, 0, a.width, a.height); + E = q.getImageData(0, 0, a.width, a.height); return { + domElement: g, update: function () { + u++; j = (new Date).getTime(); n = j - F; z = Math.min(z, n); A = Math.max(A, n); s(B.data, Math.min(30, 30 - n / 200 * 30), "ms"); c.innerHTML = '' + n + " MS (" + z + "-" + A + ")"; + o.putImageData(B, 0, 0); + F = j; if (j > v + 1E3) { l = Math.round(u * 1E3 / (j - v)); w = Math.min(w, l); + x = Math.max(x, l); + s(y.data, Math.min(30, 30 - l / 100 * 30), "fps"); + d.innerHTML = '' + l + " FPS (" + w + "-" + x + ")"; + m.putImageData(y, 0, 0); if (t == 3) p = performance.memory.usedJSHeapSize * 9.54E-7, C = Math.min(C, p), D = Math.max(D, p), s(E.data, Math.min(30, 30 - p / 2), "mb"), i.innerHTML = '' + Math.round(p) + " MB (" + Math.round(C) + "-" + Math.round(D) + ")", q.putImageData(E, 0, 0); v = j; + u = 0 } } - else { - return false; - } - } - - function rotate() { - var newdir = (current.dir == DIR.MAX ? DIR.MIN : current.dir + 1); - if (unoccupied(current.type, current.x, current.y, newdir)) { - current.dir = newdir; - invalidate(); - } - } - - function drop() { - if (!move(DIR.DOWN)) { - addScore(10); - dropPiece(); - removeLines(); - setCurrentPiece(next); - setNextPiece(randomPiece()); - clearActions(); - if (occupied(current.type, current.x, current.y, current.dir)) { - lose(); - } - } - } - - function dropPiece() { - eachblock(current.type, current.x, current.y, current.dir, function(x, y) { - setBlock(x, y, current.type); - }); - } - - function removeLines() { - var x, y, complete, n = 0; - for(y = ny ; y > 0 ; --y) { - complete = true; - for(x = 0 ; x < nx ; ++x) { - if (!getBlock(x, y)) - complete = false; - } - if (complete) { - removeLine(y); - y = y + 1; // recheck same line - n++; - } - } - if (n > 0) { - addRows(n); - addScore(100*Math.pow(2,n-1)); // 1: 100, 2: 200, 3: 400, 4: 800 - } - } - - function removeLine(n) { - var x, y; - for(y = n ; y >= 0 ; --y) { - for(x = 0 ; x < nx ; ++x) - setBlock(x, y, (y == 0) ? null : getBlock(x, y-1)); - } - } - - //------------------------------------------------------------------------- - // RENDERING - //------------------------------------------------------------------------- - - var invalid = {}; - - function invalidate() { invalid.court = true; } - function invalidateNext() { invalid.next = true; } - function invalidateScore() { invalid.score = true; } - function invalidateRows() { invalid.rows = true; } - - function draw() { - ctx.save(); - ctx.lineWidth = 1; - ctx.translate(0.5, 0.5); // for crisp 1px black lines - drawCourt(); - drawNext(); - drawScore(); - drawRows(); - ctx.restore(); - } - - function drawCourt() { - if (invalid.court) { - ctx.clearRect(0, 0, canvas.width, canvas.height); - if (playing) - drawPiece(ctx, current.type, current.x, current.y, current.dir); - var x, y, block; - for(y = 0 ; y < ny ; y++) { - for (x = 0 ; x < nx ; x++) { - if (block = getBlock(x,y)) - drawBlock(ctx, x, y, block.color); - } - } - ctx.strokeRect(0, 0, nx*dx - 1, ny*dy - 1); // court boundary - invalid.court = false; - } - } + } +}; - function drawNext() { - if (invalid.next) { - var padding = (nu - next.type.size) / 2; // half-arsed attempt at centering next piece display - uctx.save(); - uctx.translate(0.5, 0.5); - uctx.clearRect(0, 0, nu*dx, nu*dy); - drawPiece(uctx, next.type, padding, padding, next.dir); - uctx.strokeStyle = 'black'; - uctx.strokeRect(0, 0, nu*dx - 1, nu*dy - 1); - uctx.restore(); - invalid.next = false; - } - } - function drawScore() { - if (invalid.score) { - html('score', ("00000" + Math.floor(vscore)).slice(-5)); - invalid.score = false; - } - } - function drawRows() { - if (invalid.rows) { - html('rows', rows); - invalid.rows = false; - } - } +//------------------------------------------------------------------------- +// base helper methods +//------------------------------------------------------------------------- + +function get(id) { return document.getElementById(id); } +function hide(id) { get(id).style.visibility = 'hidden'; } +function show(id) { get(id).style.visibility = null; } +function html(id, html) { get(id).innerHTML = html; } + +function timestamp() { return new Date().getTime(); } +function random(min, max) { return (min + (Math.random() * (max - min))); } +function randomChoice(choices) { return choices[Math.round(random(0, choices.length-1))]; } + +if (!window.requestAnimationFrame) { // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ +window.requestAnimationFrame = window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback, element) { + window.setTimeout(callback, 1000 / 60); + } +} + +//------------------------------------------------------------------------- +// game constants +//------------------------------------------------------------------------- + +var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 }, + DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, MIN: 0, MAX: 3 }, + stats = new Stats(), + canvas = get('canvas'), + ctx = canvas.getContext('2d'), + ucanvas = get('upcoming'), + uctx = ucanvas.getContext('2d'), + speed = { start: 0.6, decrement: 0.005, min: 0.1 }, // how long before piece drops by 1 row (seconds) + nx = 10, // width of tetris court (in blocks) + ny = 20, // height of tetris court (in blocks) + nu = 5; // width/height of upcoming preview (in blocks) + +//------------------------------------------------------------------------- +// game variables (initialized during reset) +//------------------------------------------------------------------------- + +var dx, dy, // pixel size of a single tetris block + blocks, // 2 dimensional array (nx*ny) representing tetris court - either empty block or occupied by a 'piece' + actions, // queue of user actions (inputs) + playing, // true|false - game is in progress + paused, // true|false - game is currently paued (to differentiate need for reset) + dt, // time since starting this game + current, // the current piece + next, // the next piece + score, // the current score + vscore, // the currently displayed score (it catches up to score in small chunks - like a spinning slot machine) + rows, // number of completed rows in the current game + step; // how long before current piece drops by 1 row + +//------------------------------------------------------------------------- +// tetris pieces +// +// blocks: each element represents a rotation of the piece (0, 90, 180, 270) +// each element is a 16 bit integer where the 16 bits represent +// a 4x4 set of blocks, e.g. j.blocks[0] = 0x44C0 +// +// 0100 = 0x4 << 3 = 0x4000 +// 0100 = 0x4 << 2 = 0x0400 +// 1100 = 0xC << 1 = 0x00C0 +// 0000 = 0x0 << 0 = 0x0000 +// ------ +// 0x44C0 +// +//------------------------------------------------------------------------- + +var i = { id: 'i', size: 4, blocks: [0x0F00, 0x2222, 0x00F0, 0x4444], color: 'purple' }; +var j = { id: 'j', size: 3, blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20], color: 'pink' }; +var l = { id: 'l', size: 3, blocks: [0x4460, 0x0E80, 0xC440, 0x2E00], color: 'salmon' }; +var o = { id: 'o', size: 2, blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00], color: 'lime' }; +var s = { id: 's', size: 3, blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], color: 'teal' }; +var t = { id: 't', size: 3, blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], color: 'coral' }; +var z = { id: 'z', size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'olive' }; + + +//------------------------------------------------------------------------- +// TEMAS VISUAIS +//------------------------------------------------------------------------- + +var THEMES = { +classic: { + className: 'theme-classic', + pieces: { + i: '#8A2BE2', + j: '#FF69B4', + l: '#FA8072', + o: '#32CD32', + s: '#008080', + t: '#FF7F50', + z: '#808000' + } +}, + +ocean: { + className: 'theme-ocean', + pieces: { + i: '#00E5FF', + j: '#2979FF', + l: '#00B8D4', + o: '#00E676', + s: '#00ACC1', + t: '#40C4FF', + z: '#1565C0' + } +}, + +red: { + className: 'theme-red', + pieces: { + i: '#FF1744', + j: '#D50000', + l: '#FF5252', + o: '#FF8A65', + s: '#F50057', + t: '#FF3D00', + z: '#B71C1C' + } +}, + +neon: { + className: 'theme-neon', + pieces: { + i: '#00FFFF', + j: '#FF00E6', + l: '#7C4DFF', + o: '#76FF03', + s: '#00FF9D', + t: '#FFEA00', + z: '#FF1744' + } +} +}; - function drawPiece(ctx, type, x, y, dir) { - eachblock(type, x, y, dir, function(x, y) { - drawBlock(ctx, x, y, type.color); - }); +var currentTheme = 'classic'; + +function getPieceColor(type) { +if (!type || !type.id) + return type ? type.color : '#888888'; + +var theme = THEMES[currentTheme]; + +if (theme && theme.pieces[type.id]) + return theme.pieces[type.id]; + +return type.color; +} + + +//------------------------------------------------ +// do the bit manipulation and iterate through each +// occupied block (x,y) for a given piece +//------------------------------------------------ +function eachblock(type, x, y, dir, fn) { +var bit, result, row = 0, col = 0, blocks = type.blocks[dir]; +for(bit = 0x8000 ; bit > 0 ; bit = bit >> 1) { + if (blocks & bit) { + fn(x + col, y + row); + } + if (++col === 4) { + col = 0; + ++row; + } +} +} + +//----------------------------------------------------- +// check if a piece can fit into a position in the grid +//----------------------------------------------------- +function occupied(type, x, y, dir) { +var result = false +eachblock(type, x, y, dir, function(x, y) { + if ((x < 0) || (x >= nx) || (y < 0) || (y >= ny) || getBlock(x,y)) + result = true; +}); +return result; +} + +function unoccupied(type, x, y, dir) { +return !occupied(type, x, y, dir); +} + +//----------------------------------------- +// start with 4 instances of each piece and +// pick randomly until the 'bag is empty' +//----------------------------------------- +var pieces = []; +function randomPiece() { +if (pieces.length == 0) + pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z]; +var type = pieces.splice(random(0, pieces.length-1), 1)[0]; +return { type: type, dir: DIR.UP, x: Math.round(random(0, nx - type.size)), y: 0 }; +} + + +//------------------------------------------------------------------------- +// GAME LOOP +//------------------------------------------------------------------------- + +function run() { + +showStats(); // initialize FPS counter +addEvents(); // attach keydown and resize events + +var last = now = timestamp(); +function frame() { + now = timestamp(); + update(Math.min(1, (now - last) / 1000.0)); // using requestAnimationFrame have to be able to handle large delta's caused when it 'hibernates' in a background or non-visible tab + draw(); + stats.update(); + last = now; + requestAnimationFrame(frame, canvas); +} + +resize(); // setup all our sizing information +reset(); // reset the per-game variables +frame(); // start the first frame + +} + +function showStats() { +stats.domElement.id = 'stats'; +get('menu').appendChild(stats.domElement); +} + +function addEvents() { +document.addEventListener('keydown', keydown, false); +window.addEventListener('resize', resize, false); +} + +function resize(event) { +canvas.width = canvas.clientWidth; // set canvas logical size equal to its physical size +canvas.height = canvas.clientHeight; // (ditto) +ucanvas.width = ucanvas.clientWidth; +ucanvas.height = ucanvas.clientHeight; +dx = canvas.width / nx; // pixel size of a single tetris block +dy = canvas.height / ny; // (ditto) +invalidate(); +invalidateNext(); +} + +function keydown(ev) { +var handled = false; +if (playing) { + switch(ev.keyCode) { + case KEY.LEFT: actions.push(DIR.LEFT); handled = true; break; + case KEY.RIGHT: actions.push(DIR.RIGHT); handled = true; break; + case KEY.UP: actions.push(DIR.UP); handled = true; break; + case KEY.DOWN: actions.push(DIR.DOWN); handled = true; break; + case KEY.ESC: lose(); handled = true; break; + case KEY.SPACE: pause(); handled = true; break; + } +} +else if (ev.keyCode == KEY.SPACE) { + if(paused) { + restart(); + handled = true; + }else{ + play(); + handled = true; } - - function drawBlock(ctx, x, y, color) { - ctx.fillStyle = color; - ctx.fillRect(x*dx, y*dy, dx, dy); - ctx.strokeRect(x*dx, y*dy, dx, dy) +} +if (handled) + ev.preventDefault(); // prevent arrow keys from scrolling the page (supported in IE9+ and all other browsers) +} + +//------------------------------------------------------------------------- +// GAME LOGIC +//------------------------------------------------------------------------- + +function play() { hide('start'); reset(); paused = false; playing = true; } +function pause() {show('start'); paused = true; playing = false;} +function restart() {hide('start'); paused = false; playing = true;} +function lose() { show('start'); setVisualScore(); playing = false; } + +function setVisualScore(n) { vscore = n || score; invalidateScore(); } +function setScore(n) { score = n; setVisualScore(n); } +function addScore(n) { score = score + n; } +function clearScore() { setScore(0); } +function clearRows() { setRows(0); } +function setRows(n) { rows = n; step = Math.max(speed.min, speed.start - (speed.decrement*rows)); invalidateRows(); } +function addRows(n) { setRows(rows + n); } +function getBlock(x,y) { return (blocks && blocks[x] ? blocks[x][y] : null); } +function setBlock(x,y,type) { blocks[x] = blocks[x] || []; blocks[x][y] = type; invalidate(); } +function clearBlocks() { blocks = []; invalidate(); } +function clearActions() { actions = []; } +function setCurrentPiece(piece) { current = piece || randomPiece(); invalidate(); } +function setNextPiece(piece) { next = piece || randomPiece(); invalidateNext(); } + +function reset() { +dt = 0; +clearActions(); +clearBlocks(); +clearRows(); +clearScore(); +setCurrentPiece(next); +setNextPiece(); +} + +function update(idt) { +if (playing) { + if (vscore < score) + setVisualScore(vscore + 1); + handle(actions.shift()); + dt = dt + idt; + if (dt > step) { + dt = dt - step; + drop(); + } +} +} + +function handle(action) { +switch(action) { + case DIR.LEFT: move(DIR.LEFT); break; + case DIR.RIGHT: move(DIR.RIGHT); break; + case DIR.UP: rotate(); break; + case DIR.DOWN: drop(); break; +} +} + +function move(dir) { +var x = current.x, y = current.y; +switch(dir) { + case DIR.RIGHT: x = x + 1; break; + case DIR.LEFT: x = x - 1; break; + case DIR.DOWN: y = y + 1; break; +} +if (unoccupied(current.type, x, y, current.dir)) { + current.x = x; + current.y = y; + invalidate(); + return true; +} +else { + return false; +} +} + +function rotate() { +var newdir = (current.dir == DIR.MAX ? DIR.MIN : current.dir + 1); +if (unoccupied(current.type, current.x, current.y, newdir)) { + current.dir = newdir; + invalidate(); +} +} + +function drop() { +if (!move(DIR.DOWN)) { + addScore(10); + dropPiece(); + removeLines(); + setCurrentPiece(next); + setNextPiece(randomPiece()); + clearActions(); + if (occupied(current.type, current.x, current.y, current.dir)) { + lose(); + } +} +} + +function dropPiece() { +eachblock(current.type, current.x, current.y, current.dir, function(x, y) { + setBlock(x, y, current.type); +}); +} + +function removeLines() { +var x, y, complete, n = 0; +for(y = ny ; y > 0 ; --y) { + complete = true; + for(x = 0 ; x < nx ; ++x) { + if (!getBlock(x, y)) + complete = false; + } + if (complete) { + removeLine(y); + y = y + 1; // recheck same line + n++; + } +} +if (n > 0) { + addRows(n); + addScore(100*Math.pow(2,n-1)); // 1: 100, 2: 200, 3: 400, 4: 800 +} +} + +function removeLine(n) { +var x, y; +for(y = n ; y >= 0 ; --y) { + for(x = 0 ; x < nx ; ++x) + setBlock(x, y, (y == 0) ? null : getBlock(x, y-1)); +} +} + +//------------------------------------------------------------------------- +// RENDERING +//------------------------------------------------------------------------- + +var invalid = {}; + +function invalidate() { invalid.court = true; } +function invalidateNext() { invalid.next = true; } +function invalidateScore() { invalid.score = true; } +function invalidateRows() { invalid.rows = true; } + + +//------------------------------------------------------------------------- +// APLICAÇÃO DOS TEMAS +//------------------------------------------------------------------------- + +function applyTheme(themeName) { + if (!THEMES[themeName]) + themeName = 'classic'; + + currentTheme = themeName; + + var body = document.body; + + body.classList.remove( + 'theme-classic', + 'theme-ocean', + 'theme-red', + 'theme-neon' + ); + + body.classList.add(THEMES[themeName].className); + + var select = get('theme-select'); + + if (select) + select.value = themeName; + + localStorage.setItem('tetris-theme', themeName); + + invalidate(); + invalidateNext(); +} + +function initializeTheme() { +var savedTheme = localStorage.getItem('tetris-theme'); + +if (!savedTheme || !THEMES[savedTheme]) + savedTheme = 'classic'; + +applyTheme(savedTheme); + +var select = get('theme-select'); + +if (select) { + select.addEventListener('change', function() { + applyTheme(this.value); + }); +} +} + + +function draw() { +ctx.save(); +ctx.lineWidth = 1; +ctx.translate(0.5, 0.5); // for crisp 1px black lines +drawCourt(); +drawNext(); +drawScore(); +drawRows(); +ctx.restore(); +} + +function drawCourt() { +if (invalid.court) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + if (playing) + drawPiece(ctx, current.type, current.x, current.y, current.dir); + var x, y, block; + for(y = 0 ; y < ny ; y++) { + for (x = 0 ; x < nx ; x++) { + if (block = getBlock(x,y)) + drawBlock(ctx, x, y, getPieceColor(block)); } - - //------------------------------------------------------------------------- - // FINALLY, lets run the game - //------------------------------------------------------------------------- - - run(); - - + } + ctx.strokeRect(0, 0, nx*dx - 1, ny*dy - 1); // court boundary + invalid.court = false; +} +} + +function drawNext() { +if (invalid.next) { + var padding = (nu - next.type.size) / 2; // half-arsed attempt at centering next piece display + uctx.save(); + uctx.translate(0.5, 0.5); + uctx.clearRect(0, 0, nu*dx, nu*dy); + drawPiece(uctx, next.type, padding, padding, next.dir); + uctx.strokeStyle = 'black'; + uctx.strokeRect(0, 0, nu*dx - 1, nu*dy - 1); + uctx.restore(); + invalid.next = false; +} +} + +function drawScore() { +if (invalid.score) { + html('score', ("00000" + Math.floor(vscore)).slice(-5)); + invalid.score = false; +} +} + +function drawRows() { +if (invalid.rows) { + html('rows', rows); + invalid.rows = false; +} +} + +function drawPiece(ctx, type, x, y, dir) { +eachblock(type, x, y, dir, function(x, y) { + drawBlock(ctx, x, y, getPieceColor(type)); +}); +} + +function drawBlock(ctx, x, y, color) { +ctx.fillStyle = color; +ctx.fillRect(x*dx, y*dy, dx, dy); +ctx.strokeRect(x*dx, y*dy, dx, dy) +} + + +//------------------------------------------------------------------------- +// FINALLY, lets run the game +//------------------------------------------------------------------------- + +initializeTheme(); +run(); \ No newline at end of file diff --git a/styles.css b/styles.css index 56dd7a5..a8684d4 100644 --- a/styles.css +++ b/styles.css @@ -1,18 +1,141 @@ body { font-family: Helvetica, sans-serif; } - #tetris { margin: 1em auto; padding: 1em; border: 4px solid black; border-radius: 10px; background-color: #F8F8F8; } - #stats { display: inline-block; vertical-align: top; } - #canvas { display: inline-block; vertical-align: top; background: url(texture.jpg); box-shadow: 10px 10px 10px #999; border: 2px solid #333; } - #menu { display: inline-block; vertical-align: top; position: relative; } - #menu p { margin: 0.5em 0; text-align: center; } - #menu p a { text-decoration: none; color: black; } - #upcoming { display: block; margin: 0 auto; background-color: #E0E0E0; } - #score { color: blue; font-weight: bold; vertical-align: middle; } - #rows { color: blue; font-weight: bold; vertical-align: middle; } - #stats { position: absolute; bottom: 0em; right: 1em; } - @media screen and (min-width: 0px) and (min-height: 0px) { #tetris { font-size: 0.75em; width: 250px; } #menu { width: 100px; height: 200px; } #upcoming { width: 50px; height: 50px; } #canvas { width: 100px; height: 200px; } } /* 10px chunks */ - @media screen and (min-width: 400px) and (min-height: 400px) { #tetris { font-size: 1.00em; width: 350px; } #menu { width: 150px; height: 300px; } #upcoming { width: 75px; height: 75px; } #canvas { width: 150px; height: 300px; } } /* 15px chunks */ - @media screen and (min-width: 500px) and (min-height: 500px) { #tetris { font-size: 1.25em; width: 450px; } #menu { width: 200px; height: 400px; } #upcoming { width: 100px; height: 100px; } #canvas { width: 200px; height: 400px; } } /* 20px chunks */ - @media screen and (min-width: 600px) and (min-height: 600px) { #tetris { font-size: 1.50em; width: 550px; } #menu { width: 250px; height: 500px; } #upcoming { width: 125px; height: 125px; } #canvas { width: 250px; height: 500px; } } /* 25px chunks */ - @media screen and (min-width: 700px) and (min-height: 700px) { #tetris { font-size: 1.75em; width: 650px; } #menu { width: 300px; height: 600px; } #upcoming { width: 150px; height: 150px; } #canvas { width: 300px; height: 600px; } } /* 30px chunks */ - @media screen and (min-width: 800px) and (min-height: 800px) { #tetris { font-size: 2.00em; width: 750px; } #menu { width: 350px; height: 700px; } #upcoming { width: 175px; height: 175px; } #canvas { width: 350px; height: 700px; } } /* 35px chunks */ - @media screen and (min-width: 900px) and (min-height: 900px) { #tetris { font-size: 2.25em; width: 850px; } #menu { width: 400px; height: 800px; } #upcoming { width: 200px; height: 200px; } #canvas { width: 400px; height: 800px; } } /* 40px chunks */ +#tetris { margin: 1em auto; padding: 1em; border: 4px solid black; border-radius: 10px; background-color: #F8F8F8; } +#stats { display: inline-block; vertical-align: top; } +#canvas { display: inline-block; vertical-align: top; background: url(texture.jpg); box-shadow: 10px 10px 10px #999; border: 2px solid #333; } +#menu { display: inline-block; vertical-align: top; position: relative; } +#menu p { margin: 0.5em 0; text-align: center; } +#menu p a { text-decoration: none; color: black; } +#upcoming { display: block; margin: 0 auto; background-color: #E0E0E0; } +#score { color: blue; font-weight: bold; vertical-align: middle; } +#rows { color: blue; font-weight: bold; vertical-align: middle; } +#stats { position: absolute; bottom: 0em; right: 1em; } + + +/* ============================= */ +/* SELETOR DE TEMAS */ +/* ============================= */ + +#theme-container { + margin: 0.8em 0; + text-align: center; +} + +#theme-container label { + display: block; + margin-bottom: 0.3em; + font-weight: bold; +} + +#theme-select { + padding: 0.3em; + border: 2px solid #333; + border-radius: 5px; + background-color: white; + color: black; + cursor: pointer; +} + + +/* ============================= */ +/* TEMAS VISUAIS */ +/* ============================= */ + +/* Tema Clássico */ +body.theme-classic #tetris { + background-color: #F8F8F8; + border-color: black; +} + +body.theme-classic #theme-select { + background-color: white; + color: black; +} + + +/* Tema Oceano */ +body.theme-ocean #tetris { + background-color: #E3F2FD; + border-color: #0277BD; +} + +body.theme-ocean #theme-select { + background-color: #E1F5FE; + color: #01579B; + border-color: #0277BD; +} + +body.theme-ocean #menu p a { + color: #01579B; +} + +body.theme-ocean #score, +body.theme-ocean #rows { + color: #0277BD; +} + + +/* Tema Vermelho */ +body.theme-red #tetris { + background-color: #FFEBEE; + border-color: #B71C1C; +} + +body.theme-red #theme-select { + background-color: #FFCDD2; + color: #B71C1C; + border-color: #B71C1C; +} + +body.theme-red #menu p a { + color: #B71C1C; +} + +body.theme-red #score, +body.theme-red #rows { + color: #D32F2F; +} + + +/* Tema Neon */ +body.theme-neon #tetris { + background-color: #111111; + border-color: #00FFFF; +} + +body.theme-neon #theme-select { + background-color: #222222; + color: #00FFFF; + border-color: #00FFFF; +} + +body.theme-neon #menu p a { + color: #00FFFF; +} + +body.theme-neon #score, +body.theme-neon #rows { + color: #00FFFF; +} + +body.theme-neon #canvas { + border-color: #00FFFF; +} + + +/* ============================= */ +/* RESPONSIVIDADE ORIGINAL */ +/* ============================= */ + +@media screen and (min-width: 0px) and (min-height: 0px) { #tetris { font-size: 0.75em; width: 250px; } #menu { width: 100px; height: 200px; } #upcoming { width: 50px; height: 50px; } #canvas { width: 100px; height: 200px; } } /* 10px chunks */ + +@media screen and (min-width: 400px) and (min-height: 400px) { #tetris { font-size: 1.00em; width: 350px; } #menu { width: 150px; height: 300px; } #upcoming { width: 75px; height: 75px; } #canvas { width: 150px; height: 300px; } } /* 15px chunks */ + +@media screen and (min-width: 500px) and (min-height: 500px) { #tetris { font-size: 1.25em; width: 450px; } #menu { width: 200px; height: 400px; } #upcoming { width: 100px; height: 100px; } #canvas { width: 200px; height: 400px; } } /* 20px chunks */ + +@media screen and (min-width: 600px) and (min-height: 600px) { #tetris { font-size: 1.50em; width: 550px; } #menu { width: 250px; height: 500px; } #upcoming { width: 125px; height: 125px; } #canvas { width: 250px; height: 500px; } } /* 25px chunks */ + +@media screen and (min-width: 700px) and (min-height: 700px) { #tetris { font-size: 1.75em; width: 650px; } #menu { width: 300px; height: 600px; } #upcoming { width: 150px; height: 150px; } #canvas { width: 300px; height: 600px; } } /* 30px chunks */ + +@media screen and (min-width: 800px) and (min-height: 800px) { #tetris { font-size: 2.00em; width: 750px; } #menu { width: 350px; height: 700px; } #upcoming { width: 175px; height: 175px; } #canvas { width: 350px; height: 700px; } } /* 35px chunks */ + +@media screen and (min-width: 900px) and (min-height: 900px) { #tetris { font-size: 2.25em; width: 850px; } #menu { width: 400px; height: 800px; } #upcoming { width: 200px; height: 200px; } #canvas { width: 400px; height: 800px; } } /* 40px chunks */ \ No newline at end of file From a1f7fea29ffb7b7565c243839b00fbcb9117ef66 Mon Sep 17 00:00:00 2001 From: IanKilwiny Date: Thu, 8 Oct 2026 14:05:49 -0300 Subject: [PATCH 04/19] feat:adicionando tela de game-over --- index.html | 7 +++++++ script.js | 7 ++++++- styles.css | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 5b06c65..ce972f4 100644 --- a/index.html +++ b/index.html @@ -18,6 +18,13 @@ + + diff --git a/script.js b/script.js index 9a9e578..d9fedbd 100644 --- a/script.js +++ b/script.js @@ -238,6 +238,9 @@ var Stats = function () { function addEvents() { document.addEventListener('keydown', keydown, false); window.addEventListener('resize', resize, false); + get('game-over-restart').addEventListener('click', function() { + window.location.reload(); + }); } function resize(event) { @@ -253,6 +256,8 @@ var Stats = function () { function keydown(ev) { var handled = false; + if (!get('game-over').hidden) + return; if (playing) { switch(ev.keyCode) { case KEY.LEFT: actions.push(DIR.LEFT); handled = true; break; @@ -283,7 +288,7 @@ var Stats = function () { function play() { hide('start'); reset(); paused = false; playing = true; } function pause() {show('start'); paused = true; playing = false;} function restart() {hide('start'); paused = false; playing = true;} - function lose() { show('start'); setVisualScore(); playing = false; } + function lose() { hide('start'); get('game-over').hidden = false; setVisualScore(); playing = false; } function setVisualScore(n) { vscore = n || score; invalidateScore(); } function setScore(n) { score = n; setVisualScore(n); } diff --git a/styles.css b/styles.css index 56dd7a5..5e9d8f6 100644 --- a/styles.css +++ b/styles.css @@ -9,6 +9,12 @@ body { font-family: Helvetica, sans-serif; } #score { color: blue; font-weight: bold; vertical-align: middle; } #rows { color: blue; font-weight: bold; vertical-align: middle; } #stats { position: absolute; bottom: 0em; right: 1em; } + #game-over { position: fixed; inset: 0; z-index: 10002; display: flex; align-items: center; justify-content: center; padding: 1em; background: rgba(0, 0, 0, 0.72); } + #game-over[hidden] { display: none; } + .game-over-content { min-width: 240px; padding: 2em; border: 3px solid #222; border-radius: 8px; background: #F8F8F8; text-align: center; box-shadow: 0 12px 36px rgba(0, 0, 0, 0.35); } + .game-over-content h1 { margin: 0 0 1em; color: #c62828; } + #game-over-restart { padding: 0.7em 1.2em; border: 0; border-radius: 4px; background: #222; color: white; font: inherit; cursor: pointer; } + #game-over-restart:hover { background: #444; } @media screen and (min-width: 0px) and (min-height: 0px) { #tetris { font-size: 0.75em; width: 250px; } #menu { width: 100px; height: 200px; } #upcoming { width: 50px; height: 50px; } #canvas { width: 100px; height: 200px; } } /* 10px chunks */ @media screen and (min-width: 400px) and (min-height: 400px) { #tetris { font-size: 1.00em; width: 350px; } #menu { width: 150px; height: 300px; } #upcoming { width: 75px; height: 75px; } #canvas { width: 150px; height: 300px; } } /* 15px chunks */ @media screen and (min-width: 500px) and (min-height: 500px) { #tetris { font-size: 1.25em; width: 450px; } #menu { width: 200px; height: 400px; } #upcoming { width: 100px; height: 100px; } #canvas { width: 200px; height: 400px; } } /* 20px chunks */ From 57b8a449ad096a7f30f6e9e1933e5541a0120162 Mon Sep 17 00:00:00 2001 From: Fidelixjv Date: Thu, 8 Oct 2026 14:07:37 -0300 Subject: [PATCH 05/19] adequando o tamanho dos botoes --- styles.css | 1 + 1 file changed, 1 insertion(+) diff --git a/styles.css b/styles.css index a8684d4..fc71c65 100644 --- a/styles.css +++ b/styles.css @@ -24,6 +24,7 @@ body { font-family: Helvetica, sans-serif; } display: block; margin-bottom: 0.3em; font-weight: bold; + font-size: 0.6em; } #theme-select { From 25b6adbc6f0fd0b49be72552fb75f1b372f5a294 Mon Sep 17 00:00:00 2001 From: IanKilwiny Date: Thu, 8 Oct 2026 14:23:19 -0300 Subject: [PATCH 06/19] refactor:adicionando score e rows no popup --- index.html | 3 +++ script.js | 24 +++++++++++++++++++++++- styles.css | 8 ++++++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index ce972f4..190b471 100644 --- a/index.html +++ b/index.html @@ -21,6 +21,9 @@ diff --git a/script.js b/script.js index d9fedbd..057421f 100644 --- a/script.js +++ b/script.js @@ -288,7 +288,29 @@ var Stats = function () { function play() { hide('start'); reset(); paused = false; playing = true; } function pause() {show('start'); paused = true; playing = false;} function restart() {hide('start'); paused = false; playing = true;} - function lose() { hide('start'); get('game-over').hidden = false; setVisualScore(); playing = false; } + function lose() { + hide('start'); + setVisualScore(); + html('game-over-score', ("00000" + Math.floor(score)).slice(-5)); + html('game-over-rows', rows); + drawGameOverPiece(); + get('game-over').hidden = false; + playing = false; + } + + function drawGameOverPiece() { + var pieceCanvas = get('game-over-piece'); + var pieceContext; + var padding = (nu - current.type.size) / 2; + pieceCanvas.width = nu * dx; + pieceCanvas.height = nu * dy; + pieceContext = pieceCanvas.getContext('2d'); + pieceContext.save(); + pieceContext.lineWidth = 1; + pieceContext.translate(0.5, 0.5); + drawPiece(pieceContext, current.type, padding, padding, current.dir); + pieceContext.restore(); + } function setVisualScore(n) { vscore = n || score; invalidateScore(); } function setScore(n) { score = n; setVisualScore(n); } diff --git a/styles.css b/styles.css index 5e9d8f6..2b1eb66 100644 --- a/styles.css +++ b/styles.css @@ -11,8 +11,12 @@ body { font-family: Helvetica, sans-serif; } #stats { position: absolute; bottom: 0em; right: 1em; } #game-over { position: fixed; inset: 0; z-index: 10002; display: flex; align-items: center; justify-content: center; padding: 1em; background: rgba(0, 0, 0, 0.72); } #game-over[hidden] { display: none; } - .game-over-content { min-width: 240px; padding: 2em; border: 3px solid #222; border-radius: 8px; background: #F8F8F8; text-align: center; box-shadow: 0 12px 36px rgba(0, 0, 0, 0.35); } - .game-over-content h1 { margin: 0 0 1em; color: #c62828; } + .game-over-content { display: grid; justify-items: center; gap: 1em; min-width: 240px; padding: 2em; border: 3px solid #222; border-radius: 8px; background: #F8F8F8; text-align: center; box-shadow: 0 12px 36px rgba(0, 0, 0, 0.35); } + .game-over-content h1 { margin: 0; color: #c62828; } + #game-over-piece { width: 100px; height: 100px; border: 1px solid #333; background: #E0E0E0; } + .game-over-final-score, .game-over-final-rows { margin: 0; font-size: 1.1em; } + #game-over-score { color: blue; font-size: 1.25em; } + #game-over-rows { color: #16833c; font-size: 1.25em; } #game-over-restart { padding: 0.7em 1.2em; border: 0; border-radius: 4px; background: #222; color: white; font: inherit; cursor: pointer; } #game-over-restart:hover { background: #444; } @media screen and (min-width: 0px) and (min-height: 0px) { #tetris { font-size: 0.75em; width: 250px; } #menu { width: 100px; height: 200px; } #upcoming { width: 50px; height: 50px; } #canvas { width: 100px; height: 200px; } } /* 10px chunks */ From 720eb3b1e6883e7e667ac496c01ca029771100f9 Mon Sep 17 00:00:00 2001 From: Fidelixjv Date: Thu, 8 Oct 2026 14:27:59 -0300 Subject: [PATCH 07/19] =?UTF-8?q?ajustando=20cores=20dos=20bot=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script.js | 1131 +++++++++++++++++++++++++++++++++------------------- styles.css | 15 +- 2 files changed, 738 insertions(+), 408 deletions(-) diff --git a/script.js b/script.js index 6212082..b547472 100644 --- a/script.js +++ b/script.js @@ -1,481 +1,693 @@ // stats.js r6 - http://github.com/mrdoob/stats.js var Stats = function () { function s(a, g, d) { var f, c, e; for (c = 0; c < 30; c++)for (f = 0; f < 73; f++)e = (f + c * 74) * 4, a[e] = a[e + 4], a[e + 1] = a[e + 5], a[e + 2] = a[e + 6]; for (c = 0; c < 30; c++)e = (73 + c * 74) * 4, c < g ? (a[e] = b[d].bg.r, a[e + 1] = b[d].bg.g, a[e + 2] = b[d].bg.b) : (a[e] = b[d].fg.r, a[e + 1] = b[d].fg.g, a[e + 2] = b[d].fg.b) } var r = 0, t = 2, g, u = 0, j = (new Date).getTime(), F = j, v = j, l = 0, w = 1E3, x = 0, k, d, a, m, y, n = 0, z = 1E3, A = 0, f, c, o, B, p = 0, C = 1E3, D = 0, h, i, q, E, b = { - fps: { bg: { r: 16, g: 16, b: 48 }, fg: { r: 0, g: 255, b: 255 } }, ms: { bg: { r: 16, g: 48, b: 16 }, fg: { r: 0, g: 255, b: 0 } }, mb: { - bg: { - r: 48, g: 16, - b: 26 - }, fg: { r: 255, g: 0, b: 128 } - } - }; g = document.createElement("div"); - g.style.cursor = "pointer"; - g.style.width = "80px"; - g.style.opacity = "0.9"; - g.style.zIndex = "10001"; - g.addEventListener("click", function () { r++; r == t && (r = 0); - k.style.display = "none"; - f.style.display = "none"; - h.style.display = "none"; - switch (r) { case 0: k.style.display = "block"; - break; case 1: f.style.display = "block"; - break; case 2: h.style.display = "block" } }, !1); - k = document.createElement("div"); - k.style.backgroundColor = "rgb(" + Math.floor(b.fps.bg.r / 2) + "," + Math.floor(b.fps.bg.g / - 2) + "," + Math.floor(b.fps.bg.b / 2) + ")"; k.style.padding = "2px 0px 3px 0px"; - g.appendChild(k); - d = document.createElement("div"); - d.style.fontFamily = "Helvetica, Arial, sans-serif"; - d.style.textAlign = "left"; - d.style.fontSize = "9px"; - d.style.color = "rgb(" + b.fps.fg.r + "," + b.fps.fg.g + "," + b.fps.fg.b + ")"; - d.style.margin = "0px 0px 1px 3px"; d.innerHTML = 'FPS'; - k.appendChild(d); - a = document.createElement("canvas"); - a.width = 74; - a.height = 30; - a.style.display = "block"; - a.style.marginLeft = "3px"; - k.appendChild(a); + fps: { bg: { r: 16, g: 16, b: 48 }, fg: { r: 0, g: 255, b: 255 } }, ms: { bg: { r: 16, g: 48, b: 16 }, fg: { r: 0, g: 255, b: 0 } }, mb: { + bg: { + r: 48, g: 16, + b: 26 + }, fg: { r: 255, g: 0, b: 128 } + } + }; g = document.createElement("div"); + g.style.cursor = "pointer"; + g.style.width = "80px"; + g.style.opacity = "0.9"; + g.style.zIndex = "10001"; + g.addEventListener("click", function () { + r++; r == t && (r = 0); + k.style.display = "none"; + f.style.display = "none"; + h.style.display = "none"; + switch (r) { + case 0: k.style.display = "block"; + break; + case 1: f.style.display = "block"; + break; + case 2: h.style.display = "block" + } + }, !1); + k = document.createElement("div"); + k.style.backgroundColor = "rgb(" + Math.floor(b.fps.bg.r / 2) + "," + Math.floor(b.fps.bg.g / + 2) + "," + Math.floor(b.fps.bg.b / 2) + ")"; k.style.padding = "2px 0px 3px 0px"; + g.appendChild(k); + d = document.createElement("div"); + d.style.fontFamily = "Helvetica, Arial, sans-serif"; + d.style.textAlign = "left"; + d.style.fontSize = "9px"; + d.style.color = "rgb(" + b.fps.fg.r + "," + b.fps.fg.g + "," + b.fps.fg.b + ")"; + d.style.margin = "0px 0px 1px 3px"; d.innerHTML = 'FPS'; + k.appendChild(d); + a = document.createElement("canvas"); + a.width = 74; + a.height = 30; + a.style.display = "block"; + a.style.marginLeft = "3px"; + k.appendChild(a); m = a.getContext("2d"); - m.fillStyle = "rgb(" + b.fps.bg.r + "," + b.fps.bg.g + "," + b.fps.bg.b + ")"; - m.fillRect(0, 0, a.width, a.height); - y = m.getImageData(0, 0, a.width, a.height); - f = document.createElement("div"); - f.style.backgroundColor = "rgb(" + Math.floor(b.ms.bg.r / 2) + "," + Math.floor(b.ms.bg.g / 2) + "," + Math.floor(b.ms.bg.b / 2) + ")"; - f.style.padding = "2px 0px 3px 0px"; f.style.display = "none"; - g.appendChild(f); c = document.createElement("div"); - c.style.fontFamily = "Helvetica, Arial, sans-serif"; - c.style.textAlign = "left"; c.style.fontSize = "9px"; - c.style.color = "rgb(" + b.ms.fg.r + "," + b.ms.fg.g + "," + b.ms.fg.b + ")"; - c.style.margin = "0px 0px 1px 3px"; c.innerHTML = 'MS'; - f.appendChild(c); a = document.createElement("canvas"); - a.width = 74; a.height = 30; a.style.display = "block"; a.style.marginLeft = "3px"; f.appendChild(a); - o = a.getContext("2d"); o.fillStyle = "rgb(" + b.ms.bg.r + "," + b.ms.bg.g + "," + b.ms.bg.b + ")"; - o.fillRect(0, 0, a.width, a.height); B = o.getImageData(0, 0, a.width, a.height); try { - performance && performance.memory && performance.memory.totalJSHeapSize && (t = 3) - } catch (G) { } h = document.createElement("div"); h.style.backgroundColor = "rgb(" + Math.floor(b.mb.bg.r / 2) + "," + Math.floor(b.mb.bg.g / 2) + "," + Math.floor(b.mb.bg.b / 2) + ")"; - h.style.padding = "2px 0px 3px 0px"; h.style.display = "none"; - g.appendChild(h); - i = document.createElement("div"); i.style.fontFamily = "Helvetica, Arial, sans-serif"; i.style.textAlign = "left"; i.style.fontSize = "9px"; i.style.color = "rgb(" + b.mb.fg.r + "," + b.mb.fg.g + "," + b.mb.fg.b + ")"; - i.style.margin = "0px 0px 1px 3px"; i.innerHTML = 'MB'; - h.appendChild(i); - a = document.createElement("canvas"); - a.width = 74; a.height = 30; a.style.display = "block"; a.style.marginLeft = "3px"; h.appendChild(a); - q = a.getContext("2d"); q.fillStyle = "#301010"; q.fillRect(0, 0, a.width, a.height); - E = q.getImageData(0, 0, a.width, a.height); return { - domElement: g, update: function () { - u++; j = (new Date).getTime(); n = j - F; z = Math.min(z, n); A = Math.max(A, n); s(B.data, Math.min(30, 30 - n / 200 * 30), "ms"); c.innerHTML = '' + n + " MS (" + z + "-" + A + ")"; - o.putImageData(B, 0, 0); - F = j; if (j > v + 1E3) { l = Math.round(u * 1E3 / (j - v)); w = Math.min(w, l); - x = Math.max(x, l); - s(y.data, Math.min(30, 30 - l / 100 * 30), "fps"); - d.innerHTML = '' + l + " FPS (" + w + "-" + x + ")"; - m.putImageData(y, 0, 0); if (t == 3) p = performance.memory.usedJSHeapSize * 9.54E-7, C = Math.min(C, p), D = Math.max(D, p), s(E.data, Math.min(30, 30 - p / 2), "mb"), i.innerHTML = '' + Math.round(p) + " MB (" + Math.round(C) + "-" + Math.round(D) + ")", q.putImageData(E, 0, 0); v = j; - u = 0 } + m.fillStyle = "rgb(" + b.fps.bg.r + "," + b.fps.bg.g + "," + b.fps.bg.b + ")"; + m.fillRect(0, 0, a.width, a.height); + y = m.getImageData(0, 0, a.width, a.height); + f = document.createElement("div"); + f.style.backgroundColor = "rgb(" + Math.floor(b.ms.bg.r / 2) + "," + Math.floor(b.ms.bg.g / 2) + "," + Math.floor(b.ms.bg.b / 2) + ")"; + f.style.padding = "2px 0px 3px 0px"; f.style.display = "none"; + g.appendChild(f); + c = document.createElement("div"); + c.style.fontFamily = "Helvetica, Arial, sans-serif"; + c.style.textAlign = "left"; + c.style.fontSize = "9px"; + c.style.color = "rgb(" + b.ms.fg.r + "," + b.ms.fg.g + "," + b.ms.fg.b + ")"; + c.style.margin = "0px 0px 1px 3px"; c.innerHTML = 'MS'; + f.appendChild(c); + a = document.createElement("canvas"); + a.width = 74; + a.height = 30; + a.style.display = "block"; + a.style.marginLeft = "3px"; + f.appendChild(a); + o = a.getContext("2d"); + o.fillStyle = "rgb(" + b.ms.bg.r + "," + b.ms.bg.g + "," + b.ms.bg.b + ")"; + o.fillRect(0, 0, a.width, a.height); + B = o.getImageData(0, 0, a.width, a.height); + try { + performance && performance.memory && performance.memory.totalJSHeapSize && (t = 3) + } catch (G) { } + h = document.createElement("div"); + h.style.backgroundColor = "rgb(" + Math.floor(b.mb.bg.r / 2) + "," + Math.floor(b.mb.bg.g / 2) + "," + Math.floor(b.mb.bg.b / 2) + ")"; + h.style.padding = "2px 0px 3px 0px"; + h.style.display = "none"; + g.appendChild(h); + i = document.createElement("div"); + i.style.fontFamily = "Helvetica, Arial, sans-serif"; + i.style.textAlign = "left"; + i.style.fontSize = "9px"; + i.style.color = "rgb(" + b.mb.fg.r + "," + b.mb.fg.g + "," + b.mb.fg.b + ")"; + i.style.margin = "0px 0px 1px 3px"; + i.innerHTML = 'MB'; + h.appendChild(i); + a = document.createElement("canvas"); + a.width = 74; + a.height = 30; + a.style.display = "block"; + a.style.marginLeft = "3px"; + h.appendChild(a); + q = a.getContext("2d"); + q.fillStyle = "#301010"; + q.fillRect(0, 0, a.width, a.height); + E = q.getImageData(0, 0, a.width, a.height); + return { + domElement: g, update: function () { + u++; + j = (new Date).getTime(); + n = j - F; + z = Math.min(z, n); + A = Math.max(A, n); + s(B.data, Math.min(30, 30 - n / 200 * 30), "ms"); + c.innerHTML = '' + n + " MS (" + z + "-" + A + ")"; + o.putImageData(B, 0, 0); + F = j; + if (j > v + 1E3) { + l = Math.round(u * 1E3 / (j - v)); + w = Math.min(w, l); + x = Math.max(x, l); + s(y.data, Math.min(30, 30 - l / 100 * 30), "fps"); + d.innerHTML = '' + l + " FPS (" + w + "-" + x + ")"; + m.putImageData(y, 0, 0); + if (t == 3) + p = performance.memory.usedJSHeapSize * 9.54E-7, + C = Math.min(C, p), + D = Math.max(D, p), + s(E.data, Math.min(30, 30 - p / 2), "mb"), + i.innerHTML = '' + Math.round(p) + " MB (" + Math.round(C) + "-" + Math.round(D) + ")", + q.putImageData(E, 0, 0); + v = j; + u = 0 } + } } }; - - //------------------------------------------------------------------------- // base helper methods //------------------------------------------------------------------------- -function get(id) { return document.getElementById(id); } +function get(id) { return document.getElementById(id); } function hide(id) { get(id).style.visibility = 'hidden'; } -function show(id) { get(id).style.visibility = null; } -function html(id, html) { get(id).innerHTML = html; } - -function timestamp() { return new Date().getTime(); } -function random(min, max) { return (min + (Math.random() * (max - min))); } -function randomChoice(choices) { return choices[Math.round(random(0, choices.length-1))]; } - -if (!window.requestAnimationFrame) { // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ -window.requestAnimationFrame = window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function(callback, element) { - window.setTimeout(callback, 1000 / 60); - } +function show(id) { get(id).style.visibility = null; } +function html(id, html) { get(id).innerHTML = html; } +function timestamp() { return new Date().getTime(); } +function random(min, max) { return (min + (Math.random() * (max - min))); } +function randomChoice(choices) { return choices[Math.round(random(0, choices.length - 1))]; } + +if (!window.requestAnimationFrame) { + window.requestAnimationFrame = window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback, element) { + window.setTimeout(callback, 1000 / 60); + } } //------------------------------------------------------------------------- // game constants //------------------------------------------------------------------------- -var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 }, - DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, MIN: 0, MAX: 3 }, - stats = new Stats(), - canvas = get('canvas'), - ctx = canvas.getContext('2d'), +var KEY = { + ESC: 27, + SPACE: 32, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40 + }, + DIR = { + UP: 0, + RIGHT: 1, + DOWN: 2, + LEFT: 3, + MIN: 0, + MAX: 3 + }, + stats = new Stats(), + canvas = get('canvas'), + ctx = canvas.getContext('2d'), ucanvas = get('upcoming'), - uctx = ucanvas.getContext('2d'), - speed = { start: 0.6, decrement: 0.005, min: 0.1 }, // how long before piece drops by 1 row (seconds) - nx = 10, // width of tetris court (in blocks) - ny = 20, // height of tetris court (in blocks) - nu = 5; // width/height of upcoming preview (in blocks) + uctx = ucanvas.getContext('2d'), + speed = { + start: 0.6, + decrement: 0.005, + min: 0.1 + }, + nx = 10, + ny = 20, + nu = 5; //------------------------------------------------------------------------- // game variables (initialized during reset) //------------------------------------------------------------------------- -var dx, dy, // pixel size of a single tetris block - blocks, // 2 dimensional array (nx*ny) representing tetris court - either empty block or occupied by a 'piece' - actions, // queue of user actions (inputs) - playing, // true|false - game is in progress - paused, // true|false - game is currently paued (to differentiate need for reset) - dt, // time since starting this game - current, // the current piece - next, // the next piece - score, // the current score - vscore, // the currently displayed score (it catches up to score in small chunks - like a spinning slot machine) - rows, // number of completed rows in the current game - step; // how long before current piece drops by 1 row +var dx, dy, + blocks, + actions, + playing, + paused, + dt, + current, + next, + score, + vscore, + rows, + step; //------------------------------------------------------------------------- // tetris pieces -// -// blocks: each element represents a rotation of the piece (0, 90, 180, 270) -// each element is a 16 bit integer where the 16 bits represent -// a 4x4 set of blocks, e.g. j.blocks[0] = 0x44C0 -// -// 0100 = 0x4 << 3 = 0x4000 -// 0100 = 0x4 << 2 = 0x0400 -// 1100 = 0xC << 1 = 0x00C0 -// 0000 = 0x0 << 0 = 0x0000 -// ------ -// 0x44C0 -// //------------------------------------------------------------------------- -var i = { id: 'i', size: 4, blocks: [0x0F00, 0x2222, 0x00F0, 0x4444], color: 'purple' }; -var j = { id: 'j', size: 3, blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20], color: 'pink' }; -var l = { id: 'l', size: 3, blocks: [0x4460, 0x0E80, 0xC440, 0x2E00], color: 'salmon' }; -var o = { id: 'o', size: 2, blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00], color: 'lime' }; -var s = { id: 's', size: 3, blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], color: 'teal' }; -var t = { id: 't', size: 3, blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], color: 'coral' }; -var z = { id: 'z', size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'olive' }; +var i = { + id: 'i', + size: 4, + blocks: [0x0F00, 0x2222, 0x00F0, 0x4444], + color: 'purple' +}; + +var j = { + id: 'j', + size: 3, + blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20], + color: 'pink' +}; +var l = { + id: 'l', + size: 3, + blocks: [0x4460, 0x0E80, 0xC440, 0x2E00], + color: 'salmon' +}; + +var o = { + id: 'o', + size: 2, + blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00], + color: 'lime' +}; + +var s = { + id: 's', + size: 3, + blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], + color: 'teal' +}; + +var t = { + id: 't', + size: 3, + blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], + color: 'coral' +}; + +var z = { + id: 'z', + size: 3, + blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], + color: 'olive' +}; //------------------------------------------------------------------------- // TEMAS VISUAIS //------------------------------------------------------------------------- var THEMES = { -classic: { - className: 'theme-classic', - pieces: { - i: '#8A2BE2', - j: '#FF69B4', - l: '#FA8072', - o: '#32CD32', - s: '#008080', - t: '#FF7F50', - z: '#808000' - } -}, - -ocean: { - className: 'theme-ocean', - pieces: { - i: '#00E5FF', - j: '#2979FF', - l: '#00B8D4', - o: '#00E676', - s: '#00ACC1', - t: '#40C4FF', - z: '#1565C0' - } -}, - -red: { - className: 'theme-red', - pieces: { - i: '#FF1744', - j: '#D50000', - l: '#FF5252', - o: '#FF8A65', - s: '#F50057', - t: '#FF3D00', - z: '#B71C1C' - } -}, - -neon: { - className: 'theme-neon', - pieces: { - i: '#00FFFF', - j: '#FF00E6', - l: '#7C4DFF', - o: '#76FF03', - s: '#00FF9D', - t: '#FFEA00', - z: '#FF1744' - } -} -}; - -var currentTheme = 'classic'; + classic: { + className: 'theme-classic' + }, -function getPieceColor(type) { -if (!type || !type.id) - return type ? type.color : '#888888'; + ocean: { + className: 'theme-ocean' + }, -var theme = THEMES[currentTheme]; + red: { + className: 'theme-red' + }, -if (theme && theme.pieces[type.id]) - return theme.pieces[type.id]; - -return type.color; -} + neon: { + className: 'theme-neon' + } +}; +var currentTheme = 'classic'; //------------------------------------------------ // do the bit manipulation and iterate through each // occupied block (x,y) for a given piece //------------------------------------------------ + function eachblock(type, x, y, dir, fn) { -var bit, result, row = 0, col = 0, blocks = type.blocks[dir]; -for(bit = 0x8000 ; bit > 0 ; bit = bit >> 1) { - if (blocks & bit) { - fn(x + col, y + row); - } - if (++col === 4) { - col = 0; - ++row; + var bit, result, row = 0, col = 0, blocks = type.blocks[dir]; + + for (bit = 0x8000; bit > 0; bit = bit >> 1) { + if (blocks & bit) { + fn(x + col, y + row); + } + + if (++col === 4) { + col = 0; + ++row; + } } } -} //----------------------------------------------------- // check if a piece can fit into a position in the grid //----------------------------------------------------- + function occupied(type, x, y, dir) { -var result = false -eachblock(type, x, y, dir, function(x, y) { - if ((x < 0) || (x >= nx) || (y < 0) || (y >= ny) || getBlock(x,y)) - result = true; -}); -return result; + var result = false; + + eachblock(type, x, y, dir, function(x, y) { + if ((x < 0) || (x >= nx) || (y < 0) || (y >= ny) || getBlock(x, y)) + result = true; + }); + + return result; } function unoccupied(type, x, y, dir) { -return !occupied(type, x, y, dir); + return !occupied(type, x, y, dir); } //----------------------------------------- // start with 4 instances of each piece and // pick randomly until the 'bag is empty' //----------------------------------------- + var pieces = []; + function randomPiece() { -if (pieces.length == 0) - pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z]; -var type = pieces.splice(random(0, pieces.length-1), 1)[0]; -return { type: type, dir: DIR.UP, x: Math.round(random(0, nx - type.size)), y: 0 }; + if (pieces.length == 0) + pieces = [ + i, i, i, i, + j, j, j, j, + l, l, l, l, + o, o, o, o, + s, s, s, s, + t, t, t, t, + z, z, z, z + ]; + + var type = pieces.splice(random(0, pieces.length - 1), 1)[0]; + + return { + type: type, + dir: DIR.UP, + x: Math.round(random(0, nx - type.size)), + y: 0 + }; } - //------------------------------------------------------------------------- // GAME LOOP //------------------------------------------------------------------------- function run() { + showStats(); + addEvents(); -showStats(); // initialize FPS counter -addEvents(); // attach keydown and resize events + var last = now = timestamp(); -var last = now = timestamp(); -function frame() { - now = timestamp(); - update(Math.min(1, (now - last) / 1000.0)); // using requestAnimationFrame have to be able to handle large delta's caused when it 'hibernates' in a background or non-visible tab - draw(); - stats.update(); - last = now; - requestAnimationFrame(frame, canvas); -} + function frame() { + now = timestamp(); + + update(Math.min(1, (now - last) / 1000.0)); -resize(); // setup all our sizing information -reset(); // reset the per-game variables -frame(); // start the first frame + draw(); + stats.update(); + + last = now; + + requestAnimationFrame(frame, canvas); + } + + resize(); + reset(); + frame(); } function showStats() { -stats.domElement.id = 'stats'; -get('menu').appendChild(stats.domElement); + stats.domElement.id = 'stats'; + get('menu').appendChild(stats.domElement); } function addEvents() { -document.addEventListener('keydown', keydown, false); -window.addEventListener('resize', resize, false); + document.addEventListener('keydown', keydown, false); + window.addEventListener('resize', resize, false); } function resize(event) { -canvas.width = canvas.clientWidth; // set canvas logical size equal to its physical size -canvas.height = canvas.clientHeight; // (ditto) -ucanvas.width = ucanvas.clientWidth; -ucanvas.height = ucanvas.clientHeight; -dx = canvas.width / nx; // pixel size of a single tetris block -dy = canvas.height / ny; // (ditto) -invalidate(); -invalidateNext(); + canvas.width = canvas.clientWidth; + canvas.height = canvas.clientHeight; + ucanvas.width = ucanvas.clientWidth; + ucanvas.height = ucanvas.clientHeight; + + dx = canvas.width / nx; + dy = canvas.height / ny; + + invalidate(); + invalidateNext(); } function keydown(ev) { -var handled = false; -if (playing) { - switch(ev.keyCode) { - case KEY.LEFT: actions.push(DIR.LEFT); handled = true; break; - case KEY.RIGHT: actions.push(DIR.RIGHT); handled = true; break; - case KEY.UP: actions.push(DIR.UP); handled = true; break; - case KEY.DOWN: actions.push(DIR.DOWN); handled = true; break; - case KEY.ESC: lose(); handled = true; break; - case KEY.SPACE: pause(); handled = true; break; + var handled = false; + + if (playing) { + switch (ev.keyCode) { + case KEY.LEFT: + actions.push(DIR.LEFT); + handled = true; + break; + + case KEY.RIGHT: + actions.push(DIR.RIGHT); + handled = true; + break; + + case KEY.UP: + actions.push(DIR.UP); + handled = true; + break; + + case KEY.DOWN: + actions.push(DIR.DOWN); + handled = true; + break; + + case KEY.ESC: + lose(); + handled = true; + break; + + case KEY.SPACE: + pause(); + handled = true; + break; + } } -} -else if (ev.keyCode == KEY.SPACE) { - if(paused) { + else if (ev.keyCode == KEY.SPACE) { + if (paused) { restart(); handled = true; - }else{ + } + else { play(); handled = true; } -} -if (handled) - ev.preventDefault(); // prevent arrow keys from scrolling the page (supported in IE9+ and all other browsers) + } + + if (handled) + ev.preventDefault(); } //------------------------------------------------------------------------- // GAME LOGIC //------------------------------------------------------------------------- -function play() { hide('start'); reset(); paused = false; playing = true; } -function pause() {show('start'); paused = true; playing = false;} -function restart() {hide('start'); paused = false; playing = true;} -function lose() { show('start'); setVisualScore(); playing = false; } - -function setVisualScore(n) { vscore = n || score; invalidateScore(); } -function setScore(n) { score = n; setVisualScore(n); } -function addScore(n) { score = score + n; } -function clearScore() { setScore(0); } -function clearRows() { setRows(0); } -function setRows(n) { rows = n; step = Math.max(speed.min, speed.start - (speed.decrement*rows)); invalidateRows(); } -function addRows(n) { setRows(rows + n); } -function getBlock(x,y) { return (blocks && blocks[x] ? blocks[x][y] : null); } -function setBlock(x,y,type) { blocks[x] = blocks[x] || []; blocks[x][y] = type; invalidate(); } -function clearBlocks() { blocks = []; invalidate(); } -function clearActions() { actions = []; } -function setCurrentPiece(piece) { current = piece || randomPiece(); invalidate(); } -function setNextPiece(piece) { next = piece || randomPiece(); invalidateNext(); } +function play() { + hide('start'); + reset(); + paused = false; + playing = true; +} -function reset() { -dt = 0; -clearActions(); -clearBlocks(); -clearRows(); -clearScore(); -setCurrentPiece(next); -setNextPiece(); +function pause() { + show('start'); + paused = true; + playing = false; } -function update(idt) { -if (playing) { - if (vscore < score) - setVisualScore(vscore + 1); - handle(actions.shift()); - dt = dt + idt; - if (dt > step) { - dt = dt - step; - drop(); - } +function restart() { + hide('start'); + paused = false; + playing = true; +} + +function lose() { + show('start'); + setVisualScore(); + playing = false; } + +function setVisualScore(n) { + vscore = n || score; + invalidateScore(); } -function handle(action) { -switch(action) { - case DIR.LEFT: move(DIR.LEFT); break; - case DIR.RIGHT: move(DIR.RIGHT); break; - case DIR.UP: rotate(); break; - case DIR.DOWN: drop(); break; +function setScore(n) { + score = n; + setVisualScore(n); } + +function addScore(n) { + score = score + n; } -function move(dir) { -var x = current.x, y = current.y; -switch(dir) { - case DIR.RIGHT: x = x + 1; break; - case DIR.LEFT: x = x - 1; break; - case DIR.DOWN: y = y + 1; break; -} -if (unoccupied(current.type, x, y, current.dir)) { - current.x = x; - current.y = y; +function clearScore() { + setScore(0); +} + +function clearRows() { + setRows(0); +} + +function setRows(n) { + rows = n; + step = Math.max( + speed.min, + speed.start - (speed.decrement * rows) + ); + invalidateRows(); +} + +function addRows(n) { + setRows(rows + n); +} + +function getBlock(x, y) { + return (blocks && blocks[x] ? blocks[x][y] : null); +} + +function setBlock(x, y, type) { + blocks[x] = blocks[x] || []; + blocks[x][y] = type; invalidate(); - return true; } -else { - return false; + +function clearBlocks() { + blocks = []; + invalidate(); } + +function clearActions() { + actions = []; } -function rotate() { -var newdir = (current.dir == DIR.MAX ? DIR.MIN : current.dir + 1); -if (unoccupied(current.type, current.x, current.y, newdir)) { - current.dir = newdir; +function setCurrentPiece(piece) { + current = piece || randomPiece(); invalidate(); } + +function setNextPiece(piece) { + next = piece || randomPiece(); + invalidateNext(); } -function drop() { -if (!move(DIR.DOWN)) { - addScore(10); - dropPiece(); - removeLines(); - setCurrentPiece(next); - setNextPiece(randomPiece()); +function reset() { + dt = 0; + clearActions(); - if (occupied(current.type, current.x, current.y, current.dir)) { - lose(); + clearBlocks(); + clearRows(); + clearScore(); + + setCurrentPiece(next); + setNextPiece(); +} + +function update(idt) { + if (playing) { + if (vscore < score) + setVisualScore(vscore + 1); + + handle(actions.shift()); + + dt = dt + idt; + + if (dt > step) { + dt = dt - step; + drop(); + } } } + +function handle(action) { + switch (action) { + case DIR.LEFT: + move(DIR.LEFT); + break; + + case DIR.RIGHT: + move(DIR.RIGHT); + break; + + case DIR.UP: + rotate(); + break; + + case DIR.DOWN: + drop(); + break; + } } -function dropPiece() { -eachblock(current.type, current.x, current.y, current.dir, function(x, y) { - setBlock(x, y, current.type); -}); +function move(dir) { + var x = current.x, + y = current.y; + + switch (dir) { + case DIR.RIGHT: + x = x + 1; + break; + + case DIR.LEFT: + x = x - 1; + break; + + case DIR.DOWN: + y = y + 1; + break; + } + + if (unoccupied(current.type, x, y, current.dir)) { + current.x = x; + current.y = y; + + invalidate(); + + return true; + } + else { + return false; + } } -function removeLines() { -var x, y, complete, n = 0; -for(y = ny ; y > 0 ; --y) { - complete = true; - for(x = 0 ; x < nx ; ++x) { - if (!getBlock(x, y)) - complete = false; +function rotate() { + var newdir = (current.dir == DIR.MAX ? DIR.MIN : current.dir + 1); + + if (unoccupied(current.type, current.x, current.y, newdir)) { + current.dir = newdir; + invalidate(); } - if (complete) { - removeLine(y); - y = y + 1; // recheck same line - n++; +} + +function drop() { + if (!move(DIR.DOWN)) { + addScore(10); + + dropPiece(); + removeLines(); + + setCurrentPiece(next); + setNextPiece(randomPiece()); + + clearActions(); + + if (occupied(current.type, current.x, current.y, current.dir)) { + lose(); + } } } -if (n > 0) { - addRows(n); - addScore(100*Math.pow(2,n-1)); // 1: 100, 2: 200, 3: 400, 4: 800 + +function dropPiece() { + eachblock( + current.type, + current.x, + current.y, + current.dir, + function(x, y) { + setBlock(x, y, current.type); + } + ); } + +function removeLines() { + var x, y, complete, n = 0; + + for (y = ny; y > 0; --y) { + complete = true; + + for (x = 0; x < nx; ++x) { + if (!getBlock(x, y)) + complete = false; + } + + if (complete) { + removeLine(y); + y = y + 1; + n++; + } + } + + if (n > 0) { + addRows(n); + addScore(100 * Math.pow(2, n - 1)); + } } function removeLine(n) { -var x, y; -for(y = n ; y >= 0 ; --y) { - for(x = 0 ; x < nx ; ++x) - setBlock(x, y, (y == 0) ? null : getBlock(x, y-1)); -} + var x, y; + + for (y = n; y >= 0; --y) { + for (x = 0; x < nx; ++x) + setBlock(x, y, (y == 0) ? null : getBlock(x, y - 1)); + } } //------------------------------------------------------------------------- @@ -484,11 +696,21 @@ for(y = n ; y >= 0 ; --y) { var invalid = {}; -function invalidate() { invalid.court = true; } -function invalidateNext() { invalid.next = true; } -function invalidateScore() { invalid.score = true; } -function invalidateRows() { invalid.rows = true; } +function invalidate() { + invalid.court = true; +} + +function invalidateNext() { + invalid.next = true; +} + +function invalidateScore() { + invalid.score = true; +} +function invalidateRows() { + invalid.rows = true; +} //------------------------------------------------------------------------- // APLICAÇÃO DOS TEMAS @@ -523,91 +745,188 @@ function applyTheme(themeName) { } function initializeTheme() { -var savedTheme = localStorage.getItem('tetris-theme'); + var savedTheme = localStorage.getItem('tetris-theme'); -if (!savedTheme || !THEMES[savedTheme]) - savedTheme = 'classic'; + if (!savedTheme || !THEMES[savedTheme]) + savedTheme = 'classic'; -applyTheme(savedTheme); + currentTheme = savedTheme; -var select = get('theme-select'); + document.body.classList.remove( + 'theme-classic', + 'theme-ocean', + 'theme-red', + 'theme-neon' + ); -if (select) { - select.addEventListener('change', function() { - applyTheme(this.value); - }); -} + document.body.classList.add( + THEMES[savedTheme].className + ); + + var select = get('theme-select'); + + if (select) { + select.value = savedTheme; + + select.addEventListener('change', function() { + applyTheme(this.value); + }); + } } +//------------------------------------------------------------------------- +// DRAW +//------------------------------------------------------------------------- function draw() { -ctx.save(); -ctx.lineWidth = 1; -ctx.translate(0.5, 0.5); // for crisp 1px black lines -drawCourt(); -drawNext(); -drawScore(); -drawRows(); -ctx.restore(); + ctx.save(); + + ctx.lineWidth = 1; + ctx.translate(0.5, 0.5); + + drawCourt(); + drawNext(); + drawScore(); + drawRows(); + + ctx.restore(); } function drawCourt() { -if (invalid.court) { - ctx.clearRect(0, 0, canvas.width, canvas.height); - if (playing) - drawPiece(ctx, current.type, current.x, current.y, current.dir); - var x, y, block; - for(y = 0 ; y < ny ; y++) { - for (x = 0 ; x < nx ; x++) { - if (block = getBlock(x,y)) - drawBlock(ctx, x, y, getPieceColor(block)); + if (invalid.court) { + ctx.clearRect( + 0, + 0, + canvas.width, + canvas.height + ); + + if (playing) + drawPiece( + ctx, + current.type, + current.x, + current.y, + current.dir + ); + + var x, y, block; + + for (y = 0; y < ny; y++) { + for (x = 0; x < nx; x++) { + + if (block = getBlock(x, y)) + drawBlock( + ctx, + x, + y, + block.color + ); + } } + + ctx.strokeRect( + 0, + 0, + nx * dx - 1, + ny * dy - 1 + ); + + invalid.court = false; } - ctx.strokeRect(0, 0, nx*dx - 1, ny*dy - 1); // court boundary - invalid.court = false; -} } function drawNext() { -if (invalid.next) { - var padding = (nu - next.type.size) / 2; // half-arsed attempt at centering next piece display - uctx.save(); - uctx.translate(0.5, 0.5); - uctx.clearRect(0, 0, nu*dx, nu*dy); - drawPiece(uctx, next.type, padding, padding, next.dir); - uctx.strokeStyle = 'black'; - uctx.strokeRect(0, 0, nu*dx - 1, nu*dy - 1); - uctx.restore(); - invalid.next = false; -} + if (invalid.next) { + + var padding = (nu - next.type.size) / 2; + + uctx.save(); + + uctx.translate(0.5, 0.5); + + uctx.clearRect( + 0, + 0, + nu * dx, + nu * dy + ); + + drawPiece( + uctx, + next.type, + padding, + padding, + next.dir + ); + + uctx.strokeStyle = 'black'; + + uctx.strokeRect( + 0, + 0, + nu * dx - 1, + nu * dy - 1 + ); + + uctx.restore(); + + invalid.next = false; + } } function drawScore() { -if (invalid.score) { - html('score', ("00000" + Math.floor(vscore)).slice(-5)); - invalid.score = false; -} + if (invalid.score) { + html( + 'score', + ("00000" + Math.floor(vscore)).slice(-5) + ); + + invalid.score = false; + } } function drawRows() { -if (invalid.rows) { - html('rows', rows); - invalid.rows = false; -} + if (invalid.rows) { + html('rows', rows); + invalid.rows = false; + } } function drawPiece(ctx, type, x, y, dir) { -eachblock(type, x, y, dir, function(x, y) { - drawBlock(ctx, x, y, getPieceColor(type)); -}); + eachblock( + type, + x, + y, + dir, + function(x, y) { + drawBlock( + ctx, + x, + y, + type.color + ); + } + ); } function drawBlock(ctx, x, y, color) { -ctx.fillStyle = color; -ctx.fillRect(x*dx, y*dy, dx, dy); -ctx.strokeRect(x*dx, y*dy, dx, dy) -} + ctx.fillStyle = color; + + ctx.fillRect( + x * dx, + y * dy, + dx, + dy + ); + ctx.strokeRect( + x * dx, + y * dy, + dx, + dy + ); +} //------------------------------------------------------------------------- // FINALLY, lets run the game diff --git a/styles.css b/styles.css index fc71c65..d2f6ecc 100644 --- a/styles.css +++ b/styles.css @@ -109,10 +109,22 @@ body.theme-neon #theme-select { border-color: #00FFFF; } +/* Todos os textos do menu */ +body.theme-neon #menu p { + color: #00FFFF; +} + +/* Botão Press Space to Play */ body.theme-neon #menu p a { color: #00FFFF; } +/* Texto "Tema" */ +body.theme-neon #theme-container label { + color: #00FFFF; +} + +/* Números do Score e Rows */ body.theme-neon #score, body.theme-neon #rows { color: #00FFFF; @@ -122,9 +134,8 @@ body.theme-neon #canvas { border-color: #00FFFF; } - /* ============================= */ -/* RESPONSIVIDADE ORIGINAL */ +/* RESPONSIVIDADE */ /* ============================= */ @media screen and (min-width: 0px) and (min-height: 0px) { #tetris { font-size: 0.75em; width: 250px; } #menu { width: 100px; height: 200px; } #upcoming { width: 50px; height: 50px; } #canvas { width: 100px; height: 200px; } } /* 10px chunks */ From 41eefb8b47e145fbd8338336769687504eaa2200 Mon Sep 17 00:00:00 2001 From: Rian Date: Thu, 8 Oct 2026 14:45:57 -0300 Subject: [PATCH 08/19] =?UTF-8?q?adi=C3=A7=C3=A3o=20de=20pe=C3=A7as=20mk1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/script.js b/script.js index 9a9e578..17f85a4 100644 --- a/script.js +++ b/script.js @@ -158,10 +158,13 @@ var Stats = function () { var s = { size: 3, blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], color: 'teal' }; var t = { size: 3, blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], color: 'coral' }; var z = { size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'olive' }; - + var Plus = { size: 3, blocks: [0x4E40, 0x4E40, 0x4E40, 0x4E40], color: 'orange' }; + var block = { size: 3, blocks: [0xeee0, 0xeee0, 0xeee0, 0xeee0], color: 'green' }; + var block2 = { size: 4, blocks: [0xFfff, 0xFfff, 0xFfff, 0xFfff], color: 'blue' }; + var oo = { size: 4, blocks: [0xCCcc, 0x00ff, 0xCCcc, 0x00ff], color: 'red' }; //------------------------------------------------ // do the bit manipulation and iterate through each - // occupied block (x,y) for a given piece + // occupied block (x,y) for a given piecere //------------------------------------------------ function eachblock(type, x, y, dir, fn) { var bit, result, row = 0, col = 0, blocks = type.blocks[dir]; @@ -199,7 +202,7 @@ var Stats = function () { var pieces = []; function randomPiece() { if (pieces.length == 0) - pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z]; + pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z,Plus,Plus,Plus,Plus,block,block,block,blocks,block2,block2,block2,block2,oo,oo,oo,oo]; var type = pieces.splice(random(0, pieces.length-1), 1)[0]; return { type: type, dir: DIR.UP, x: Math.round(random(0, nx - type.size)), y: 0 }; } From 109265ac7dccd4f7124e0fba042354918b5da238 Mon Sep 17 00:00:00 2001 From: ryanccoelho Date: Thu, 8 Oct 2026 14:52:34 -0300 Subject: [PATCH 09/19] feat: adiciona botao de reiniciar --- index.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 5b06c65..d1a11d7 100644 --- a/index.html +++ b/index.html @@ -1,8 +1,9 @@ + Javascript Tetris - + @@ -12,6 +13,7 @@

score 00000

rows 0

+

Sorry, this example cannot be run because your browser does not support the <canvas> element @@ -19,6 +21,7 @@ - + - + + \ No newline at end of file From dc72ff07b939594b28ac5378697293acf6846994 Mon Sep 17 00:00:00 2001 From: ryanccoelho Date: Tue, 13 Oct 2026 08:46:20 -0300 Subject: [PATCH 10/19] implementa reinicio da partidae estiliza;ao do botao --- index.html | 2 +- styles.css | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index d1a11d7..99aa39b 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,7 @@

score 00000

rows 0

-

+ Sorry, this example cannot be run because your browser does not support the <canvas> element diff --git a/styles.css b/styles.css index 56dd7a5..4e96ea3 100644 --- a/styles.css +++ b/styles.css @@ -9,6 +9,23 @@ body { font-family: Helvetica, sans-serif; } #score { color: blue; font-weight: bold; vertical-align: middle; } #rows { color: blue; font-weight: bold; vertical-align: middle; } #stats { position: absolute; bottom: 0em; right: 1em; } + #restartButton { + background-color: #222; + color: white; + border: 2px solid white; + padding: 10px 20px; + font-size: 16px; + font-weight: bold; + border-radius: 8px; + cursor: pointer; + transition: 0.3s; +} + +#restartButton:hover { + background-color: white; + color: #222; + transform: scale(1.05); +} @media screen and (min-width: 0px) and (min-height: 0px) { #tetris { font-size: 0.75em; width: 250px; } #menu { width: 100px; height: 200px; } #upcoming { width: 50px; height: 50px; } #canvas { width: 100px; height: 200px; } } /* 10px chunks */ @media screen and (min-width: 400px) and (min-height: 400px) { #tetris { font-size: 1.00em; width: 350px; } #menu { width: 150px; height: 300px; } #upcoming { width: 75px; height: 75px; } #canvas { width: 150px; height: 300px; } } /* 15px chunks */ @media screen and (min-width: 500px) and (min-height: 500px) { #tetris { font-size: 1.25em; width: 450px; } #menu { width: 200px; height: 400px; } #upcoming { width: 100px; height: 100px; } #canvas { width: 200px; height: 400px; } } /* 20px chunks */ From 05c2220aa8d873f08d282e79cd51db19b1c7b03e Mon Sep 17 00:00:00 2001 From: "John E. Onias" <119425650+JohnOnias@users.noreply.github.com> Date: Tue, 13 Oct 2026 09:35:32 -0300 Subject: [PATCH 11/19] feat(pause): styles e codigo do modal --- assets/pause.png | Bin 0 -> 11571 bytes index.html | 30 +++++++++------- script.js | 74 +++++++++++++++++++++++++++++++++++---- styles.css | 89 +++++++++++++++++++++++++++++++++-------------- 4 files changed, 149 insertions(+), 44 deletions(-) create mode 100644 assets/pause.png diff --git a/assets/pause.png b/assets/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..cc98006cc5f58f7d9001bfbadeb8b4725f7034a7 GIT binary patch literal 11571 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 bo^lch$MGApeSOeE + Javascript Tetris - + @@ -18,23 +19,28 @@ - - -
-
+
+
+ + + - +
-
- - - + + + \ No newline at end of file diff --git a/script.js b/script.js index 9a9e578..86aa51e 100644 --- a/script.js +++ b/script.js @@ -265,8 +265,7 @@ var Stats = function () { } else if (ev.keyCode == KEY.SPACE) { if(paused) { - restart(); - handled = true; + }else{ play(); handled = true; @@ -279,11 +278,74 @@ var Stats = function () { //------------------------------------------------------------------------- // GAME LOGIC //------------------------------------------------------------------------- + const resume = get('resume'); + +resume.addEventListener('click', function() { + closeGameModal(); + resumeCountdown(); +}); + +function openGameModal() { + hide('start'); + show('container-pause'); + + get('container-pause').style.visibility = 'visible'; + paused = true; + playing = false; +} + +function closeGameModal() { + get('container-pause').style.visibility = 'hidden'; +} + +function resumeCountdown() { + let countdown = 5; - function play() { hide('start'); reset(); paused = false; playing = true; } - function pause() {show('start'); paused = true; playing = false;} - function restart() {hide('start'); paused = false; playing = true;} - function lose() { show('start'); setVisualScore(); playing = false; } + const countdownElement = get('start'); + show('start'); + + countdownElement.textContent = `O jogo vai começar em: ${countdown}`; + + const interval = setInterval(function() { + countdown--; + + countdownElement.textContent = `O jogo vai começar em: ${countdown}`; + + if (countdown === 0) { + clearInterval(interval); + hide('start'); + + paused = false; + playing = true; + } + }, 1000); +} + +function play() { + hide('start'); + reset(); + paused = false; + playing = true; +} + +function pause() { + show('start'); + paused = true; + playing = false; + openGameModal(); +} + +function restart() { + closeGameModal(); + resumeCountdown(); + +} + +function lose() { + show('start'); + setVisualScore(); + playing = false; +} function setVisualScore(n) { vscore = n || score; invalidateScore(); } function setScore(n) { score = n; setVisualScore(n); } diff --git a/styles.css b/styles.css index cd36f3f..7756f7f 100644 --- a/styles.css +++ b/styles.css @@ -227,38 +227,75 @@ body { -#container-pause{ +#container-pause { display: flex; - justify-content: center; + position: fixed; + top: 0; align-items: center; - height: 100%; - width: 100%; - z-index: 1000; -} -#pause { - display: flex; - flex-direction: rom; justify-content: center; - align-items: center; - background-color: #999; - color: #F8F8F8; - height: 350px; - width: 500px; - border-radius: 15px; - + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.2); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + visibility: hidden; +} +.modal-header { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 12px; +} +#pause { + position: relative; + width: 100%; + max-width: 420px; + padding: 32px 24px; + box-sizing: border-box; + + /* Efeito de Vidro Jateado */ + background: rgba(255, 255, 255, 0.65); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + + /* Bordas arredondadas e sombras sutis */ + border-radius: 28px; + border: 1px solid rgba(255, 255, 255, 0.6); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.08); + + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} +#pause-icon { + + width: 30px; + height: 30px; + } #resume { - height: 100px; - width: 200px; - border: 1px solid; - border-radius: 15px; - font-size: 32px; - font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; - box-shadow: 5px 5px 1px black; - + display: inline-flex; + align-items: center; + justify-content: center; + gap: 10px; + + background-color: #6366f1; /* Tom azul/púrpura suave */ + color: #ffffff; + + border: none; + border-radius: 50px; /* Estilo pílula */ + padding: 14px 40px; + font-size: 16px; + font-weight: 600; + cursor: pointer; + + /* Sombra roxa no botão */ + box-shadow: 0 8px 20px rgba(99, 102, 241, 0.35); + } -#resume:hover{ - background-color: aqua; + +#resume:hover { + background-color: aqua; } \ No newline at end of file From 93f5871488453af14313e554db4a18f85059d0f5 Mon Sep 17 00:00:00 2001 From: Rian Date: Tue, 13 Oct 2026 10:49:23 -0300 Subject: [PATCH 12/19] =?UTF-8?q?atualiza=C3=A7=C3=A3o=20das=20corres=20da?= =?UTF-8?q?s=20pe=C3=A7as=20que=20estava=20bagun=C3=A7ado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script.js | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/script.js b/script.js index 17f85a4..e69d004 100644 --- a/script.js +++ b/script.js @@ -151,19 +151,22 @@ var Stats = function () { // //------------------------------------------------------------------------- - var i = { size: 4, blocks: [0x0F00, 0x2222, 0x00F0, 0x4444], color: 'purple' }; - var j = { size: 3, blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20], color: 'pink' }; - var l = { size: 3, blocks: [0x4460, 0x0E80, 0xC440, 0x2E00], color: 'salmon' }; - var o = { size: 2, blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00], color: 'lime' }; - var s = { size: 3, blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], color: 'teal' }; - var t = { size: 3, blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], color: 'coral' }; - var z = { size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'olive' }; - var Plus = { size: 3, blocks: [0x4E40, 0x4E40, 0x4E40, 0x4E40], color: 'orange' }; - var block = { size: 3, blocks: [0xeee0, 0xeee0, 0xeee0, 0xeee0], color: 'green' }; - var block2 = { size: 4, blocks: [0xFfff, 0xFfff, 0xFfff, 0xFfff], color: 'blue' }; - var oo = { size: 4, blocks: [0xCCcc, 0x00ff, 0xCCcc, 0x00ff], color: 'red' }; + + var i = { size: 4, blocks: [0x0F00, 0x2222, 0x00F0, 0x4444], color: 'red' }; + var j = { size: 3, blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20], color: 'green' }; + var l = { size: 3, blocks: [0x4460, 0x0E80, 0xC440, 0x2E00], color: 'blue' }; + var o = { size: 2, blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00], color: 'orange' }; + var s = { size: 3, blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], color: 'purple' }; + var t = { size: 3, blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], color: 'yellow' }; + var z = { size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'pink' }; + var Plus = { size: 3, blocks: [0x4E40, 0x4E40, 0x4E40, 0x4E40], color: 'teal' }; + var block = { size: 3, blocks: [0xeee0, 0xeee0, 0xeee0, 0xeee0], color: 'coral' }; + var block2 = { size: 4, blocks: [0xFfff, 0xFfff, 0xFfff, 0xFfff], color: 'turquoise' }; + var oo = { size: 4, blocks: [0xCCcc, 0x00ff, 0xCCcc, 0x00ff], color: 'maroon' }; + + //------------------------------------------------ - // do the bit manipulation and iterate through each + // do the bit manipulation and iterate through each // occupied block (x,y) for a given piecere //------------------------------------------------ function eachblock(type, x, y, dir, fn) { @@ -202,7 +205,7 @@ var Stats = function () { var pieces = []; function randomPiece() { if (pieces.length == 0) - pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z,Plus,Plus,Plus,Plus,block,block,block,blocks,block2,block2,block2,block2,oo,oo,oo,oo]; + pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z,Plus,Plus,Plus,Plus,block,block,block,block,block2,block2,block2,block2,oo,oo,oo,oo]; var type = pieces.splice(random(0, pieces.length-1), 1)[0]; return { type: type, dir: DIR.UP, x: Math.round(random(0, nx - type.size)), y: 0 }; } From e09103cfe19a1b50f69d5aaf509dd5690f6de6c6 Mon Sep 17 00:00:00 2001 From: Rian Date: Tue, 13 Oct 2026 10:59:44 -0300 Subject: [PATCH 13/19] =?UTF-8?q?romo=C3=A7=C3=A3o=20de=20uma=20pe=C3=A7a?= =?UTF-8?q?=20block=204x4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/script.js b/script.js index e69d004..b0b5512 100644 --- a/script.js +++ b/script.js @@ -161,7 +161,6 @@ var Stats = function () { var z = { size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'pink' }; var Plus = { size: 3, blocks: [0x4E40, 0x4E40, 0x4E40, 0x4E40], color: 'teal' }; var block = { size: 3, blocks: [0xeee0, 0xeee0, 0xeee0, 0xeee0], color: 'coral' }; - var block2 = { size: 4, blocks: [0xFfff, 0xFfff, 0xFfff, 0xFfff], color: 'turquoise' }; var oo = { size: 4, blocks: [0xCCcc, 0x00ff, 0xCCcc, 0x00ff], color: 'maroon' }; @@ -205,7 +204,7 @@ var Stats = function () { var pieces = []; function randomPiece() { if (pieces.length == 0) - pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z,Plus,Plus,Plus,Plus,block,block,block,block,block2,block2,block2,block2,oo,oo,oo,oo]; + pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z,Plus,Plus,Plus,Plus,block,block,block,block,oo,oo,oo,oo]; var type = pieces.splice(random(0, pieces.length-1), 1)[0]; return { type: type, dir: DIR.UP, x: Math.round(random(0, nx - type.size)), y: 0 }; } From b850fda2f5161419761fe5b695531c5c54d8e9db Mon Sep 17 00:00:00 2001 From: ryanccoelho Date: Tue, 13 Oct 2026 17:08:46 -0300 Subject: [PATCH 14/19] Revert "merge: integra feature/reiniciar na main" This reverts commit af2d4feffebebe3db111f1335693d368f58262c8, reversing changes made to c6133ebe30985a2804d6a9faab522d8b24a07afd. --- index.html | 31 ++++++++++++++++++++++++++++++- styles.css | 20 -------------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/index.html b/index.html index ec4bd27..c4ce978 100644 --- a/index.html +++ b/index.html @@ -1,3 +1,24 @@ + + + + + Javascript Tetris + + + + +
+ + + Sorry, this example cannot be run because your browser does not support the <canvas> element + +
+