Controls: click and drag to look around, and click on a location to move to it!
The main technique here is ray-marching signed distance fields, as pioneered / popularized by the incredible Inigo Quilez.
Controls: click and drag to look around, and click on a location to move to it!
The main technique here is ray-marching signed distance fields, as pioneered / popularized by the incredible Inigo Quilez.
<script>
var piece, rows = [], delay = 500, key = 0;
onkeydown = e => key = e.key;
document.body.onload = () => (
cvs.style.width = "100px", cvs.style.height = "300px",
piece = makep(), frame(), setTimeout(step, delay));
// respond to player input, draw the board and piece
function frame() {
move(({w: p => p.r = (p.r+1)%4, s: p => p.y--,
a: p => p.x--, d: p => p.x++})[key] || (p => p));
key = 0;
cvs.getContext("2d").clearRect(0, 0, cvs.width, cvs.height);
var px = (x, y) => cvs.getContext("2d").fillRect(x, cvs.height-y-1, 1, 1);
rows.map((r, y) => Object.keys(r).map(x => px(+x, y)));
eachblock(piece, px);
if (delay > 0) delay -= .01;
requestAnimationFrame(frame);
}
// try to move the piece down, clear rows and/or end the game if can't
function step() {
setTimeout(step, delay);
if (move(p => p.y--)) return;
eachblock(piece, (x, y) => (rows[y] = rows[y] || {}, rows[y][x] = 1));
score.innerHTML = parseInt(score.innerHTML) + rows.length -
(rows = rows.filter(r => Object.keys(r).length < cvs.width)).length;
if (rows.length >= cvs.height) score.innerHTML += " -- GAME OVER";
piece = makep();
}
function move(f) {
var newp = Object.assign({}, piece);
f(newp);
if (legal(newp)) {Object.assign(piece, newp); return true}
return false;
}
var makep = () => ({y: cvs.height-1, x: cvs.width/2 -1|0, r: 0,
blocks: ["1111", "11\n 11", " 11\n11", "11\n11",
"111\n1", "111\n 1", "111\n 1"][Math.random()*7|0]});
function eachblock(p, f) {
var results = [], [x, y] = [p.x, p.y];
var r = p.blocks == "11\n11"? 0 : p.r;
var [nextblock, nextline] = [
[() => x++, () => {y--; x = p.x}], [() => y--, () => {x--; y = p.y}],
[() => x--, () => {y++; x = p.x}], [() => y++, () => {x++; y = p.y}]][r];
p.blocks.split("").map(c => {
if (c == "\n") {nextline(); return}
if (c == "1") results.push(f(+x + [0,1,2,0][r], +y + [0,0,-1,-1][r]));
nextblock()});
return results;
}
var legal = p => eachblock(p, (x, y) => x >= 0 && x < cvs.width && y >= 0
&& !(rows[y] || {})[x]).filter(x=>x).length == 4;
</script>
<canvas id="cvs" width="10" height = "30"
style = "image-rendering:pixelated; border: 1px solid black;">
</canvas> <div id="score">0</div>