├── README.md ├── index.html ├── tetris - starter template.rar ├── tetris.js └── tetrominoes.js /README.md: -------------------------------------------------------------------------------- 1 | # Tetris-JavaScript 2 | 3 | The Tetris game, created using JavaScript, and The HTML5 canvas. 4 | 5 | Download the starter template, and follow the tutorial on youtube step by step. 6 | 7 | Tutorial link : https://www.youtube.com/watch?v=HEsAr2Yt2do 8 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Tetris Game JS 4 | 19 | 20 | 21 |
This Game Was Created By Code Explained

22 | 23 |
24 | Score :
0
25 |
26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tetris - starter template.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeExplainedRepo/Tetris-JavaScript/3b63a59bbac0cc581c3ada6222781bc5da79c6b0/tetris - starter template.rar -------------------------------------------------------------------------------- /tetris.js: -------------------------------------------------------------------------------- 1 | const cvs = document.getElementById("tetris"); 2 | const ctx = cvs.getContext("2d"); 3 | const scoreElement = document.getElementById("score"); 4 | 5 | const ROW = 20; 6 | const COL = COLUMN = 10; 7 | const SQ = squareSize = 20; 8 | const VACANT = "WHITE"; // color of an empty square 9 | 10 | // draw a square 11 | function drawSquare(x,y,color){ 12 | ctx.fillStyle = color; 13 | ctx.fillRect(x*SQ,y*SQ,SQ,SQ); 14 | 15 | ctx.strokeStyle = "BLACK"; 16 | ctx.strokeRect(x*SQ,y*SQ,SQ,SQ); 17 | } 18 | 19 | // create the board 20 | 21 | let board = []; 22 | for( r = 0; r 6 56 | return new Piece( PIECES[r][0],PIECES[r][1]); 57 | } 58 | 59 | let p = randomPiece(); 60 | 61 | // The Object Piece 62 | 63 | function Piece(tetromino,color){ 64 | this.tetromino = tetromino; 65 | this.color = color; 66 | 67 | this.tetrominoN = 0; // we start from the first pattern 68 | this.activeTetromino = this.tetromino[this.tetrominoN]; 69 | 70 | // we need to control the pieces 71 | this.x = 3; 72 | this.y = -2; 73 | } 74 | 75 | // fill function 76 | 77 | Piece.prototype.fill = function(color){ 78 | for( r = 0; r < this.activeTetromino.length; r++){ 79 | for(c = 0; c < this.activeTetromino.length; c++){ 80 | // we draw only occupied squares 81 | if( this.activeTetromino[r][c]){ 82 | drawSquare(this.x + c,this.y + r, color); 83 | } 84 | } 85 | } 86 | } 87 | 88 | // draw a piece to the board 89 | 90 | Piece.prototype.draw = function(){ 91 | this.fill(this.color); 92 | } 93 | 94 | // undraw a piece 95 | 96 | 97 | Piece.prototype.unDraw = function(){ 98 | this.fill(VACANT); 99 | } 100 | 101 | // move Down the piece 102 | 103 | Piece.prototype.moveDown = function(){ 104 | if(!this.collision(0,1,this.activeTetromino)){ 105 | this.unDraw(); 106 | this.y++; 107 | this.draw(); 108 | }else{ 109 | // we lock the piece and generate a new one 110 | this.lock(); 111 | p = randomPiece(); 112 | } 113 | 114 | } 115 | 116 | // move Right the piece 117 | Piece.prototype.moveRight = function(){ 118 | if(!this.collision(1,0,this.activeTetromino)){ 119 | this.unDraw(); 120 | this.x++; 121 | this.draw(); 122 | } 123 | } 124 | 125 | // move Left the piece 126 | Piece.prototype.moveLeft = function(){ 127 | if(!this.collision(-1,0,this.activeTetromino)){ 128 | this.unDraw(); 129 | this.x--; 130 | this.draw(); 131 | } 132 | } 133 | 134 | // rotate the piece 135 | Piece.prototype.rotate = function(){ 136 | let nextPattern = this.tetromino[(this.tetrominoN + 1)%this.tetromino.length]; 137 | let kick = 0; 138 | 139 | if(this.collision(0,0,nextPattern)){ 140 | if(this.x > COL/2){ 141 | // it's the right wall 142 | kick = -1; // we need to move the piece to the left 143 | }else{ 144 | // it's the left wall 145 | kick = 1; // we need to move the piece to the right 146 | } 147 | } 148 | 149 | if(!this.collision(kick,0,nextPattern)){ 150 | this.unDraw(); 151 | this.x += kick; 152 | this.tetrominoN = (this.tetrominoN + 1)%this.tetromino.length; // (0+1)%4 => 1 153 | this.activeTetromino = this.tetromino[this.tetrominoN]; 154 | this.draw(); 155 | } 156 | } 157 | 158 | let score = 0; 159 | 160 | Piece.prototype.lock = function(){ 161 | for( r = 0; r < this.activeTetromino.length; r++){ 162 | for(c = 0; c < this.activeTetromino.length; c++){ 163 | // we skip the vacant squares 164 | if( !this.activeTetromino[r][c]){ 165 | continue; 166 | } 167 | // pieces to lock on top = game over 168 | if(this.y + r < 0){ 169 | alert("Game Over"); 170 | // stop request animation frame 171 | gameOver = true; 172 | break; 173 | } 174 | // we lock the piece 175 | board[this.y+r][this.x+c] = this.color; 176 | } 177 | } 178 | // remove full rows 179 | for(r = 0; r < ROW; r++){ 180 | let isRowFull = true; 181 | for( c = 0; c < COL; c++){ 182 | isRowFull = isRowFull && (board[r][c] != VACANT); 183 | } 184 | if(isRowFull){ 185 | // if the row is full 186 | // we move down all the rows above it 187 | for( y = r; y > 1; y--){ 188 | for( c = 0; c < COL; c++){ 189 | board[y][c] = board[y-1][c]; 190 | } 191 | } 192 | // the top row board[0][..] has no row above it 193 | for( c = 0; c < COL; c++){ 194 | board[0][c] = VACANT; 195 | } 196 | // increment the score 197 | score += 10; 198 | } 199 | } 200 | // update the board 201 | drawBoard(); 202 | 203 | // update the score 204 | scoreElement.innerHTML = score; 205 | } 206 | 207 | // collision fucntion 208 | 209 | Piece.prototype.collision = function(x,y,piece){ 210 | for( r = 0; r < piece.length; r++){ 211 | for(c = 0; c < piece.length; c++){ 212 | // if the square is empty, we skip it 213 | if(!piece[r][c]){ 214 | continue; 215 | } 216 | // coordinates of the piece after movement 217 | let newX = this.x + c + x; 218 | let newY = this.y + r + y; 219 | 220 | // conditions 221 | if(newX < 0 || newX >= COL || newY >= ROW){ 222 | return true; 223 | } 224 | // skip newY < 0; board[-1] will crush our game 225 | if(newY < 0){ 226 | continue; 227 | } 228 | // check if there is a locked piece alrady in place 229 | if( board[newY][newX] != VACANT){ 230 | return true; 231 | } 232 | } 233 | } 234 | return false; 235 | } 236 | 237 | // CONTROL the piece 238 | 239 | document.addEventListener("keydown",CONTROL); 240 | 241 | function CONTROL(event){ 242 | if(event.keyCode == 37){ 243 | p.moveLeft(); 244 | dropStart = Date.now(); 245 | }else if(event.keyCode == 38){ 246 | p.rotate(); 247 | dropStart = Date.now(); 248 | }else if(event.keyCode == 39){ 249 | p.moveRight(); 250 | dropStart = Date.now(); 251 | }else if(event.keyCode == 40){ 252 | p.moveDown(); 253 | } 254 | } 255 | 256 | // drop the piece every 1sec 257 | 258 | let dropStart = Date.now(); 259 | let gameOver = false; 260 | function drop(){ 261 | let now = Date.now(); 262 | let delta = now - dropStart; 263 | if(delta > 1000){ 264 | p.moveDown(); 265 | dropStart = Date.now(); 266 | } 267 | if( !gameOver){ 268 | requestAnimationFrame(drop); 269 | } 270 | } 271 | 272 | drop(); 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | -------------------------------------------------------------------------------- /tetrominoes.js: -------------------------------------------------------------------------------- 1 | const I = [ 2 | [ 3 | [0, 0, 0, 0], 4 | [1, 1, 1, 1], 5 | [0, 0, 0, 0], 6 | [0, 0, 0, 0], 7 | ], 8 | [ 9 | [0, 0, 1, 0], 10 | [0, 0, 1, 0], 11 | [0, 0, 1, 0], 12 | [0, 0, 1, 0], 13 | ], 14 | [ 15 | [0, 0, 0, 0], 16 | [0, 0, 0, 0], 17 | [1, 1, 1, 1], 18 | [0, 0, 0, 0], 19 | ], 20 | [ 21 | [0, 1, 0, 0], 22 | [0, 1, 0, 0], 23 | [0, 1, 0, 0], 24 | [0, 1, 0, 0], 25 | ] 26 | ]; 27 | 28 | const J = [ 29 | [ 30 | [1, 0, 0], 31 | [1, 1, 1], 32 | [0, 0, 0] 33 | ], 34 | [ 35 | [0, 1, 1], 36 | [0, 1, 0], 37 | [0, 1, 0] 38 | ], 39 | [ 40 | [0, 0, 0], 41 | [1, 1, 1], 42 | [0, 0, 1] 43 | ], 44 | [ 45 | [0, 1, 0], 46 | [0, 1, 0], 47 | [1, 1, 0] 48 | ] 49 | ]; 50 | 51 | const L = [ 52 | [ 53 | [0, 0, 1], 54 | [1, 1, 1], 55 | [0, 0, 0] 56 | ], 57 | [ 58 | [0, 1, 0], 59 | [0, 1, 0], 60 | [0, 1, 1] 61 | ], 62 | [ 63 | [0, 0, 0], 64 | [1, 1, 1], 65 | [1, 0, 0] 66 | ], 67 | [ 68 | [1, 1, 0], 69 | [0, 1, 0], 70 | [0, 1, 0] 71 | ] 72 | ]; 73 | 74 | const O = [ 75 | [ 76 | [0, 0, 0, 0], 77 | [0, 1, 1, 0], 78 | [0, 1, 1, 0], 79 | [0, 0, 0, 0], 80 | ] 81 | ]; 82 | 83 | const S = [ 84 | [ 85 | [0, 1, 1], 86 | [1, 1, 0], 87 | [0, 0, 0] 88 | ], 89 | [ 90 | [0, 1, 0], 91 | [0, 1, 1], 92 | [0, 0, 1] 93 | ], 94 | [ 95 | [0, 0, 0], 96 | [0, 1, 1], 97 | [1, 1, 0] 98 | ], 99 | [ 100 | [1, 0, 0], 101 | [1, 1, 0], 102 | [0, 1, 0] 103 | ] 104 | ]; 105 | 106 | const T = [ 107 | [ 108 | [0, 1, 0], 109 | [1, 1, 1], 110 | [0, 0, 0] 111 | ], 112 | [ 113 | [0, 1, 0], 114 | [0, 1, 1], 115 | [0, 1, 0] 116 | ], 117 | [ 118 | [0, 0, 0], 119 | [1, 1, 1], 120 | [0, 1, 0] 121 | ], 122 | [ 123 | [0, 1, 0], 124 | [1, 1, 0], 125 | [0, 1, 0] 126 | ] 127 | ]; 128 | 129 | const Z = [ 130 | [ 131 | [1, 1, 0], 132 | [0, 1, 1], 133 | [0, 0, 0] 134 | ], 135 | [ 136 | [0, 0, 1], 137 | [0, 1, 1], 138 | [0, 1, 0] 139 | ], 140 | [ 141 | [0, 0, 0], 142 | [1, 1, 0], 143 | [0, 1, 1] 144 | ], 145 | [ 146 | [0, 1, 0], 147 | [1, 1, 0], 148 | [1, 0, 0] 149 | ] 150 | ]; 151 | --------------------------------------------------------------------------------