Tetris, in TypeScript
With the intention of getting more familiarized with TypeScript, I decided to start a new project. It’s been many years since the last time I made a game from scrath so it seemed fitting to give that a go. I chose Tetris because it’s a well known game, with a defined set of problems and functionality. All I had to worry about was to code their solutions.
The TypeScript Lesson
I did get more familiar with TypeScript, some of its strengths, caveats and tooling. Still, it would be hard (or overengineered) to cover all of the language features in a project. One important feature I left out is generics, perhaps I need to start working on Space Invaders now so I can give it a try?
Implementation Details
I tried to keep it as lean as possible, therefore this is the tech I used:
- TypeScript 🪛
- HTML Canvas and CSS for drawing and coloring 🎨
- Webpack for bundling everything 📦
Favorite part
The most fun part of the project was to write the function to create the possible rotations for each piece. I could have used a hard-coded two dimensional array with all of them in there but where’s the fun in that?i Another downside of that approach is that I would have to limit the shapes of Tetris pieces I could use. Thanks to this function, I can create my custom shaped Tetris pieces! Anyway, here’s the function:
1 generateRotations(): Cell[][][] {
2 let rots: Cell[][][] = []
3 let nextBase: Cell[][]
4
5 for (let rotationCounter = 0; rotationCounter < 4; rotationCounter++) {
6 rots[rotationCounter] = new BlankPiece(this.rows, this.columns).shape
7 let destY = this.columns - 1
8 for (let i = 0; i < this.columns; i++) {
9 let destX = 0
10 for (let j = 0; j < this.rows; j++) {
11 if (!nextBase) {
12 rots[rotationCounter][destY][destX] = this.shape[j][i]
13 } else {
14 rots[rotationCounter][destY][destX] = nextBase[j][i]
15 }
16 destX++
17 }
18 destY--
19 }
20 nextBase = rots[rotationCounter]
21 }
22 return rots
23 }I enjoyed working on this function because I had to keep track of how the Tetris piece was moving on every iteration at the cell level. It also forced me to initialize the rots array with a BlankPiece. This is an object that extends Piece. Initializations of the same type aren’t required in JavaScript but they are in TypeScript. It was a nice reminder that I had to think about the type system once again.
Demo
Game available here (limited mobile support because that was out of the scope 😆)
