Build Tetris using React Native and Expo

Lesson 6 of 8

Scoring, Levels, and Game Over

A line-clearing board isn't quite a full game yet, it needs a score, a sense of progression as levels speed things up, and a way to know when it's over.

Classic scoring

const LINE_SCORES = [0, 100, 300, 500, 800]; // index = number of lines cleared at once

function scoreForLines(linesCleared: number, level: number): number {
  return LINE_SCORES[linesCleared] * (level + 1);
}

Clearing 4 lines at once (a Tetris, the move the game is named after) is worth far more than 4x a single line (800 vs. 100), this is deliberate in the original game design, it rewards setting up multi-line clears instead of clearing lines one at a time. Multiplying by (level + 1) makes higher levels worth more points for the same clear, on top of the game already being faster and harder there.

Leveling up and speeding up

function levelForLines(totalLinesCleared: number): number {
  return Math.floor(totalLinesCleared / 10); // level up every 10 lines
}

function speedForLevel(level: number): number {
  return Math.max(100, 1000 - level * 75); // ms per tick, capped so it never gets impossibly fast
}

speedForLevel feeds directly into the useGameLoop hook's speedMs from the game loop lesson, as level climbs, the interval between ticks shrinks, gravity pulls pieces down faster. Math.max(100, ...) puts a floor on how fast it can get, without it, the formula would eventually produce a negative or absurdly tiny interval.

Detecting game over

function isGameOver(board: Matrix, newPiece: ActivePiece): boolean {
  return hasCollision(board, newPiece, newPiece.row, newPiece.col);
}

The game is over the instant a freshly spawned piece already collides with something at its starting position, meaning the stack has reached all the way to the top, there's nowhere left to put a new piece. Check this right after spawning each new piece in the tick handler from the previous lesson, before letting the game loop continue.

const nextPiece = spawnPiece(randomShapeName());
if (isGameOver(clearedBoard, nextPiece)) {
  // stop the interval, show a game over screen
}

TIP

Track totalLinesCleared as a running total across the whole game (not just the current tick), levelForLines needs the cumulative count to know when a level threshold has actually been crossed.

📝 Scoring and Game Over Quiz

Passing score: 70%
  1. 1.Why is clearing 4 lines at once (800 points) worth more than 4x a single line clear (4 x 100 = 400)?

  2. 2.The game is detected as over the instant a freshly spawned piece already collides with the board at its starting position.

  3. 3.Math.max(100, 1000 - level * 75) puts a ____ on how fast the tick speed can get as the level increases.