├── 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 |
22 |
23 |
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 |
--------------------------------------------------------------------------------