ESP32 Defender: Building an Alien Attack-Inspired Game with T-Display ESP32 and Arduino IDE
ESP32 Defender: A Fun and Challenging Project Hello, community! Today, I want to share a project that has been incredibly fun and challenging: ESP32 Defender, a game inspired by the classic Alien Attack, developed using a T-Display ESP32 with Wi-Fi and Bluetooth, a 1.14-inch LCD screen, and programmed in the Arduino IDE. This project started as a hobby, but it quickly became a journey of learning and growth. I want to share a bit about the process, the challenges I faced, and how it inspired me to create other projects. Let’s dive in! What is ESP32 Defender? ESP32 Defender is a defense game where the player controls a spaceship and must destroy waves of approaching aliens. The game was developed to run on a T-Display ESP32, which combines an ESP32 microcontroller with a 1.14-inch LCD screen. The programming was done entirely in the Arduino IDE, using libraries like TFT_eSPI to control the display and ESP32TimerInterrupt to handle timing events. Components and Tools Used T-Display ESP32: A powerful module that integrates Wi-Fi, Bluetooth, and an LCD screen. 1.14-inch LCD Screen: Responsible for displaying the game with simple but effective graphics. Arduino IDE: The development environment used to program the ESP32. Libraries: TFT_eSPI: For controlling the LCD screen. ESP32TimerInterrupt: For managing timed events, like alien movement. Challenges and Learnings Memory Management: The ESP32 has limited resources, so I had to optimize the code to ensure the game ran smoothly without crashes. LCD Screen Control: Learning to use the TFT_eSPI library was challenging but rewarding. Game Logic: Creating the mechanics for alien movement, shooting, and collisions required a lot of logical thinking. Future Feature Integration: I’m already planning to add Wi-Fi and Bluetooth support to enable multiplayer mode or even an online leaderboard. Why Stepping Out of Your Comfort Zone Matters This project showed me how rewarding it is to tackle technical challenges and learn new things. When starting a project like this, it’s common to face problems that seem insurmountable, but overcoming each obstacle brings tremendous growth. Moreover, ESP32 Defender inspired me to start other projects, such as a home automation system and an IoT device for plant monitoring. As I make progress, I plan to share more about these ideas here in the community. Next Steps Add Wi-Fi and Bluetooth support to create a multiplayer mode. Improve graphics and add sound effects. Publish the source code on GitHub so others can contribute and learn from the project. Final Thoughts Projects like ESP32 Defender are more than just hobbies; they’re opportunities for personal and professional growth. They teach us to be persistent, creative, and to face problems head-on. What about you? Have you worked on any projects that pushed you out of your comfort zone? Share your experiences in the comments! Let’s exchange ideas and inspire more people to create amazing things. Useful Links ESP32 Documentation TFT_eSPI Library Arduino IDE Hashtags ESP32 #Arduino #IoT #GameDevelopment #TFT #PersonalGrowth #DIY #ElectronicsProjects #DevCommunity Code cpp #include TFT_eSPI tft = TFT_eSPI(); // Cria o objeto TFT int playerX = 60; // Posição inicial X do jogador (centro horizontal) int playerY = 220; // Posição inicial Y do jogador (próximo à parte inferior) int playerWidth = 16; // Largura do jogador int playerHeight = 8; // Altura do jogador uint16_t playerColor = TFT_GREEN; // Cor do jogador // Definições para o tiro int bulletX = 0; // Posição X do tiro int bulletY = 0; // Posição Y do tiro int bulletSpeed = 6; // Velocidade do tiro (aumentada) bool bulletActive = false; // Estado do tiro (ativo ou não) uint16_t bulletColor = TFT_RED; // Cor do tiro // Definições para os inimigos int enemyRows = 3; // Número de linhas de inimigos int enemyCols = 6; // Número de colunas de inimigos int enemyWidth = 12; // Largura do inimigo int enemyHeight = 8; // Altura do inimigo int enemySpacing = 20; // Espaçamento entre inimigos int enemySpeed = 2; // Velocidade dos inimigos (aumentada) uint16_t enemyColor = TFT_WHITE; // Cor dos inimigos bool enemies[3][6] = { // Matriz de inimigos (vivos ou mortos) {true, true, true, true, true, true}, {true, true, true, true, true, true}, {true, true, true, true, true, true} }; int enemyY = 10; // Posição Y inicial dos inimigos // Placar int score = 0; // Contador de naves inimigas destruídas const int maxScore = 20; // Número máximo de naves para vencer // Estado do jogo bool gameOver = false; // Indica se o jogo terminou bool gameWon = false; // Indica se o jogador venceu unsigned long restartTime = 0; // Tempo para reiniciar o jogo // Timers para controle de movimentação e disparo unsigned long lastEnemyMove = 0; unsigned long lastPlayerMove = 0; unsigned long lastBulletMove

