"use strict"; const grid_x = 10; const grid_y = 20; const tetrimonios = [ /*'I'*/{ mR:2, r:[ [ [0,0],[0,1],[0,2],[0,3] ], [ [0,0],[1,0],[2,0],[3,0] ] ] }, /*'O':*/{ mR:1, r:[ [ [0,0],[0,1],[1,0],[1,1] ] ] }, /*'L':*/{ mR:4, r:[ [ [0,0],[0,1],[0,2],[1,2] ], [ [0,0],[1,0],[2,0],[0,1] ], [ [0,0],[1,0],[1,1],[1,2] ], [ [2,0],[2,1],[1,1],[0,1] ] ] }, /*'L2':*/{ mR:4, r:[ [ [1,0],[1,1],[1,2],[0,2] ], [ [0,0],[0,1],[1,1],[2,1] ], [ [1,0],[0,0],[0,1],[0,2] ], [ [0,0],[1,0],[2,0],[2,1] ] ] }, /*'Z':*/{ mR:2, r:[ [ [0,0],[1,0],[1,1],[2,1] ], [ [1,0],[1,1],[0,1],[0,2] ] ] }, /*'Z2':*/{ mR:2, r:[ [ [0,1],[1,1],[1,0],[2,0] ], [ [0,0],[0,1],[1,1],[1,2] ] ] }, /*'T':*/{ mR:4, r:[ [ [1,0],[0,1],[1,1],[2,1] ], [ [0,0],[0,1],[0,2],[1,1] ], [ [0,0],[1,0],[2,0],[1,1] ], [ [1,0],[1,1],[1,2],[0,1] ] ] } ]; class Shape { constructor(board) { this.board = board; this.set(null); } set(t) { this.t = t; this.x = this.board.w/2 -1; this.ox = this.x; this.y = 0; this.oy = 0; this.r = 0; this.or = 0 } rotate() { let r = this.r; this.r = (this.r + 1) % this.t.mR; if ( this.board.collision(this) ) { this.r = r; } else { this.or = r; this.ox = this.x; this.oy = this.y; this.board.draw(this); // this.t, this.x, this.y, this.r); } } down() { this.y++; if ( this.board.collision(this) ) { this.y--; this.board.glue(this); } else { this.ox = this.x; this.oy = this.y -1; this.or = this.r; this.board.draw(this); } } left() { this.x--; if ( this.board.collision(this) ) { this.x++; } else { this.ox = this.x + 1; this.oy = this.y; this.or = this.r; this.board.draw(this); } } right() { this.x++; if ( this.board.collision(this) ) { this.x--; } else { this.ox = this.x - 1; this.oy = this.y; this.or = this.r; this.board.draw(this); } } } class Board { constructor(w,h,canvas) { this.ctx = canvas.getContext("2d"); const space_top = 5; const space_right = 10; const { width, height } = canvas.getBoundingClientRect(); this.s = Math.floor( Math.min( height / (space_top + h), width / (space_right + w) ) ); this.x = this.s*1; this.y = canvas.height - this.s*h - this.s*1; this.w = w; this.h = h; this.next_t = this.getRandomT(); this.reset(); this.shape = new Shape(this); this.shape.set(this.getRandomT()); } reset() { this.board = Array.from(Array(this.h), () => new Array(this.w)); // Board[Y][X] this.clean(); } collision(p /*:Shape*/ ) { if ( p.x<0 || p.x>=this.w || p.y<0 || p.y>=this.h ) return true; if ( p.t.r[p.r].filter(b => ( p.x+b[0]>=this.w || p.y+b[1]>=this.h || this.board[p.y+b[1]][p.x+b[0]]==1 ) ).length>0 ) return true; return false } glue(p /*:Shape*/) { p.t.r[p.r].forEach(b => { this.board[p.y+b[1]][p.x+b[0]]=1; } ); this.draw(p,false); this.deleteRows( this.board.filter( r=>r.filter(c=>c==1).length==grid_x ) ); p.set(this.next_t); this.next_t = this.getRandomT(); } getRandomT() { return tetrimonios[ Math.floor(Math.random() * tetrimonios.length) ]; } draw(p /*:Shape*/, live) { live = typeof(live) == 'undefined' ? true : live; this.ctx.fillStyle = "#FFFFFF"; p.t.r[p.or].forEach(b => this.drawBlock(p.ox + b[0], p.oy + b[1])); this.ctx.fillStyle = live?"#F66666":"#666666"; p.t.r[p.r].forEach(b => this.drawBlock(p.x + b[0], p.y + b[1])); } drawBlock(x,y) { this.ctx.fillRect(this.x + this.s*x, this.y + this.s*y, this.s, this.s); } deleteRows(r) { if (r.length>0) { let newBoard = this.board.filter( r=>r.filter(c=>c==1).length new Array(this.w)); this.board = this.board.concat(newBoard); this.clean(); this.ctx.fillStyle = "#666666"; this.board.forEach((r,y)=>r.forEach((c,x)=>{if(c==1)this.drawBlock(x,y);})) } } clean() { this.ctx.fillStyle = "#FFFFFF"; this.ctx.fillRect(this.x, this.y, this.s*this.w, this.s*this.h); } } let tetris = function () { // ---------------------------------------------------------- let timer; let canvas = document.getElementById("app"); canvas.width = window.innerWidth canvas.height = window.innerHeight let ctx = canvas.getContext("2d"); let board = new Board(grid_x,grid_y,canvas); document.addEventListener('keydown', control); newGame(); // ---------------------------------------------------------- function control(e) { switch(e.key) { case 'r': newGame(); break; case 'ArrowUp': board.shape.rotate(); break; case 'ArrowDown': board.shape.down(); break; case 'ArrowLeft': board.shape.left(); break; case 'ArrowRight': board.shape.right(); break; } } function newGame() { drawBackground(); board.reset(); if (!timer) timer = setInterval(()=>board.shape.down(), 1000); } function drawBackground() { ctx.fillStyle = "#FFFFFF"; ctx.fillRect(0,0,canvas.getBoundingClientRect().width,canvas.getBoundingClientRect().height); ctx.strokeStyle = "#0074cc"; ctx.strokeRect(board.x -1, board.y - 1, board.s*board.w +2, board.s*board.h +2); } } document.addEventListener('DOMContentLoaded', tetris );