Learn Object-Oriented Programming In JavaScript by Creating Tetris (2)

Ravi da N.
6 min readMay 4, 2023

The goal of this time is to understand how to use new function and this, and take a step forward in understanding OOP.

Here is a link to articles in this series: Previous Article / Next Article

There are many websites that show a Tetris program using JavaScript. But there are few websites that create it using the OOP method. So I’m sure you will find this articles interesting.

We will continue to use the following tetris.html in this series, so please save it. When you run tetris.js, drop this tetris.html into your browser.

<!-- tetris.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Let's Master OOP!</title>
</head>
<body>
</body>
<script src="tetris.js"></script>
</html>

Now, save the file below as tetris.js.

// tetris.js
'use strict';

const divTitle = document.createElement('div');
divTitle.textContent = "TETRIS";
document.body.appendChild(divTitle);

const g = {
Px_BLOCK: 30,
Px_BLOCK_INNER: 28,

PCS_COL: 10,
PCS_ROW: 20,
PCS_FIELD_COL: 12,
}

const gFieldGfx = new function() {
const pxWidthField = g.Px_BLOCK * g.PCS_FIELD_COL;
const pxHeightField = g.Px_BLOCK * (g.PCS_ROW + 1);

const canvas = document.createElement('canvas');
canvas.width = pxWidthField;
canvas.height = pxHeightField;
document.body.appendChild(canvas);

const _ctx = canvas.getContext('2d');
_ctx.fillStyle = "black";
_ctx.fillRect(0, 0, pxWidthField, pxHeightField);

const yBtmBlk = g.Px_BLOCK * g.PCS_ROW;
const xRightBlk = pxWidthField - g.Px_BLOCK + 1;

_ctx.fillStyle = 'gray';
for (let y = 1; y < yBtmBlk; y += g.Px_BLOCK) {
_ctx.fillRect(1, y, g.Px_BLOCK_INNER, g.Px_BLOCK_INNER);
_ctx.fillRect(xRightBlk, y, g.Px_BLOCK_INNER, g.Px_BLOCK_INNER);
}

for (let x = 1; x < pxWidthField; x += g.Px_BLOCK) {
_ctx.fillRect(x, yBtmBlk + 1, g.Px_BLOCK_INNER, g.Px_BLOCK_INNER);
}

this.context2d = _ctx;
}

Drop tetris.html into your browser to run tetris.js. Could you see Fig.1?

Fig.1

I’ll describe the important parts of this program. JavaScript has a useful feature. If we follow Fig.2, z.A represents 10 and z.B represents 20.

Fig.2

Following Fig.3, we can represent the number of pixels of a block as g.Px_BLOCK. Tetris is a game with 10 columns and 20 rows, so g.PCS_COL is 10 and g.PCS_ROW is 20. And there is one block on each end of both the left and right sides, so g.PCS_FIELD_COL becomes 12.

Fig.3

Fig.2 and the following Fig.4 have the same meaning.

Fig.4: Same meaning as Fig.2

It seems easier to use the way of Fig.2, but Fig.4 is more useful if the value

of z.A is obtained after some operation. In fact, gFieldGfx sets the value of context2d after getting _ctx.

Set this.context2d after getting _ctx

Next, be sure to know the difference between let and const. Both let and const determine the name of the variable. We just use const for variables that is prohibited from reassignment and let for variables that is to be reassigned. yBtmBlk in L31 fo Fig.5 is a variable that is prohibited from reassignment. On the other hand, y in L34 is reassigned to the result of y + g.Px_BLOCK.

Fig.5

The program works correctly if you use only let. However, const can reduce the mistakes related to wrong reassignments, so it should be used proactively.

You should know another way to write new function. Please add the program below to tetris.js. You can have it added under gFieldGfx.

function MinoGfx(color, pxpos8) {
const _ctx = gFieldGfx.context2d;
const _color = color;
const _pxpos8 = pxpos8;

this.draw = () => {
_ctx.fillStyle = _color;
for (let idx = 0; idx < 8; idx += 2) {
_ctx.fillRect(_pxpos8[idx] + 1, _pxpos8[idx + 1] + 1
, g.Px_BLOCK_INNER, g.Px_BLOCK_INNER);
}
}
}

const t_mino = new MinoGfx('magenta', [90, 0, 60, 30, 90, 30, 120, 30]);
t_mino.draw();

Run tetris.js. Could you see the T-mino as shown in Fig.6?

Fig.6: T-mino appears!

You can get the same functionality as new function by using a function MinoGfx and then executing new MinoGfx, as in the program you just added. Using this writing style, you can pass arguments easily just as you would for a general function when executing new function.

In JavaScript, as in most programming languages, arrays can be handled using [ ]. The array [90, 0, 60, 30, …] above represents the coordinates of the T-mino blocks.

In the program we created now, gFieldGfx is responsible for drawing the game field and MinoGfx is responsible for drawing a mino.

It is most essential for the OOP architecture to adopt the notion of designing a system that specifies roles and responsibilities. We should build objects that have specific roles and responsibilities in a program.

For example, supposing that you also want to draw O-mino, you should consider creating an object that has the role to draw O-mino. The program you should create is as follows.

const o_mino = new MinoGfx('yellow', [180, 0, 210, 0, 180, 30, 210, 30]);
o_mino.draw();
O mino also appears!

OOP is widely used in modern software development. The reason for this is that this approach is the same as how social life works in the real world.

For instance, a manager has a manager’s job, a programmer has a programmer’s job, and they do their own work. Now, we have achieved exactly the same thing with our program. We just created a new o_mino, which is the same as hiring a new programmer. gFieldGfx does the job of drawing the game field, t_mino does the job of drawing the T-mino, and o_mino does the job of drawing the O-mino.

The central idea of OOP is to put the social structure into the program world. It is sometimes mistakenly believed that using classes and inheritance is OOP, but that is not the case. OOP is easy to understand because all you have to do is think about your own daily life.

Once your role has been determined and your job has been assigned, the tools you will need for the job will be determined. Look inside { } of the program that defines MinoGfx. Notice variables prefixed with _. Actually, those are the tools forMinoGfx. In order to display the mino, it needs a context in which to draw 2D image and information on the color of the mino, so it has _ctx and _color as work-tools.

Such variables are called member variables. It means that along with those variables, an object can do the assigned job for it.

That is all I wanted to tell you about OOP in this article. I will provide a brief explanation about the program that we’ve created this time.

Arrow Function

In JavaScript, functions of the form ( ) => { } are commonly used. For example, we represent a function that adds two numbers as follows.

If you want to name this function, name it with const as follows.

In function, you can also name it using this, as in the program we’ve created this time.

I will make every effort to help you understand OOP better. Thanks for reading this article.

--

--

Ravi da N.

C++, C# developer. I'm happy to help so many people enjoy programming. I'd also like to share a lot of knowledge about the program!