ESP32 Defender: A Fun and Challenging Project
Hello, community! Today, I want to share a project that has been incredibly fun and challenging: ESP32 Defender, a game inspired by the classic Alien Attack, developed using a T-Display ESP32 with Wi-Fi and Bluetooth, a 1.14-inch LCD screen, and programmed in the Arduino IDE.
This project started as a hobby, but it quickly became a journey of learning and growth. I want to share a bit about the process, the challenges I faced, and how it inspired me to create other projects. Let’s dive in!
What is ESP32 Defender?
ESP32 Defender is a defense game where the player controls a spaceship and must destroy waves of approaching aliens. The game was developed to run on a T-Display ESP32, which combines an ESP32 microcontroller with a 1.14-inch LCD screen. The programming was done entirely in the Arduino IDE, using libraries like TFT_eSPI to control the display and ESP32TimerInterrupt to handle timing events.
Components and Tools Used
- T-Display ESP32: A powerful module that integrates Wi-Fi, Bluetooth, and an LCD screen.
- 1.14-inch LCD Screen: Responsible for displaying the game with simple but effective graphics.
- Arduino IDE: The development environment used to program the ESP32.
-
Libraries:
- TFT_eSPI: For controlling the LCD screen.
- ESP32TimerInterrupt: For managing timed events, like alien movement.
Challenges and Learnings
- Memory Management: The ESP32 has limited resources, so I had to optimize the code to ensure the game ran smoothly without crashes.
- LCD Screen Control: Learning to use the TFT_eSPI library was challenging but rewarding.
- Game Logic: Creating the mechanics for alien movement, shooting, and collisions required a lot of logical thinking.
- Future Feature Integration: I’m already planning to add Wi-Fi and Bluetooth support to enable multiplayer mode or even an online leaderboard.
Why Stepping Out of Your Comfort Zone Matters
This project showed me how rewarding it is to tackle technical challenges and learn new things. When starting a project like this, it’s common to face problems that seem insurmountable, but overcoming each obstacle brings tremendous growth.
Moreover, ESP32 Defender inspired me to start other projects, such as a home automation system and an IoT device for plant monitoring. As I make progress, I plan to share more about these ideas here in the community.
Next Steps
- Add Wi-Fi and Bluetooth support to create a multiplayer mode.
- Improve graphics and add sound effects.
- Publish the source code on GitHub so others can contribute and learn from the project.
Final Thoughts
Projects like ESP32 Defender are more than just hobbies; they’re opportunities for personal and professional growth. They teach us to be persistent, creative, and to face problems head-on.
What about you? Have you worked on any projects that pushed you out of your comfort zone? Share your experiences in the comments! Let’s exchange ideas and inspire more people to create amazing things.
Useful Links
ESP32 Documentation
TFT_eSPI Library
Arduino IDE
Hashtags
ESP32 #Arduino #IoT #GameDevelopment #TFT #PersonalGrowth #DIY #ElectronicsProjects #DevCommunity
Code
cpp
#include
TFT_eSPI tft = TFT_eSPI(); // Cria o objeto TFT
int playerX = 60; // Posição inicial X do jogador (centro horizontal)
int playerY = 220; // Posição inicial Y do jogador (próximo à parte inferior)
int playerWidth = 16; // Largura do jogador
int playerHeight = 8; // Altura do jogador
uint16_t playerColor = TFT_GREEN; // Cor do jogador
// Definições para o tiro
int bulletX = 0; // Posição X do tiro
int bulletY = 0; // Posição Y do tiro
int bulletSpeed = 6; // Velocidade do tiro (aumentada)
bool bulletActive = false; // Estado do tiro (ativo ou não)
uint16_t bulletColor = TFT_RED; // Cor do tiro
// Definições para os inimigos
int enemyRows = 3; // Número de linhas de inimigos
int enemyCols = 6; // Número de colunas de inimigos
int enemyWidth = 12; // Largura do inimigo
int enemyHeight = 8; // Altura do inimigo
int enemySpacing = 20; // Espaçamento entre inimigos
int enemySpeed = 2; // Velocidade dos inimigos (aumentada)
uint16_t enemyColor = TFT_WHITE; // Cor dos inimigos
bool enemies[3][6] = { // Matriz de inimigos (vivos ou mortos)
{true, true, true, true, true, true},
{true, true, true, true, true, true},
{true, true, true, true, true, true}
};
int enemyY = 10; // Posição Y inicial dos inimigos
// Placar
int score = 0; // Contador de naves inimigas destruídas
const int maxScore = 20; // Número máximo de naves para vencer
// Estado do jogo
bool gameOver = false; // Indica se o jogo terminou
bool gameWon = false; // Indica se o jogador venceu
unsigned long restartTime = 0; // Tempo para reiniciar o jogo
// Timers para controle de movimentação e disparo
unsigned long lastEnemyMove = 0;
unsigned long lastPlayerMove = 0;
unsigned long lastBulletMove = 0;
const unsigned long enemyMoveInterval = 300; // Intervalo de movimentação dos inimigos (ms)
const unsigned long playerMoveInterval = 50; // Intervalo de movimentação do jogador (ms)
const unsigned long bulletMoveInterval = 20; // Intervalo de movimentação do tiro (ms)
// Protótipos das funções
void drawPlayer();
void movePlayer(int dx);
void shoot();
void moveBullet();
void drawEnemies();
void moveEnemies();
void checkCollisions();
void drawScore();
void showGameOver();
void showGameWon();
void resetGame();
void drawCountdown();
void setup() {
tft.init(); // Inicializa o display
tft.setRotation(0); // Ajusta a rotação do display para 0 graus (padrão)
tft.fillScreen(TFT_BLACK); // Limpa a tela com fundo preto
// Configura os botões
pinMode(0, INPUT_PULLUP); // Botão esquerdo (move para a esquerda e atira)
pinMode(35, INPUT_PULLUP); // Botão direito (move para a direita e atira)
// Inicializa o jogador
drawPlayer();
// Inicializa os inimigos
drawEnemies();
// Exibe o placar inicial zerado
drawScore();
}
void loop() {
unsigned long currentTime = millis();
if (!gameOver && !gameWon) {
// Movimentação do jogador e disparo
if (digitalRead(0) == LOW && currentTime - lastPlayerMove >= playerMoveInterval) { // Botão esquerdo
movePlayer(-2); // Move para a esquerda
lastPlayerMove = currentTime;
if (!bulletActive) { // Atira apenas se não houver tiro ativo
shoot();
}
}
if (digitalRead(35) == LOW && currentTime - lastPlayerMove >= playerMoveInterval) { // Botão direito
movePlayer(2); // Move para a direita
lastPlayerMove = currentTime;
if (!bulletActive) { // Atira apenas se não houver tiro ativo
shoot();
}
}
// Movimentação do tiro
if (bulletActive && currentTime - lastBulletMove >= bulletMoveInterval) {
moveBullet();
lastBulletMove = currentTime;
}
// Movimentação dos inimigos
if (currentTime - lastEnemyMove >= enemyMoveInterval) {
moveEnemies();
lastEnemyMove = currentTime;
}
// Verifica colisões
checkCollisions();
// Verifica se os inimigos alcançaram o final da tela
if (enemyY + enemyRows * enemySpacing >= playerY) {
gameOver = true;
restartTime = currentTime + 15000; // Reinicia em 15 segundos
showGameOver();
}
// Verifica se o jogador venceu
if (score >= maxScore) {
gameWon = true;
restartTime = currentTime + 15000; // Reinicia em 15 segundos
showGameWon();
}
} else {
// Exibe a contagem regressiva para reiniciar o jogo
drawCountdown();
// Reinicia o jogo após 15 segundos
if (currentTime >= restartTime) {
resetGame();
}
}
}
// Função para desenhar o jogador
void drawPlayer() {
tft.fillRect(playerX, playerY, playerWidth, playerHeight, playerColor);
}
// Função para mover o jogador
void movePlayer(int dx) {
tft.fillRect(playerX, playerY, playerWidth, playerHeight, TFT_BLACK); // Apaga o jogador
playerX += dx;
if (playerX < 0) playerX = 0;
if (playerX > tft.width() - playerWidth) playerX = tft.width() - playerWidth;
drawPlayer(); // Redesenha o jogador
}
// Função para disparar o tiro
void shoot() {
bulletX = playerX + playerWidth / 2 - 1;
bulletY = playerY;
bulletActive = true;
tft.fillRect(bulletX, bulletY, 2, 4, bulletColor);
}
// Função para mover o tiro
void moveBullet() {
tft.fillRect(bulletX, bulletY, 2, 4, TFT_BLACK); // Apaga o tiro
bulletY -= bulletSpeed;
if (bulletY < 0) {
bulletActive = false;
} else {
tft.fillRect(bulletX, bulletY, 2, 4, bulletColor); // Redesenha o tiro
}
}
// Função para desenhar os inimigos
void drawEnemies() {
for (int i = 0; i < enemyRows; i++) {
for (int j = 0; j < enemyCols; j++) {
if (enemies[i][j]) {
tft.fillRect(j * enemySpacing + 10, i * enemySpacing + enemyY, enemyWidth, enemyHeight, enemyColor);
}
}
}
}
// Função para mover os inimigos
void moveEnemies() {
tft.fillRect(0, enemyY, tft.width(), enemyRows * enemySpacing, TFT_BLACK); // Apaga os inimigos
enemyY += enemySpeed;
drawEnemies(); // Redesenha os inimigos
}
// Função para verificar colisões
void checkCollisions() {
if (bulletActive) {
for (int i = 0; i < enemyRows; i++) {
for (int j = 0; j < enemyCols; j++) {
if (enemies[i][j] && bulletX >= j * enemySpacing + 10 && bulletX <= j * enemySpacing + 10 + enemyWidth &&
bulletY >= i * enemySpacing + enemyY && bulletY <= i * enemySpacing + enemyY + enemyHeight) {
enemies[i][j] = false;
bulletActive = false;
tft.fillRect(j * enemySpacing + 10, i * enemySpacing + enemyY, enemyWidth, enemyHeight, TFT_BLACK);
score++; // Incrementa o placar
drawScore(); // Atualiza o placar na tela
}
}
}
}
}
// Função para exibir o placar
void drawScore() {
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setCursor(10, 10);
tft.print("Score: ");
tft.print(score);
}
// Função para exibir a tela de Game Over
void showGameOver() {
tft.fillScreen(TFT_BLACK);
tft.setTextSize(2);
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.setCursor(20, 80);
tft.print("Game Over");
tft.setCursor(20, 110);
tft.print("Score: ");
tft.print(score);
}
// Função para exibir a tela de vitória
void showGameWon() {
tft.fillScreen(TFT_BLACK);
tft.setTextSize(2);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setCursor(20, 80);
tft.print("Você Venceu!");
tft.setCursor(20, 110);
tft.print("Score: ");
tft.print(score);
}
// Função para reiniciar o jogo
void resetGame() {
tft.fillScreen(TFT_BLACK);
gameOver = false;
gameWon = false;
score = 0;
enemyY = 10;
bulletActive = false;
for (int i = 0; i < enemyRows; i++) {
for (int j = 0; j < enemyCols; j++) {
enemies[i][j] = true;
}
}
drawPlayer();
drawEnemies();
drawScore();
}
// Função para exibir a contagem regressiva
void drawCountdown() {
int remainingTime = (restartTime - millis()) / 1000; // Tempo restante em segundos
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setCursor(20, 140);
tft.print("Reiniciando em: ");
tft.print(remainingTime);
tft.print("s");
}