Back to Tetris Game

Documentation

A comprehensive guide to the Tetris game implementation with modern React and smooth animations

1. Game Overview

This Tetris implementation is built with React and features modern animations, smooth gameplay, and a responsive design. The game follows classic Tetris rules with all seven standard tetrominoes and includes features like ghost pieces, line clearing, and progressive difficulty.

Key Features

  • Seven Tetromino Shapes: I, O, T, L, J, S, and Z pieces
  • Ghost Piece: Preview where the current piece will land
  • Line Clearing: Complete horizontal lines are removed
  • Progressive Difficulty: Speed increases every 10 lines
  • Scoring System: Points for soft drop, hard drop, and line clears
  • Modern UI: Smooth animations and responsive design
  • Local Storage: High score persistence

Scoring System

  • Soft Drop: 1 point per cell
  • Hard Drop: 2 points per cell
  • Single Line: 40 × level
  • Double Line: 100 × level
  • Triple Line: 300 × level
  • Tetris (4 lines): 1200 × level

2. Game Mechanics

Tetromino Pieces

The game includes all seven standard Tetris pieces, each with distinct shapes and rotation patterns:

Tetromino Definitions
1const SHAPES = [ 2 [[1, 1, 1, 1]], // I-piece (Cyan) 3 [[1, 1], [1, 1]], // O-piece (Yellow) 4 [[1, 1, 1], [0, 1, 0]], // T-piece (Purple) 5 [[1, 1, 1], [1, 0, 0]], // L-piece (Orange) 6 [[1, 1, 1], [0, 0, 1]], // J-piece (Blue) 7 [[1, 1, 0], [0, 1, 1]], // S-piece (Green) 8 [[0, 1, 1], [1, 1, 0]] // Z-piece (Red) 9];

Collision Detection

The collision system checks for boundary violations and overlaps with placed pieces:

Collision Detection
1const checkCollision = (piece, position, boardToCheck = board) => { 2 if (!piece) return true; 3 4 for (let y = 0; y < piece.shape.length; y++) { 5 for (let x = 0; x < piece.shape[y].length; x++) { 6 if (piece.shape[y][x]) { 7 const newX = position.x + x; 8 const newY = position.y + y; 9 10 // Check boundaries 11 if (newX < 0 || newX >= COLS || newY >= ROWS) { 12 return true; 13 } 14 15 // Check overlap with existing pieces 16 if (newY >= 0 && boardToCheck[newY][newX].value) { 17 return true; 18 } 19 } 20 } 21 } 22 return false; 23};

Line Clearing Algorithm

When lines are completed, they are removed and new empty lines are added at the top:

Line Clearing
1// Check for completed lines 2let completedLines = []; 3newBoard.forEach((row, y) => { 4 if (row.every(cell => cell.value)) { 5 completedLines.push(y); 6 } 7}); 8 9// Remove completed lines 10if (completedLines.length > 0) { 11 completedLines.forEach(lineY => { 12 newBoard.splice(lineY, 1); 13 newBoard.unshift(Array(COLS).fill({ value: 0, color: null })); 14 }); 15 16 // Calculate score 17 const points = [0, 40, 100, 300, 1200][completedLines.length] * level; 18 setScore(prev => prev + points); 19}

3. Implementation Details

Game Loop

The game uses setInterval to create a continuous game loop that drops pieces automatically:

Game Loop
1useEffect(() => { 2 if (gameState !== 'playing') return; 3 4 const gameLoop = setInterval(() => { 5 if (!movePiece(0, 1)) { 6 lockPiece(); 7 } 8 }, dropIntervalRef.current); 9 10 gameLoopRef.current = gameLoop; 11 return () => clearInterval(gameLoop); 12}, [gameState, movePiece, lockPiece, level]);

Piece Movement

All piece movements go through collision detection before being applied:

Movement System
1const movePiece = useCallback((dx, dy) => { 2 if (!currentPiece || gameState !== 'playing') return false; 3 4 const newPosition = { x: currentPosition.x + dx, y: currentPosition.y + dy }; 5 6 if (!checkCollision(currentPiece, newPosition)) { 7 setCurrentPosition(newPosition); 8 return true; 9 } 10 return false; 11}, [currentPiece, currentPosition, checkCollision, gameState]);

4. State Management

React State Structure

The game manages multiple pieces of state using React hooks:

State Variables
1// Board and piece state 2const [board, setBoard] = useState(initialBoard); 3const [currentPiece, setCurrentPiece] = useState(null); 4const [currentPosition, setCurrentPosition] = useState({ x: 0, y: 0 }); 5const [nextPiece, setNextPiece] = useState(null); 6 7// Game statistics 8const [score, setScore] = useState(0); 9const [level, setLevel] = useState(1); 10const [lines, setLines] = useState(0); 11 12// Game flow control 13const [gameState, setGameState] = useState('ready'); 14const [highScore, setHighScore] = useState(0);

High Score Persistence

High scores are saved to localStorage for persistence across sessions:

localStorage Integration
1const [highScore, setHighScore] = useState(() => { 2 if (typeof window !== 'undefined') { 3 return parseInt(localStorage.getItem('tetrisHighScore') || '0'); 4 } 5 return 0; 6}); 7 8// Save new high score 9if (score > highScore) { 10 setHighScore(score); 11 localStorage.setItem('tetrisHighScore', score.toString()); 12}

5. Rendering System

Block Rendering

Each block is rendered with absolute positioning and gradient colors:

Block Component
1<motion.div 2 key={`${x}-${y}`} 3 initial={{ scale: 0 }} 4 animate={{ scale: 1 }} 5 className={cn( 6 "absolute rounded-sm bg-gradient-to-br shadow-lg", 7 "border border-white/20", 8 cell.color 9 )} 10 style={{ 11 left: `${x * BLOCK_SIZE}px`, 12 top: `${y * BLOCK_SIZE}px`, 13 width: `${BLOCK_SIZE - 2}px`, 14 height: `${BLOCK_SIZE - 2}px`, 15 }} 16/>

Ghost Piece Rendering

The ghost piece shows where the current piece will land with reduced opacity:

Ghost Piece
1{currentPiece && ghostPosition && gameState === 'playing' && ( 2 currentPiece.shape.map((row, y) => 3 row.map((value, x) => value ? ( 4 <div 5 key={`ghost-${x}-${y}`} 6 className="absolute rounded-sm border-2 border-white/20 opacity-20" 7 style={{ 8 left: `${(ghostPosition.x + x) * BLOCK_SIZE}px`, 9 top: `${(ghostPosition.y + y) * BLOCK_SIZE}px`, 10 width: `${BLOCK_SIZE - 4}px`, 11 height: `${BLOCK_SIZE - 4}px`, 12 }} 13 /> 14 ) : null) 15 ) 16)}

6. Controls & Input

Keyboard Event Handling

The game listens for keyboard events and prevents default browser behavior:

Input Handler
1const handleKeyPress = (e) => { 2 if (gameState !== 'playing') return; 3 4 switch (e.key) { 5 case 'ArrowLeft': 6 e.preventDefault(); 7 movePiece(-1, 0); 8 break; 9 case 'ArrowRight': 10 e.preventDefault(); 11 movePiece(1, 0); 12 break; 13 case 'ArrowDown': 14 e.preventDefault(); 15 if (movePiece(0, 1)) { 16 setScore(prev => prev + 1); 17 } 18 break; 19 case 'ArrowUp': 20 e.preventDefault(); 21 rotatePiece(); 22 break; 23 case ' ': 24 e.preventDefault(); 25 hardDrop(); 26 break; 27 } 28};

Control Mapping

Keyboard Controls

Move Left
Move Right
Soft Drop
Rotate
SpaceHard Drop

This documentation covers the complete implementation of the Tetris game. The source code demonstrates modern React patterns, state management, and game development concepts.