├── .gitignore ├── README.md ├── assets ├── bubble.ttf └── tetris-screen.png ├── index.html ├── javascript └── tetris.js └── tetris.css /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .DS_Store? 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quick Tetris 2 | 3 | #### Try it out at: https://sacert.github.io/Quick-Tetris/ 4 | 5 | Built a quick version of Tetris using html/css/javascript 6 | 7 | Inspired by https://github.com/jstimpfle/tetris-on-a-plane/ who built Tetris during a plane ride - I decided to do the same except I set my deadline as the time before I had to start studying for my midterm. 8 | 9 | Of course due to time constraints, there are several features missing such as displaying the next block that will drop, a scoring system, and a game over screen. And to add, yes the code is messy but it works! 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /assets/bubble.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sacert/Quick-Tetris/113ffaaf317501a140b9bd638ec43180e0cd2eae/assets/bubble.ttf -------------------------------------------------------------------------------- /assets/tetris-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sacert/Quick-Tetris/113ffaaf317501a140b9bd638ec43180e0cd2eae/assets/tetris-screen.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tetris 5 | 6 | 7 | 8 |
JS TETRIS
9 |
10 | 11 |
12 |
CONTROLS: 'R' RESET, 'SPC' DROP, 'ARROWS' MOVE
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /javascript/tetris.js: -------------------------------------------------------------------------------- 1 | // great wall of global variables 2 | // travelers beware 3 | var c = document.getElementsByTagName('canvas')[0]; 4 | var ctx = c.getContext("2d"); 5 | var w = 350; 6 | var h = 600; 7 | var ROWS = 20; 8 | var COLS = 10; 9 | var BLOCK_W = w/ COLS; 10 | var BLOCK_H = h/ ROWS; 11 | var shape; 12 | var tetrisBoard = []; 13 | var currX, currY; 14 | var firstTime = true; 15 | var pieceSize; 16 | var gameOver = false; 17 | 18 | window.addEventListener('resize', resizeCanvas, false); 19 | window.addEventListener("keydown", controls, false); 20 | 21 | function controls(e) { 22 | if(e.keyCode == 38) { // up key 23 | e.preventDefault(); 24 | var rotShape = rotate(); 25 | if(valid(0,0,rotShape)) { 26 | shape = rotShape; 27 | } 28 | } else if(e.keyCode == 39) { // right key 29 | e.preventDefault(); 30 | if(valid(1)) { 31 | currX++; 32 | } 33 | } else if(e.keyCode == 37) { // left key 34 | e.preventDefault(); 35 | if(valid(-1)) { 36 | currX--; 37 | } 38 | } else if(e.keyCode == 40) { // down key 39 | e.preventDefault(); 40 | if(valid(0,1)) { 41 | currY++; 42 | } 43 | } else if(e.keyCode == 32) { // spacebar 44 | e.preventDefault(); 45 | dropDown(); 46 | } else if(e.keyCode == 82) { // reset 'r' 47 | newGame(); 48 | } 49 | } 50 | 51 | var pieces = [ 52 | [1,1,1,1], 53 | [2,2,2, 54 | 2], 55 | [3,3,3, 56 | 0,0,3], 57 | [4,4,4, 58 | 0,4,0], 59 | [0,5,5, 60 | 0,5,5], 61 | [0,6,6, 62 | 6,6], 63 | [7,7,0, 64 | 0,7,7]]; 65 | 66 | 67 | function createShape() { 68 | 69 | var randomShape = Math.floor(Math.random() * pieces.length) 70 | 71 | if (randomShape == 0) { // if I shape, the matrix will be 4x4 72 | pieceSize = 4; 73 | } else { 74 | pieceSize = 3; 75 | } 76 | 77 | var counter = -pieceSize; 78 | shape = []; 79 | for (i = 0; i < pieceSize; i++) { 80 | shape[ i ] = []; 81 | for (j = 0; j < pieceSize; j++) { 82 | if( counter < pieces[randomShape].length && i > 0) { 83 | shape[i][j] = pieces[randomShape][counter]; 84 | } else { 85 | shape[i][j] = 0; 86 | } 87 | counter++; 88 | } 89 | } 90 | 91 | // set dimensions for the shape on the board 92 | currX = 3; 93 | currY = -1; 94 | 95 | } 96 | 97 | function rotate() { 98 | 99 | shapeString = shape.toString(); 100 | boxString = [[0,0,0],[0,5,5],[0,5,5]].toString(); 101 | 102 | // don't rotate the square 103 | if (shapeString == boxString) { 104 | return shape; 105 | } 106 | var rotShape = []; 107 | for ( i = 0; i < pieceSize; ++i ) { 108 | rotShape[ i ] = []; 109 | for ( j = 0; j < pieceSize; ++j ) { 110 | rotShape[ i ][ j ] = shape[ pieceSize - j - 1 ][ i ]; 111 | } 112 | } 113 | 114 | // set the shape to be that of the rotated shape 115 | return rotShape; 116 | } 117 | 118 | // clears the board 119 | function init() { 120 | for(i = 0; i < ROWS; i++) { 121 | tetrisBoard[i] = []; 122 | for(j = 0; j < COLS; j++) { 123 | tetrisBoard[i][j] = 0; 124 | } 125 | } 126 | } 127 | 128 | var colors = [ 129 | 'cyan', 'orange', 'deepskyblue', 'yellow', 'tomato', 'lime', 'violet' 130 | ]; 131 | 132 | // draws the board and the moving shape 133 | function draw() { 134 | 135 | for ( var x = 0; x < COLS; ++x ) { 136 | for ( var y = 0; y < ROWS; ++y ) { 137 | if ( tetrisBoard[ y ][ x ] ) { 138 | ctx.strokeStyle = 'black'; 139 | ctx.lineWidth = "4"; 140 | ctx.fillStyle = colors[ tetrisBoard[ y ][ x ] - 1 ]; 141 | ctx.fillRect( BLOCK_W * x, BLOCK_H * y, BLOCK_W - 1 , BLOCK_H - 1 ); 142 | ctx.strokeRect( BLOCK_W * x, BLOCK_H * y, BLOCK_W - 1 , BLOCK_H - 1 ); 143 | } 144 | else { 145 | ctx.strokeStyle = 'black'; 146 | ctx.lineWidth = "0.8"; 147 | ctx.fillStyle = 'white'; 148 | ctx.fillRect( BLOCK_W * x+1, BLOCK_H * y+1, BLOCK_W - 1 , BLOCK_H - 1 ); 149 | ctx.strokeRect( BLOCK_W * x, BLOCK_H * y, BLOCK_W - 1 , BLOCK_H - 1 ); 150 | } 151 | } 152 | } 153 | 154 | ctx.strokeStyle = 'black'; 155 | for ( var y = 0; y < pieceSize; ++y ) { 156 | for ( var x = 0; x < pieceSize; ++x ) { 157 | if ( shape[ y ][ x ] ) { 158 | ctx.fillStyle = colors[ shape[ y ][ x ] - 1 ]; 159 | ctx.lineWidth = "4"; 160 | ctx.fillRect( BLOCK_W * (x+currX) , BLOCK_H * (y+currY) , BLOCK_W - 1 , BLOCK_H - 1 ); 161 | ctx.strokeRect( BLOCK_W * (x+currX) , BLOCK_H * (y+currY) , BLOCK_W - 1 , BLOCK_H - 1 ); 162 | } 163 | } 164 | } 165 | } 166 | 167 | 168 | function tick() { 169 | 170 | if(valid(0, 1)) { 171 | currY++; 172 | } else { 173 | modifyBoard(); 174 | lineCheck(); 175 | if(gameOver) { 176 | return; 177 | } 178 | createShape(); 179 | } 180 | } 181 | 182 | function lineCheck() { 183 | 184 | for ( var y = ROWS-1; y >= 0; --y ) { 185 | var clearLine = true; 186 | for ( var x = 0; x < COLS; ++x ) { 187 | if(!tetrisBoard[y][x]) { 188 | clearLine = false; 189 | break; 190 | } 191 | } 192 | 193 | if(clearLine) { 194 | for ( var i = y; i> 0; --i ) { 195 | for ( var j = 0; j < COLS; ++j ) { 196 | tetrisBoard[i][j] = tetrisBoard[i-1][j]; 197 | } 198 | } 199 | y++; 200 | } 201 | } 202 | } 203 | 204 | function modifyBoard() { 205 | for ( var y = 0; y < pieceSize; ++y ) { 206 | for ( var x = 0; x < pieceSize; ++x ) { 207 | if ( shape[ y ][ x ] ) { 208 | tetrisBoard[currY + y][currX + x] = shape[y][x] 209 | } 210 | } 211 | } 212 | } 213 | 214 | function valid( offsetX, offsetY, newCurrent ) { 215 | offsetX = offsetX || 0; 216 | offsetY = offsetY || 0; 217 | offsetX = currX + offsetX; 218 | offsetY = currY + offsetY; 219 | newCurrent = newCurrent || shape; 220 | 221 | for ( var y = 0; y < pieceSize; ++y ) { 222 | for ( var x = 0; x < pieceSize; ++x ) { 223 | if ( newCurrent[ y ][ x ] ) { 224 | if ( typeof tetrisBoard[ y + offsetY ] == 'undefined' 225 | || typeof tetrisBoard[ y + offsetY ][ x + offsetX ] == 'undefined' 226 | || tetrisBoard[ y + offsetY ][ x + offsetX ] 227 | || x + offsetX < 0 228 | || y + offsetY >= ROWS 229 | || x + offsetX >= COLS ) { 230 | if((offsetY == 0 || offsetY == 1) && (offsetX >= 0 && offsetX < 11 - pieceSize)) { 231 | gameOver = true; 232 | } 233 | return false; 234 | } 235 | } 236 | } 237 | } 238 | return true; 239 | } 240 | 241 | function dropDown() { 242 | 243 | for ( var y = pieceSize - 1; y >= 0; --y ) { 244 | for ( var x = pieceSize - 1; x >= 0; --x ) { 245 | if ( shape[ y ][ x ] ) { 246 | for ( var offsetY = currY; offsetY < ROWS; ++offsetY ) { 247 | 248 | if(valid(0,1)) { 249 | currY++; 250 | } 251 | } 252 | } 253 | } 254 | } 255 | } 256 | 257 | function newGame() { 258 | for ( var y = 0; y < ROWS; ++y ) { 259 | for ( var x = 0; x < COLS; ++x ) { 260 | tetrisBoard[y][x] = 0; 261 | } 262 | } 263 | gameOver = false; 264 | createShape(); 265 | } 266 | 267 | function startGame() { 268 | resizeCanvas(); 269 | init(); 270 | createShape(); 271 | draw(); 272 | 273 | setInterval( tick, 250 ); 274 | setInterval( draw, 30 ); 275 | 276 | } 277 | 278 | function resizeCanvas() { 279 | c.width = ((window.innerHeight/1.3) / 1.714); 280 | c.height = window.innerHeight/1.3; 281 | w = c.width; 282 | h = c.height; 283 | BLOCK_W = w/ COLS; 284 | BLOCK_H = h/ ROWS; 285 | } 286 | 287 | startGame(); 288 | -------------------------------------------------------------------------------- /tetris.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: bubble; 3 | src: url(assets/bubble.ttf); 4 | } 5 | 6 | body { 7 | width: 100%; 8 | height: 100%; 9 | margin: 0px; 10 | } 11 | 12 | canvas { 13 | display: block; 14 | margin: auto; 15 | border: 5px solid black; 16 | border-radius: 5px; 17 | background-color: #2F4F4F; 18 | } 19 | 20 | #title { 21 | text-align: center; 22 | padding: 20px; 23 | font-family: bubble; 24 | font-size: 50px; 25 | } 26 | 27 | #container { 28 | height: 60%; 29 | } 30 | 31 | #guide { 32 | text-align: center; 33 | padding: 20px; 34 | font-family: bubble; 35 | font-size: 30px; 36 | } 37 | --------------------------------------------------------------------------------