JavaScript Tutorial: Build Tetris with modern JavaScript
Tags: javascript, gamedev, tutorial, beginners
Published: 2021-05-14 16:03:58

Learning a new programming language is difficult and not everyone learns the same way. For many, hands-on exploration on a project or interactive tutorial is the key to lasting learning.
 
Especially for intuitive languages like JavaScript, building projects helps to provide context for how and why to use fundamental concepts in different applications. It also helps build your resume because you can show recruiters a collection of awesome projects to demonstrate your drive and developer skills.
 
Today, we'll help you get started on a JavaScript game development project to build Tetris. By the end of the article, you'll have all the foundational pieces you need to continue building on your own.
 
**Here’s what we’ll cover today:**
 
* [What is Tetris?](#what)
* [Styling the game](#styling)
* [Designing the board](#designing)
* [Creating the canvas](#canvas)
* [Next steps for your game](#next)


<br>
 
<h4><b> Learn JavaScript your way, in half the time</b></h4>
 
Pick up modern JavaScript skills while building a fun and fully featured project for your portfolio.
 
<b>[Game Development with JavaScript: Creating Tetris](https://www.educative.io/courses/game-development-js-tetris)</b>
<br>
 
<a name="what"></a>

## What is Tetris?
 
Tetris is a classic arcade game created in 1984 by Alexey Pajitnov. The game requires players to rotate and move falling Tetris pieces. Players clear lines by completing horizontal rows of blocks without empty cells. If the pieces reach the top, the game is over.

Tetris is a popular project that lets aspiring game developers practice their skills in a simple environment. For example, you'll get hands-on practice with essential game design concepts, such as gameplay loop design, and implementing common game mechanics like user controls, score tracking, and collision detection. Unlike more complicated games, the behavior and visuals for Tetris are very simple. This lets you practice applying JavaScript basics for game development rather than figuring out animation or complex player behavior flowcharts.

For this example, we'll start by using the simplest tools and build the complexity towards the end.

To make Tetris, you'll need to know:
- [HTML](https://www.educative.io/blog/html-beginners-tutorial-build-from-scratch)/[CSS](https://www.educative.io/blog/beginner-guide-to-web-dev#basics) styling
- JavaScript classes, variables, and scope
- Arrow functions
- Template literals
- Spread vs Rest
- Destructuring

<br>
 
<a name="styling"></a>

## Styling the game
First, let's set up the basic UI elements: the play area, a start button, and readouts to track score, lines, and level. We'll use [Flexbox](https://www.educative.io/blog/css-flexbox) and [CSS Grid](https://www.educative.io/blog/complete-guide-css-positions) to position the elements correctly.

```html
<!-- index.html -->
<div class="grid">
  <canvas id="board" class="game-board"></canvas>
  <div class="right-column">
    <div>
      <h1>TETRIS</h1>
      <p>Score: <span id="score">0</span></p>
      <p>Lines: <span id="lines">0</span></p>
      <p>Level: <span id="level">0</span></p>
      <canvas id="next" class="next"></canvas>
    </div>
    <button onclick="play()" class="play-button">Play</button>
  </div>
</div>
```

```css
// styles.css
.grid {
  display: grid;
  grid-template-columns: 320px 200px;
}

.right-column {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.game-board {
  border: solid 2px;
}
 
.play-button {
  background-color: #4caf50;
  font-size: 16px;
  padding: 15px 30px;
  cursor: pointer;
}
```

A fundamental part of 80s games was the highly recognizable bitmap font. **Press start 2P** is a free font from Google we can use to simulate the feeling. 

To add the font, we need to link to it in the `<head>` section of our HTML document and set it to our desired font in the CSS style sheet.

```html
 <!--index.html-->
<link
  href="https://fonts.googleapis.com/css?family=Press+Start+2P"
  rel="stylesheet"
/>
```
```css
// styles.css
* {
  font-family: 'Press Start 2P', cursive;
}
```

Finally, code the infrastructure of the game board using JavaScript.
You'll need to add  `<script>` elements at the end of our HTML document to import our JavaScript. 

The bottom of your HTML document should look like this:

```html
    <script type="text/javascript" src="constants.js"></script>
    <script type="text/javascript" src="board.js"></script>
    <script type="text/javascript" src="piece.js"></script>
    <script type="text/javascript" src="main.js"></script>
  </body>
</html>
```
`constants.js` will contain the code for our static play board. These values will never change regardless of player actions. The playboard will consist of 10 columns and 20 rows, with a block size of 30.

```js
//constants.js
const COLS = 10;
const ROWS = 20;
const BLOCK_SIZE = 30;
```

Then, in the `main.js` file we'll include some code to manipulate the document `object`, which provides a programmable interface for the HTML document. This type of document is called a **Document Object Model (DOM)**.

We can use the DOM to call the `getElementByID` to let us target specific elements and automatically scale our game to match the size of the user's browser window. This uses the `canvas` element new with HTML5, which allows us to create and use 2D shapes with ease.

The `main.js` file should look like this:

```js
//main.js
const canvas = document.getElementById('board');
const ctx = canvas.getContext('2d');

// Calculate size of canvas from constants.
ctx.canvas.width = COLS * BLOCK_SIZE;
ctx.canvas.height = ROWS * BLOCK_SIZE;

// Scale blocks
ctx.scale(BLOCK_SIZE, BLOCK_SIZE);
```

By the end, you'll have the following files:

```html
<!--index.html-->
<html>
<head>
  <link
href="https://fonts.googleapis.com/css?family=Press+Start+2P"
rel="stylesheet"
/>
</head>

<body>

  <div class="grid">
    <canvas id="board" class="game-board"></canvas>
    <div class="right-column">
      <div>
        <h1>TETRIS</h1>
        <p>Score: <span id="score">0</span></p>
        <p>Lines: <span id="lines">0</span></p>
        <p>Level: <span id="level">0</span></p>
        <canvas id="next" class="next"></canvas>
      </div>
      <button onclick="play()" class="play-button">Play</button>
    </div>
  </div>

</body>
```

```js
//main.js
const canvas = document.getElementById('board');
const ctx = canvas.getContext('2d');
 
// Calculate size of canvas from constants.
ctx.canvas.width = COLS * BLOCK_SIZE;
ctx.canvas.height = ROWS * BLOCK_SIZE;
 
// Scale blocks
ctx.scale(BLOCK_SIZE, BLOCK_SIZE);
```

```js
//constants.js
const COLS = 10;
const ROWS = 20;
const BLOCK_SIZE = 30;
```

```css
//styles.css
* {
  font-family: 'Press Start 2P', cursive;
}
 
.grid {
  display: grid;
  grid-template-columns: 320px 200px;
}
 
.right-column {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
 
.game-board {
  border: solid 2px;
}
 
.play-button {
  background-color: #4caf50;
  font-size: 16px;
  padding: 15px 30px;
  cursor: pointer;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/28mwy40kn0u9sun64d30.PNG)

<br>

<div style="background-color:#F1F1FF;padding-left: 10px;padding-top:1px;padding-bottom:1px;">

#### Keep learning JS with hands-on projects.

Learn in-demand JavaScript skills without the bookwork. Educative's text-based courses are easy to skim and feature hands-on project environments to help you learn your way, in half the time.

<b>[Game Development with JavaScript: Creating Tetris](https://www.educative.io/courses/game-development-js-tetris)</b>

</div>

<br>
 
<a name="designing"></a>

## Designing the board
Now that we have created a container for our game, it’s time to start coding the logic. First, we need the board to be able to draw the falling pieces and keep track of the game state.

The board and pieces are both good candidates for a class. We can create a new instance of `Board` when starting a new game and a new instance of `Piece` every time a new piece enters the game.

For the `Board` class, we'll make a new `board.js` file. We want the board to reference the canvas every time the game starts so we'll include `ctx` in the `Board` constructor. We'll also include the `this` keyword to let us set and access properties within `ctx`.

```js
//board.js
class Board { 
  constructor(ctx) {
    this.ctx = ctx;    
  } 
}
```

Tetris boards consist of many individual cells that are either empty or occupied. We'll represent empty cells with `0` and occupied cells with integers of `1-7` to represent colors.

To represent the rows and columns of the board, we'll use a 2D array (a matrix). We'll have arrays of integers to represent a row and an array of rows to represent the full board. 

Since all games start with an empty board, we'll need a method that returns an empty board. We can use the built-in `fill()` array method to populate all elements of each row to `0`. The constructor will call this method so all games start empty.

Our `board.js` file will now look like this:

```js
//board.js
class Board { 
  constructor(ctx) {
    this.ctx = ctx;
    this.grid = this.getEmptyBoard();
  }
 
  getEmptyBoard() {
    return Array.from(
      {length: ROWS}, () => Array(COLS).fill(0)
    );
  }
}
```


Finally, we'll go back to `main.js` to add this new game functionality to the play button.

```js
function play() {
  board = new Board(ctx);
  console.table(board.grid);
}
```

Now our game board is set up! You can use `console.table()` to see the matrix that controls the board. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tr94v1negl9x0va4st1.PNG)

<br>
 
<a name="canvas"></a>

## Creating the canvas
Now we'll make sure our `canvas` element is ready to use. The canvas provides a blank canvas for our game to sit on. 

We can also add a 2D drawing context over the canvas for drawing shapes, text, images, and other objects. It works similarly to programs like MS Paint in that you can choose your brush type and color then draw using code. 

First, we want to make sure the canvas is the right size. It is 300x150 pixels by default but we want it to scale using the code we added above.

To do so, we add a `canvas` element to our `index.html`:

```html
<canvas id="canvas"></canvas>
```

Then add a reference to the HTML `<canvas>` element element in the DOM (Document Object Model) using the `getElementById` method.
 
```js
let canvas = document.getElementById('canvas');
```

Now we'll use the canvas context to render some pieces. 

We can use the `HTMLCanvasElement.getContext()` method to get the canvas context where we render the graphics. This method needs an argument so we'll pass `'2d'` to get the 2D render context.
```js
let ctx = canvas.getContext('2d');
```

Before we can draw we have to choose a color using the `fillStyle()` method.

```js
ctx.fillStyle = 'red';
```

We can then use the `fillRect()` method from the context API to draw a simple rectangle filled with our chosen red color. `fillRect()` takes 4 arguments: the x and y coordinates where the shape should start and the width/height of the rectangle.

```js
ctx.fillRect(x, y, width, height);
```
Since all Tetris pieces are collections of squares, we can use this single draw method for all of our pieces!

<br>

### Animations

Now that we have the tools to draw our graphics, we have to be able to move them.

Canvas uses **immediate rendering**: Drawn shapes are immediately rendered on the screen, but are not stored as shape objects. Instead, canvas only recognizes the shape as filled pixels, meaning we cannot move the shape in one piece. 

To show a moving shape, we have to delete the old shape using `clearRect()`  and redraw it in a new position using `fillRect()`. Canvas animations are essentially like stop motion animation because they move a little bit in each frame. 

Take a look at this example:

```js
const {width, height} = this.ctx.canvas;
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, 10, 10);
ctx.clearRect(0, 0, width, height);
ctx.fillRect(1, 1, 10, 10);
```

Here, we select blue as our color then fill a rectangle at point `0,0`. Then we clear the whole canvas using `clearRect()` and passing the width and height of the whole canvas. Finally, we draw a new rectangle of the same size and color at `1,1`. 

From the user's perspective, the rectangle moved down and to the right on the screen.


Now that you've got your canvas and drawing tools set up, you've got all the tools you need to start coding gameplay and a collection of game pieces!


<br>
 
<a name="next"></a>

## Next steps for your game
 
This is a great start to your next portfolio project. Now that you've built the foundation of the game, your next step is to create objects that draw each unique Tetris game piece in its own color. 

Each piece type will be represented by a 3x3 matrix where the piece is the filled cells and the surrounding empty space helps to rotate around the central cell.

```
[2, 0, 0],  
[2, 2, 2],  
[0, 0, 0];
```

The best way to do this is with a `Piece` class.

You'll also have to add keyboard support so the user can control the pieces. The best way to do this is to use keyboard event support built-in to modern browsers. You can set the program to listen for keyboard events like `keydown`, `keyup`, and so on at the document level using the `addEventListener()` method.

After these steps, you'll move onto adding more advanced features like:

- Add collision detection and piece randomizer
- Add line clearing if a row is filled
- Track score, level, and past high scores
- Increase responsiveness with asynchronous JavaScript


To help complete this project and learn JavaScript with hands-on experience, Educative has created the course [**Game Development with JavaScript: Creating Tetris**](https://www.educative.io/courses/game-development-js-tetris). This course helps you pick up foundational skills in JavaScript and game development at the same time by building a fun browser game. By the end of the course, you'll have a fully-featured Tetris web game and will have gained experience with JavaScript skills from beginner to advanced.

*Happy learning!*


<br>
 
### Continue reading about JavaScript
- [JavaScript Snake Game Tutorial: build a simple, interactive game](https://www.educative.io/blog/javascript-snake-game-tutorial)
- [Level up your JavaScript skills with 10 coding challenges](https://www.educative.io/blog/level-up-javascript-coding-challenges)

- [JavaScript ES6 Tutorial: A complete crash course on modern JS](https://www.educative.io/blog/javascript-es6-tutorial-a-complete-crash-course)