Tetris Game Using HTML CSS And JavaScript

Introduction
Hello coders, welcome to another new blog. Today in this article we’ll learn to create a Tetris Game. Most of us, played this game in our childhood and this was fun to play but we’ll build this Tetris Game by ourselves. In this game we’ve used HTML CSS and JavaScript to make our Tetris Game.
The Tetris game is a dynamic project for the web developers. To create this Tetris game project we’ve used HTML CSS and JavaScript. HTML code sets up the basic structure for our Tetris game. CSS styles and design our game and make our game visually appealing. Lastly, the JavaScript adds interactive functionality in our Tetris Game.
If you’re interested to build this type of game then you should have the good knowledge and skills in HTML CSS and JavaScript. If you’re good in these technologies then you’re good to go. You can also build this type of game by yourself. This type of dynamic game project enhances your coding skills and knowledge. Let’s understand the code.
HTML (index.html)
Get Discount on Top Educational Courses
This is our HTML code. HTML stands for Hyper Text Markup Language. This HTML code sets up the basic structure for our Tetris game. Let’s breakdown our code.
- <!DOCTYPE html> : It defines the type of our document and ensures that our document is a HTML file document.
- <title> : It sets the title of our webpage as Tetris Game.
- <link> : This tag links external CSS file into our code document.
- <body> : This contains all the content of our page.
- <div id=”tetris”> : This works as a main container of the game.
- <div id=”info”> : Contains all the game objects.
- <div id=”next_shape”> : This will display the next shape which will appear in the game.
- <p>: The 4 paragraph tag with the id “level”, “line”, “score” and “time” that will display the game statics.
- <button id=”start”> : This will start the game.
- <p class=”red”> : This will display a message in red text to pause the game using esc button.
- <div id=”canvas”> : This is the section where game board will appear.
- <script> : This tag links external JavaScript file in our code document.
Tetris Game
Level:
Lines:
Score:
Time:
Press the Esc button to pause
CSS (Style.css)
This is our CSS code which designs our Tetris game. This code makes our game Visually appealing. CSS generally used for designing the webpages. Let’s breakdown our code.
- The body selector styles our whole webpage. It sets overflow hidden and a light gray background.
- The #tetris sets width of 360px, border of 1px solid black and 20px of padding.
- The #canvas selector sets height of 440px and width of 200px. It also sets black background color with white text color and position relative to the parent.
- The h1 of canvas element removes margin padding and centers the text and increases font size.
- .piece sets a position absolute and a border.
- The #start selector sets an animation with a background color, color, border radius and font size. It also sets the cursor as pointer.
- The keyframes defines animation for the start selector.
- .red class applies red text color to its elements.
- .square class sets position, height, width and border.
- .type[0-6] sets the different background colors.
- #next_shape sets its position to relative, black background, white border, with height width of 110px.
- #info sets black background color, white text color, height, width, padding and float the element to the right.
body {
overflow: hidden;
background: #d7d7d7;
}
#tetris {
width: 360px;
border: 1px solid black;
padding: 20px;
}
#canvas {
width: 200px;
height: 440px;
background-color: #000;
position: relative;
color: #fff;
}
#canvas h1 {
margin: 0;
padding: 0;
text-align: center;
font-size: 30px;
padding-top: 200px;
}
.piece {
border: 1px solid white;
position: absolute;
}
#start {
animation: blink 0.7s steps(2, start) infinite;
background: #e1ff5f;
border-radius: 2px;
color: #202020;
cursor: pointer;
font-size: 28px;
}
@keyframes blink {
to {
outline: #e1ff5f solid 1px;
}
}
.red {
color: #f00000;
}
.square {
position: absolute;
width: 19px;
height: 19px;
border: 1px solid white;
}
.type0 {
background-color: #a000f0;
}
.type1 {
background-color: #00f0f0;
}
.type2 {
background-color: #f0a000;
}
.type3 {
background-color: #0000f0;
}
.type4 {
background-color: #00f000;
}
.type5 {
background-color: #f00000;
}
.type6 {
background-color: #f0f000;
}
#next_shape {
position: relative;
background-color: #000;
border: 1px solid white;
width: 110px;
height: 110px;
}
#info {
background-color: #000;
color: #fff;
float: right;
width: 110px;
height: 420px;
padding: 10px;
}
Javascript (Script.js)
This is our JavaScript code which is the main important part for tetris game. Without the JavaScript code our game is only a design. This code adds functionality to our game which makes it work properly. JavaScript code adds logic to our tetris game and make it interactive. Let’s understand the code in brief.
- The code starts by defining a self invoked function that summarize entire game logic.
- The init method initialize the game by calling the other methods to starts the game board elements and then starts the game by calling play method.
- The initBoard function initialize the board size and creates an array to represent the board.
- initInfo function initialize the game info by displaying all elements.
- The initShapes function reset the current squares. It sets the current shape to the selected shape, initialize the next shape, set the coordinates for the current shape to the spawn point, and draw the current shape on the board.
- The initNextShape function sets the next shape which will be displayed and control its placement.
- The iniTempShapes function creates the possibles shapes array and then shuffle the array.
- The shiftTempShapes shift the temporary shapes array by removing first element from the array.
- drawShapes function creates the current shape on the board.
- The initTimer sets up the timer by which call the incTime function in every 2 second.
- The play function start the game and sets the active status to 1 and drawing the square on the canvas.
- The bindKeyEvents function sets key to bind event in the game. When key is pressed, corresponding action is performed.
- The move method moves the shape in specified direction by using some logic.
- calcScore function calculates the game score on the basis of line and speed of shape cleared.
- The checkScore function sets the players score and level up the level of game.
- gameOver function ends the game when the defining conditions are fulfilled.
- togglePause function works as pause and resume the game.
- createSquare function creates the single individual shape for the tetris game.
- removeCur function removes the current shape when the shape landed in game.
- The event listener added on the start button and when clicked, it starts the game.
This is how our JavaScript code works. This code is not easy to understand as it looks complicated but when you starts applying it you’ll find it easier. You can check the code below.
(function () {
var isStart = false;
var tetris = {
board: [],
boardDiv: null,
canvas: null,
pSize: 20,
canvasHeight: 440,
canvasWidth: 200,
boardHeight: 0,
boardWidth: 0,
spawnX: 4,
spawnY: 1,
shapes: [
[
[-1, 1],
[0, 1],
[1, 1],
[0, 0], //TEE
],
[
[-1, 0],
[0, 0],
[1, 0],
[2, 0], //line
],
[
[-1, -1],
[-1, 0],
[0, 0],
[1, 0], //L EL
],
[
[1, -1],
[-1, 0],
[0, 0],
[1, 0], //R EL
],
[
[0, -1],
[1, -1],
[-1, 0],
[0, 0], // R ess
],
[
[-1, -1],
[0, -1],
[0, 0],
[1, 0], //L ess
],
[
[0, -1],
[1, -1],
[0, 0],
[1, 0], //square
],
],
tempShapes: null,
curShape: null,
curShapeIndex: null,
curX: 0,
curY: 0,
curSqs: [],
nextShape: null,
nextShapeDisplay: null,
nextShapeIndex: null,
sqs: [],
score: 0,
scoreDisplay: null,
level: 1,
levelDisplay: null,
numLevels: 10,
time: 0,
maxTime: 1000,
timeDisplay: null,
isActive: 0,
curComplete: false,
timer: null,
sTimer: null,
speed: 700,
lines: 0,
init: function () {
isStart = true;
this.canvas = document.getElementById("canvas");
this.initBoard();
this.initInfo();
this.initLevelScores();
this.initShapes();
this.bindKeyEvents();
this.play();
},
initBoard: function () {
this.boardHeight = this.canvasHeight / this.pSize;
this.boardWidth = this.canvasWidth / this.pSize;
var s = this.boardHeight * this.boardWidth;
for (var i = 0; i < s; i++) {
this.board.push(0);
}
//this.boardDiv = document.getElementById('board); //for debugging
},
initInfo: function () {
this.nextShapeDisplay = document.getElementById("next_shape");
this.levelDisplay = document
.getElementById("level")
.getElementsByTagName("span")[0];
this.timeDisplay = document
.getElementById("time")
.getElementsByTagName("span")[0];
this.scoreDisplay = document
.getElementById("score")
.getElementsByTagName("span")[0];
this.linesDisplay = document
.getElementById("lines")
.getElementsByTagName("span")[0];
this.setInfo("time");
this.setInfo("score");
this.setInfo("level");
this.setInfo("lines");
},
initShapes: function () {
this.curSqs = [];
this.curComplete = false;
this.shiftTempShapes();
this.curShapeIndex = this.tempShapes[0];
this.curShape = this.shapes[this.curShapeIndex];
this.initNextShape();
this.setCurCoords(this.spawnX, this.spawnY);
this.drawShape(this.curX, this.curY, this.curShape);
},
initNextShape: function () {
if (typeof this.tempShapes[1] === "undefined") {
this.initTempShapes();
}
try {
this.nextShapeIndex = this.tempShapes[1];
this.nextShape = this.shapes[this.nextShapeIndex];
this.drawNextShape();
} catch (e) {
throw new Error("Could not create next shape. " + e);
}
},
initTempShapes: function () {
this.tempShapes = [];
for (var i = 0; i < this.shapes.length; i++) {
this.tempShapes.push(i);
}
var k = this.tempShapes.length;
while (--k) {
//Fisher Yates Shuffle
var j = Math.floor(Math.random() * (k + 1));
var tempk = this.tempShapes[k];
var tempj = this.tempShapes[j];
this.tempShapes[k] = tempj;
this.tempShapes[j] = tempk;
}
},
shiftTempShapes: function () {
try {
if (
typeof this.tempShapes === "undefined" ||
this.tempShapes === null
) {
this.initTempShapes();
} else {
this.tempShapes.shift();
}
} catch (e) {
throw new Error("Could not shift or init tempShapes: " + e);
}
},
initTimer: function () {
var me = this;
var tLoop = function () {
me.incTime();
me.timer = setTimeout(tLoop, 2000);
};
this.timer = setTimeout(tLoop, 2000);
},
initLevelScores: function () {
var c = 1;
for (var i = 1; i <= this.numLevels; i++) {
this["level" + i] = [c * 1000, 40 * i, 5 * i]; //for nxt level, row score, p sore,
c = c + c;
}
},
setInfo: function (el) {
this[el + "Display"].innerHTML = this[el];
},
drawNextShape: function () {
var ns = [];
for (var i = 0; i < this.nextShape.length; i++) {
ns[i] = this.createSquare(
this.nextShape[i][0] + 2,
this.nextShape[i][1] + 2,
this.nextShapeIndex
);
}
this.nextShapeDisplay.innerHTML = "";
for (var k = 0; k < ns.length; k++) {
this.nextShapeDisplay.appendChild(ns[k]);
}
},
drawShape: function (x, y, p) {
for (var i = 0; i < p.length; i++) {
var newX = p[i][0] + x;
var newY = p[i][1] + y;
this.curSqs[i] = this.createSquare(newX, newY, this.curShapeIndex);
}
for (var k = 0; k 0) {
score += lines * this["level" + this.level][1];
this.incLines(lines);
}
if (shape === true) {
score += shape * this["level" + this.level][2];
}
/*if (speed > 0){ score += speed * this["level" +this .level[3]];}*/
this.incScore(score);
},
checkScore: function () {
if (this.score >= this["level" + this.level][0]) {
this.incLevel();
}
},
gameOver: function () {
this.clearTimers();
isStart = false;
this.canvas.innerHTML = "GAME OVER
";
},
play: function () {
var me = this;
if (this.timer === null) {
this.initTimer();
}
var gameLoop = function () {
me.move("D");
if (me.curComplete) {
me.markBoardShape(me.curX, me.curY, me.curShape);
me.curSqs.eachdo(function () {
me.sqs.push(this);
});
me.calcScore({ shape: true });
me.checkRows();
me.checkScore();
me.initShapes();
me.play();
} else {
me.pTimer = setTimeout(gameLoop, me.speed);
}
};
this.pTimer = setTimeout(gameLoop, me.speed);
this.isActive = 1;
},
togglePause: function () {
if (this.isActive === 1) {
this.clearTimers();
this.isActive = 0;
} else {
this.play();
}
},
clearTimers: function () {
clearTimeout(this.timer);
clearTimeout(this.pTimer);
this.timer = null;
this.pTimer = null;
},
move: function (dir) {
var s = "";
var me = this;
var tempX = this.curX;
var tempY = this.curY;
switch (dir) {
case "L":
s = "left";
tempX -= 1;
break;
case "R":
s = "left";
tempX += 1;
break;
case "D":
s = "top";
tempY += 1;
break;
case "RT":
this.rotate();
return true;
break;
default:
throw new Error("wtf");
break;
}
if (this.checkMove(tempX, tempY, this.curShape)) {
this.curSqs.eachdo(function (i) {
var l = parseInt(this.style[s], 10);
dir === "L" ? (l -= me.pSize) : (l += me.pSize);
this.style[s] = l + "px";
});
this.curX = tempX;
this.curY = tempY;
} else if (dir === "D") {
if (this.curY === 1 || this.time === this.maxTime) {
this.gameOver();
return false;
}
this.curComplete = true;
}
},
rotate: function () {
if (this.curShapeIndex !== 6) {
//square
var temp = [];
this.curShape.eachdo(function () {
temp.push([this[1] * -1, this[0]]);
});
if (this.checkMove(this.curX, this.curY, temp)) {
this.curShape = temp;
this.removeCur();
this.drawShape(this.curX, this.curY, this.curShape);
} else {
throw new Error("Could not rotate!");
}
}
},
checkMove: function (x, y, p) {
if (this.isOB(x, y, p) || this.isCollision(x, y, p)) {
return false;
}
return true;
},
isCollision: function (x, y, p) {
var me = this;
var bool = false;
p.eachdo(function () {
var newX = this[0] + x;
var newY = this[1] + y;
if (me.boardPos(newX, newY) === 1) {
bool = true;
}
});
return bool;
},
isOB: function (x, y, p) {
var w = this.boardWidth - 1;
var h = this.boardHeight - 1;
var bool = false;
p.eachdo(function () {
var newX = this[0] + x;
var newY = this[1] + y;
if (newX w || newY h) {
bool = true;
}
});
return bool;
},
getRowState: function (y) {
var c = 0;
for (var x = 0; x < this.boardWidth; x++) {
if (this.boardPos(x, y) === 1) {
c = c + 1;
}
}
if (c === 0) {
return "E";
}
if (c === this.boardWidth) {
return "F";
}
return "U";
},
checkRows: function () {
var me = this;
var start = this.boardHeight;
this.curShape.eachdo(function () {
var n = this[1] + me.curY;
console.log(n);
if (n = 0; y--) {
switch (this.getRowState(y)) {
case "F":
this.removeRow(y);
c++;
break;
case "E":
if (c === 0) {
stopCheck = true;
}
break;
case "U":
if (c > 0) {
this.shiftRow(y, c);
}
break;
default:
break;
}
if (stopCheck === true) {
break;
}
}
if (c > 0) {
this.calcScore({ lines: c });
}
},
shiftRow: function (y, amount) {
var me = this;
for (var x = 0; x < this.boardWidth; x++) {
this.sqs.eachdo(function () {
if (me.isAt(x, y, this)) {
me.setBlock(x, y + amount, this);
}
});
}
me.emptyBoardRow(y);
},
emptyBoardRow: function (y) {
for (var x = 0; x < this.boardWidth; x++) {
this.markBoardAt(x, y, 0);
}
},
removeRow: function (y) {
for (var x = 0; x < this.boardWidth; x++) {
this.removeBlock(x, y);
}
},
removeBlock: function (x, y) {
var me = this;
this.markBoardAt(x, y, 0);
this.sqs.eachdo(function (i) {
if (me.getPos(this)[0] === x && me.getPos(this)[1] === y) {
me.canvas.removeChild(this);
me.sqs.splice(i, 1);
}
});
},
setBlock: function (x, y, block) {
this.markBoardAt(x, y, 1);
var newX = x * this.pSize;
var newY = y * this.pSize;
block.style.left = newX + "px";
block.style.top = newY + "px";
},
isAt: function (x, y, block) {
if (this.getPos(block)[0] === x && this.getPos(block)[1] === y) {
return true;
}
return false;
},
getPos: function (block) {
var p = [];
p.push(parseInt(block.style.left, 10) / this.pSize);
p.push(parseInt(block.style.top, 10) / this.pSize);
return p;
},
getBoardIdx: function (x, y) {
return x + y * this.boardWidth;
},
boardPos: function (x, y) {
return this.board[x + y * this.boardWidth];
},
markBoardAt: function (x, y, val) {
this.board[this.getBoardIdx(x, y)] = val;
},
markBoardShape: function (x, y, p) {
var me = this;
p.eachdo(function (i) {
var newX = p[i][0] + x;
var newY = p[i][1] + y;
me.markBoardAt(newX, newY, 1);
});
},
isIE: function () {
return this.bTest(/IE/);
},
isFirefox: function () {
return this.bTest(/Firefox/);
},
isSafari: function () {
return this.bTest(/Safari/);
},
bTest: function (rgx) {
return rgx.test(navigator.userAgent);
},
};
const btn = document.querySelector("#start");
btn.addEventListener("click", function () {
btn.style.display = "none";
if (!isStart) {
tetris.init();
}
});
})();
if (!Array.prototype.eachdo) {
Array.prototype.eachdo = function (fn) {
for (var i = 0; i < this.length; i++) {
fn.call(this[i], i);
}
};
}
if (!Array.prototype.remDup) {
Array.prototype.remDup = function () {
var temp = [];
for (var i = 0; i < this.length; i++) {
var bool = true;
for (var j = i + 1; j < this.length; j++) {
if (this[i] === this[j]) {
bool = false;
}
}
if (bool === true) {
temp.push(this[i]);
}
}
return temp;
};
}
Output:

Disclaimer: The code provided in this post is sourced from GitHub and is distributed under the MIT License. All credits for the original code go to the respective owner. We have shared this code for educational purposes only. Please refer to the original repository for detailed information and any additional usage rights or restrictions.
TUI Expense Tracker Using Textual in Python Introduction: Managing money is a very important skill in life. But many people still use …
Educational Website using html CSS and JavaScript Introduction Hello friends, welcome to today’s new blog post. Today we have created a beautiful …
A Django-Based Gym Management System Introduction Managing a gym can be complicated because there are so many things to keep track of, …
how to create a video background with html CSS JavaScript Introduction Hello friends, you all are welcome to today’s new blog post. …