What I learnt building Tetris in vanilla JS
3 min read

What I learnt building Tetris in vanilla JS

What I learnt building Tetris in vanilla JS

Tetris might seem like a simple enough game upfront. It's easy to understand and simple to play, but that's exactly what makes it challenging to build. There are many nuances to consider that only come to light when actually building the game. The most challenging part I faced was making sure that the pieces don't go off screen or overlap other 'fixed pieces' when rotating.

Staying within the view
Finding the space to rotate

Each piece, or sigil as I like to call them, is made of a 4x4 grid. The green cells that are 'solid' and have a value of '1'. The cells with the value '0' don't get rendered in the final production, but I've coloured them a translucent grey to demonstrate the grid concept in these gifs. Below is the code for the mirrored "L" piece in the first gif above.

[
    [0],[0],[1],[0],
    [0],[0],[1],[0],
    [0],[1],[1],[0],
    [0],[0],[0],[0]
]

To add my own twist to the game, I made a 'bomb' sigil which explodes and destroys other blocks in a 1 cell radius. This made the gameplay more interesting than I imagined. Sometimes they helpfully get you out of a sticky situation, but sometimes, they force you to demolish what you tried to carefully build making it harder to clear rows.

Drop the bomb!

Below we have code that rotates the sigil. It might seem a bit daunting at first, but all it does is just shift the 1's and 0's around. Well, first it checks if the sigil is a bomb. Since bombs are only 1x1, we don't want to rotate it. Then, it creates a temporary sigil (tempSigil) to calculate where the real sigil (_currSigil) would be AFTER it's rotated. And if calculations return that the temporary sigil isn't restricted by other fixed blocks, we set the real sigil to the temporary one.

var _rotate = function() {
    if(_bomb) return; // Do not rotate if it's a bomb
    var tempSigil = [];
    var i = 0;
    tempSigil.length = _currSigil.length;
    
    for (i = 0; i < _currSigil.length; i++) {
        var x = i % _row;
        var y = Math.floor(i/_row);
        var newX = _row - y - 1;
        var newY = x;
        var newIndex = newY * _row + newX;
        tempSigil[newIndex] = _currSigil[i];
    }
        
    // Only rotate if the sigil has space to rotate
    if(_hasSpaceToBe(tempSigil)) {
        _currSigil = tempSigil;
    }
};

While I learnt a lot from this exercise, like the proper way to build a game-loop, handle multiple scenes and build a Finite State Machine, my initial main aim of building a Tetris clone was to improve my understanding of various design patterns, decoupling and abstraction in Javascript. I built the game in a highly decoupled way, where every 'module' or piece of the game only knows about each other and a 'game core'. Here's where the Observer and Interface pattern come in handy. The modules never talk with each other, so if any one of them break, the rest stay intact, making it easy to debug and also to extend the functionality of the game. I won't go into those details in this article, but you can get the sourecode on Github.
To all junior developers serious about improving their code skills in any Object Oriented Language, I highly recommend

All of them are available online for free and have immense amounts of information about building large scale applications and games. These articles made a big impact on my skills as a junior developer and I'm greatly thankful to them for it.

Alright, time to PLAY THE GAME. Enjoy!