Creating a simple game using the ESP32, Joystick, and an OLED display can be a fun project! Let’s create a basic “Dodge the Block” game where a player controls a character (represented by a square) on the screen using a joystick, and they must avoid falling blocks. The blocks will fall from the top of the screen, and the player must dodge them using the joystick. If a block hits the player, the game ends.
Components:
- ESP32 (Development board)
- Joystick Module (With X and Y analog outputs)
- OLED Display (128×64 I2C display)
Wiring Connections:
- Joystick:
VCC
→ 3.3V (on ESP32)GND
→ GND (on ESP32)X-Axis
→GPIO34
(or any analog input pin)Y-Axis
→GPIO35
(or any analog input pin)
- OLED Display (I2C):
VCC
→ 3.3V (on ESP32)GND
→ GND (on ESP32)SDA
→GPIO21
(default I2C SDA on ESP32)SCL
→GPIO22
(default I2C SCL on ESP32)
Buzzer Connections:
- Positive leg (long leg) of the buzzer to GPIO 14.
- Negative leg (short leg) of the buzzer to GND on the ESP32.
Libraries to Include:
- Adafruit_SSD1306 (for OLED display)
- Wire (for I2C communication)
- Adafruit_GFX (for basic graphics)
Code:
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
// OLED display setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_I2C_ADDRESS 0x3C // Define the I2C address here
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Joystick Pins
#define JOY_X_PIN 34
#define JOY_Y_PIN 35
// Buzzer Pin
#define BUZZER_PIN 14 // Pin for the buzzer
// Game variables
int playerX = SCREEN_WIDTH / 2; // Player's initial X position
int playerY = SCREEN_HEIGHT - 10; // Player's Y position (bottom of the screen)
int playerSize = 10; // Size of the player (square)
int blockX[5]; // X positions of the blocks
int blockY[5]; // Y positions of the blocks
int blockSpeed = 1; // Speed of falling blocks
int blockWidth = 10; // Block width
int blockHeight = 10; // Block height
int score = 0; // Player's score
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
// Initialize OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_I2C_ADDRESS)) { // Using the correct I2C address
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Infinite loop if OLED initialization fails
}
display.display();
delay(2000); // Wait for 2 seconds
// Initialize joystick pins as analog inputs
pinMode(JOY_X_PIN, INPUT);
pinMode(JOY_Y_PIN, INPUT);
// Initialize buzzer pin
pinMode(BUZZER_PIN, OUTPUT);
// Initialize block positions
for (int i = 0; i < 5; i++) {
blockX[i] = random(0, SCREEN_WIDTH - blockWidth);
blockY[i] = random(-200, -50); // Blocks start off-screen
}
}
void loop() {
// Read joystick values (map to player movement)
int joyX = analogRead(JOY_X_PIN);
int joyY = analogRead(JOY_Y_PIN);
// Map joystick values to player movement (X axis)
playerX = map(joyX, 0, 4095, 0, SCREEN_WIDTH - playerSize);
playerY = map(joyY, 0, 4095, 0, SCREEN_HEIGHT - playerSize);
// Update block positions
for (int i = 0; i < 5; i++) {
blockY[i] += blockSpeed; // Blocks fall down
if (blockY[i] >= SCREEN_HEIGHT) {
blockY[i] = random(-50, -10); // Reset block to top
blockX[i] = random(0, SCREEN_WIDTH - blockWidth); // Random new X position
score++; // Increase score when block is passed
}
}
// Check for collision with blocks
for (int i = 0; i < 5; i++) {
if (playerX < blockX[i] + blockWidth &&
playerX + playerSize > blockX[i] &&
playerY < blockY[i] + blockHeight &&
playerY + playerSize > blockY[i]) {
playBuzzer(); // Play buzzer sound when collision occurs
gameOver(); // End the game if collision occurs
}
}
// Display everything
display.clearDisplay();
display.fillRect(playerX, playerY, playerSize, playerSize, WHITE); // Draw player
// Draw falling blocks
for (int i = 0; i < 5; i++) {
display.fillRect(blockX[i], blockY[i], blockWidth, blockHeight, WHITE); // Draw block
}
// Display score
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Score: ");
display.print(score);
display.display();
delay(10); // Add delay for smooth gameplay
}
void gameOver() {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(SCREEN_WIDTH / 4, SCREEN_HEIGHT / 2);
display.print("GAME OVER");
display.setTextSize(1);
display.setCursor(SCREEN_WIDTH / 4, SCREEN_HEIGHT / 2 + 16);
display.print("Score: ");
display.print(score);
display.display();
delay(2000); // Show game over screen for 2 seconds
resetGame();
}
void resetGame() {
playerX = SCREEN_WIDTH / 2;
playerY = SCREEN_HEIGHT - 10;
score = 0;
for (int i = 0; i < 5; i++) {
blockX[i] = random(0, SCREEN_WIDTH - blockWidth);
blockY[i] = random(-200, -50);
}
}
void playBuzzer() {
tone(BUZZER_PIN, 1000, 200); // Play sound at 1000Hz for 200 milliseconds
}
Explanation:
- Joystick Movement:
- The X and Y axes of the joystick control the position of the player (a square on the screen). The values from the joystick are mapped to the screen dimensions.
- Falling Blocks:
- The blocks fall from the top of the screen. When they reach the bottom, they reset to the top with new random X positions. The player needs to avoid these blocks.
- Game Over:
- If a block collides with the player, the game ends, and the score is displayed. After 2 seconds, the game resets.
- Score:
- Every time a block passes the player, the score increases.
- Display:
- The OLED is used to display the game state, including the player, falling blocks, and score.
Explanation of Buzzer Functionality:
- Buzzer Pin Setup:
- Defined a pin for the buzzer (
BUZZER_PIN
) and set it as anOUTPUT
pin in thesetup()
function.
- Defined a pin for the buzzer (
playBuzzer()
Function:- This function is used to generate a tone on the buzzer when called. We use the
tone()
function, which plays a tone on the specified pin. - It plays a 1000 Hz sound for 200 milliseconds when the player collides with a block.
- This function is used to generate a tone on the buzzer when called. We use the
- Collision Detection:
- When a collision between the player and a block is detected, the
playBuzzer()
function is called to sound the buzzer, followed by thegameOver()
function.
- When a collision between the player and a block is detected, the
This game is simple but can be expanded upon with more features. It will give you a solid foundation for working with the ESP32, joystick, and OLED.