Tetris is a classic puzzle game where the player arranges falling blocks (Tetriminoes) to form complete rows. When a row is fully filled, it disappears, and the player earns points. The game gets progressively faster, increasing difficulty over time.
Basic Rules of Tetris
Tetriminoes Fall: Randomly generated blocks (Tetriminoes) fall from the top of the game area.
Player Control: The player can move left, move right, rotate, or soft drop the block.
Goal: Arrange blocks to form full horizontal lines.
Line Clearing: A completed row disappears, and the blocks above shift down.
Scoring System: Points increase with each cleared line.
Speed Increase: As the game progresses, the blocks fall faster.
Game Over: The game ends if a new block cannot spawn at the top.
The Tetris game follows a structured flow, where the ESP32 manages the game logic, the LCD I2C screen displays the game grid, the joystick controls the blocks, and the buzzer provides audio feedback
The game follows these main steps:
1- Initialization: The ESP32 sets up the display, joystick, and buzzer.
2- Block Spawning: A new Tetrimino (block) appears at the top of the grid.
3- Player Input: The joystick is used to move and rotate the block.
4- Block Movement: The block moves down automatically at a set interval.
5- Collision Detection: Checks if the block hits another block or the bottom.
6- Line Clearing: If a row is full, it is cleared, and the score increases.
7- Game Over Check: If new blocks cannot spawn, the game ends.
8- Repeat Steps 2-7 until the game is over.
ESP32 Board
The ESP32 is the microcontroller that will run the Tetris logic, handle input from the joystick, update the display, and play sounds through the buzzer.
It provides multiple GPIO pins to interface with peripherals.
Supports I2C communication for the LCD screen.
Has enough processing power and memory to manage game logic efficiently.
LCD I2C Screen
The LCD screen will serve as the display for the game, showing falling Tetriminoes and the game grid.
Typically, a 16x2 LCD (1602) or 20x4 LCD (2004) can be used.
It communicates via I2C protocol, reducing the number of GPIO pins required.
It uses libraries like i2c_lcd
and lcd_api
for display management.
Joystick (Controller)
The joystick is used to control the falling Tetriminoes.
It moves the blocks left or right by tilting left or right.
It moves the block down faster (soft drop) by tilting down.
It rotates the block when the joystick button is pressed.
It Connects to ESP32 via analog inputs (X & Y axes) and a digital button press.
Buzzer (Sound Effects)
The buzzer is used to play simple sound effects for: block movement, rotation, line clearing and game over.
Breadboard
Purpose: Used to assemble and connect components without soldering.
Jumper Wires
Jumper wires will be used to make connections between the components.
1- Joystick to ESP32 :
GND → GND
VCC → 3V3
X-axis (VRx pin ) → GPIO34
Y-axis (VRy pin) → GPIO35
Button (SW pin) → GPIO33
LCD Screen (I2C-based) to ESP32 :
SDA → GPIO21 (I2C Data).
SCL → GPIO22 (I2C Clock).
VCC → 5V
GND → GND
Tle Micropython program is a simplified version due to the limitations of a character-based LCD, where Tetriminoes are represented using custom characters.
This script handles game logic, LCD updates, joystick input, and buzzer sounds.
1- Ensure MicroPython is installed on your ESP32
2- Flash your ESP32 with MicroPython using this file esp32-20210902-v1.17.bin
3- Import this two libraries : i2c_lcd and lcd_api for I2C LCD screen
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
from machine import Pin, I2C, ADC, PWM import time import random from lcd_api import LcdApi from i2c_lcd import I2cLcd # ==== LCD SETUP (16x2 or 20x4) ==== I2C_ADDR = 0x27 # LCD I2C Address i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=400000) lcd = I2cLcd(i2c, I2C_ADDR, 16, 2) # Change to (20,4) for 20x4 LCD # ==== JOYSTICK SETUP ==== joy_x = ADC(Pin(34)) # X-axis joy_y = ADC(Pin(35)) # Y-axis button = Pin(32, Pin.IN, Pin.PULL_UP) # Button # ==== BUZZER SETUP ==== buzzer = PWM(Pin(15)) def beep(freq=1000, duration=0.1): buzzer.freq(freq) buzzer.duty(512) time.sleep(duration) buzzer.duty(0) # ==== GAME VARIABLES ==== GRID_WIDTH = 8 # Limited due to LCD constraints GRID_HEIGHT = 16 grid = [[0] * GRID_WIDTH for _ in range(GRID_HEIGHT)] current_tetrimino = None current_x, current_y = 3, 0 # ==== TETRIMINO SHAPES ==== TETRIMINOES = [ [[1, 1, 1, 1]], # I [[1, 1], [1, 1]], # O [[0, 1, 0], [1, 1, 1]], # T [[1, 0], [1, 0], [1, 1]], # L [[0, 1], [0, 1], [1, 1]], # J [[0, 1, 1], [1, 1, 0]], # S [[1, 1, 0], [0, 1, 1]], # Z ] def new_tetrimino(): global current_tetrimino, current_x, current_y current_tetrimino = random.choice(TETRIMINOES) current_x, current_y = 3, 0 if not is_valid_position(current_tetrimino, current_x, current_y): return False # Game Over return True def is_valid_position(shape, x, y): for row_idx, row in enumerate(shape): for col_idx, cell in enumerate(row): if cell and (x + col_idx < 0 or x + col_idx >= GRID_WIDTH or y + row_idx >= GRID_HEIGHT or grid[y + row_idx][x + col_idx]): return False return True def place_tetrimino(): for row_idx, row in enumerate(current_tetrimino): for col_idx, cell in enumerate(row): if cell: grid[current_y + row_idx][current_x + col_idx] = 1 clear_lines() return new_tetrimino() def clear_lines(): global grid new_grid = [row for row in grid if any(cell == 0 for cell in row)] lines_cleared = GRID_HEIGHT - len(new_grid) grid = [[0] * GRID_WIDTH] * lines_cleared + new_grid if lines_cleared > 0: beep(2000, 0.2) def move_tetrimino(dx, dy): global current_x, current_y if is_valid_position(current_tetrimino, current_x + dx, current_y + dy): current_x += dx current_y += dy return True return False def rotate_tetrimino(): global current_tetrimino rotated = [list(row) for row in zip(*current_tetrimino[::-1])] if is_valid_position(rotated, current_x, current_y): current_tetrimino = rotated beep(1500, 0.1) def update_lcd(): lcd.clear() for row in range(8): # Limit to LCD display for col in range(16): char = '#' if grid[row][col] else ' ' lcd.putchar(char) lcd.putchar('\n') def get_joystick_input(): x_val = joy_x.read() y_val = joy_y.read() btn_pressed = not button.value() if x_val < 1000: move_tetrimino(-1, 0) elif x_val > 3000: move_tetrimino(1, 0) elif y_val > 3000: move_tetrimino(0, 1) elif btn_pressed: rotate_tetrimino() # ==== MAIN GAME LOOP ==== if not new_tetrimino(): lcd.clear() lcd.putstr("GAME OVER") while True: pass fall_speed = 1.0 last_fall_time = time.time() while True: get_joystick_input() if time.time() - last_fall_time > fall_speed: if not move_tetrimino(0, 1): # Move down if not place_tetrimino(): # Lock in place lcd.clear() lcd.putstr("GAME OVER") beep(500, 1) break last_fall_time = time.time() update_lcd() time.sleep(0.1) |
Educational robotics refers to the use of robots and robotics technology to promote learning in educational settings. It involves the integration of technology, engineering, and computer science into the classroom, allowing students to engage in hands-on, project-based learning experiences.
In this context, our website represents an excellent resource for parents, teachers and children who wish to discover robotics.
Zaouiet Kontech-Jemmel-Monastir-Tunisia
+216 92 886 231
medaliprof@gmail.com
Robotic site created by MedAli-Teacher info