Introduction: Tetris Game on S3 Mini Pro - ESP32 Using Arduino IDE

About: I enjoy designing 3D models and printed circuit boards. I am an Electrical Engineer. I will share some cool projects & try out a few! #innovator

Hello electronic enthusiast, students, and Arduino programmers. As we all know, the game of Tetris is legendary! With this new S3 Mini Pro development board we can play the classic puzzle challenge. With its vibrant 128 x 128 pixel display and onboard push buttons for responsive controls, you'll be able to stack those iconic falling blocks. The S3 Mini Pro ESP32 offers a techie experience that combines nostalgia with modern technology. Plus, its energy-efficient 3.3V design ensures that you can enjoy hours of play.

Whether you're a seasoned Tetris master or a newcomer eager to test your skills, get ready to immerse yourself in the timeless challenge of Tetris and see how high you can stack your score!


Overview of Tetris Game Code

A simple Tetris game involves several key components:

  1. Game Board: A grid representing the play area.
  2. Tetrominoes: The falling shapes made of blocks.
  3. Game Loop: The main loop where the game updates and renders.
  4. Input Handling: To control the Tetrominoes (move left, right, rotate, drop).
  5. Collision Detection: To check if Tetrominoes are colliding with the board or other blocks.
  6. Clearing Lines: To remove filled lines and update the score.
  7. Game Over Condition: To check if the game is over.

Supplies

Step 1: Upload Code

Use the attached file to upload the code to your development board.

More details and explanation of the development board can be found at my GitHub page.

Step 2: Game Play

Code Breakdown

Here's a simplified version of Tetris code, along with explanations for each section:

Let's break down the Tetris code for the S3 Mini Pro ESP32 step by step. Below, I’ll provide a general outline of the main components involved in a basic Tetris implementation, including explanations of the functions, variables, and game logic.

Overview of Tetris Game Code

A simple Tetris game involves several key components:

  1. Game Board: A grid representing the play area.
  2. Tetrominoes: The falling shapes made of blocks.
  3. Game Loop: The main loop where the game updates and renders.
  4. Input Handling: To control the Tetrominoes (move left, right, rotate, drop).
  5. Collision Detection: To check if Tetrominoes are colliding with the board or other blocks.
  6. Clearing Lines: To remove filled lines and update the score.
  7. Game Over Condition: To check if the game is over.

Code Breakdown

Here's a simplified version of Tetris code, along with explanations for each section:

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>

// Pin definitions for the TFT display
#define TFT_CS 35
#define TFT_RST 34
#define TFT_DC 36
#define TFT_BL 33

// Board dimensions
const int boardWidth = 10;
const int boardHeight = 20;
// Game board
int board[boardHeight][boardWidth];

// Tetromino structure
struct Tetromino {
int shape[4][4]; // Tetromino shape
int x, y; // Position on the board
};

// Define Tetromino shapes
Tetromino tetrominoes[] = {
{{1, 1, 1, 1}}, // I shape
{{1, 1, 1, 0}, {0, 1, 0, 0}}, // T shape
// Add other shapes (O, J, L, S, Z) here
};

// Current Tetromino
Tetromino current;

// Game state variables
bool gameOver = false;
int score = 0;

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

void setup() {
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH); // Turn on backlight
tft.initR(INITR_BLACKTAB);
tft.setRotation(2);
resetBoard();
newTetromino();
}

void loop() {
if (!gameOver) {
// Game logic
if (canMove(0, 1)) {
current.y++; // Move Tetromino down
} else {
placeTetromino(); // Place Tetromino on board
clearLines(); // Clear any filled lines
newTetromino(); // Get a new Tetromino
if (!canMove(0, 0)) {
gameOver = true; // Game over if new Tetromino can't spawn
}
}

drawBoard(); // Render the game board
delay(500); // Control falling speed
}
}

void resetBoard() {
for (int y = 0; y < boardHeight; y++) {
for (int x = 0; x < boardWidth; x++) {
board[y][x] = 0; // Clear the board
}
}
}

void newTetromino() {
current = tetrominoes[random(0, sizeof(tetrominoes) / sizeof(tetrominoes[0]))]; // Random Tetromino
current.x = boardWidth / 2 - 2; // Start in the middle
current.y = 0; // Start at the top
}

bool canMove(int dx, int dy) {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if (current.shape[y][x]) { // If part of Tetromino
int newX = current.x + x + dx;
int newY = current.y + y + dy;
// Check if new position is valid
if (newX < 0 || newX >= boardWidth || newY >= boardHeight || board[newY][newX]) {
return false; // Out of bounds or collision
}
}
}
}
return true; // Move is valid
}

void placeTetromino() {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
if (current.shape[y][x]) {
board[current.y + y][current.x + x] = 1; // Place Tetromino on board
}
}
}
}

void clearLines() {
for (int y = boardHeight - 1; y >= 0; y--) {
bool fullLine = true;
for (int x = 0; x < boardWidth; x++) {
if (!board[y][x]) {
fullLine = false; // Line is not full
break;
}
}
if (fullLine) {
// Clear line
score++; // Increase score
for (int k = y; k > 0; k--) {
for (int x = 0; x < boardWidth; x++) {
board[k][x] = board[k - 1][x]; // Move lines down
}
}
y++; // Check the same line again
}
}
}

void drawBoard() {
tft.fillScreen(ST7735_BLACK); // Clear the screen
for (int y = 0; y < boardHeight; y++) {
for (int x = 0; x < boardWidth; x++) {
if (board[y][x]) {
tft.fillRect(x * 10, y * 10, 10, 10, ST7735_WHITE); // Draw filled block
}
}
}
// Draw current Tetromino (implement this)
}

Explanation of Key Sections


  1. Library Imports: The code includes libraries for graphics handling (Adafruit_GFX and Adafruit_ST7735).


  1. Game Board Initialization:
  2. The game board is defined as a 2D array (board) where each cell can hold a value representing whether it's empty or filled.
  3. Tetromino Structure:
  4. Each Tetromino is defined with a 4x4 shape array and its current position (x, y) on the board.
  5. Setup Function:
  6. Initializes the display, clears the board, and generates a new Tetromino.
  7. Game Loop:
  8. Runs continuously, checking if the game is over and moving the current Tetromino down. If it can't move, it places it on the board, checks for filled lines, and spawns a new Tetromino.
  9. Movement & Collision Detection:
  10. The canMove function checks whether the Tetromino can move in the desired direction without colliding with other blocks or going out of bounds.
  11. Placing Tetrominoes:
  12. When a Tetromino reaches the bottom or collides, it is placed on the board, and filled lines are checked and cleared.
  13. Drawing the Board:
  14. The drawBoard function renders the current state of the game board and the Tetrominoes on the display.

Additional Features to Consider

  1. Scoring System: Implement a display for the current score and possibly a high score.
  2. Game Over Screen: Display a message or restart option when the game ends.



Step 3: Conclusion

This Tetris implementation on the S3 Mini Pro ESP32 is a great starting point for understanding game programming concepts such as game loops, collision detection, and rendering graphics. You can expand this code by adding more features and refining the gameplay. If you have specific questions or want to delve deeper into any section, feel free to ask!