├── .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 |
--------------------------------------------------------------------------------