#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Pin Definitions
#define BUTTON_PIN 2
// Game Variables
float birdY = 32.0;
float velocity = 0.0;
const float gravity = 0.4;
const float flapForce = -3.5;
const int birdRadius = 3;
int pipeX = 128;
int gapY = 24;
const int gapHeight = 22;
const int pipeWidth = 10;
const float pipeSpeed = 2.0;
int score = 0;
bool gameOver = false;
bool gameStarted = false;
// Custom 5x5 Bird Bitmap
const unsigned char PROGMEM bird_bmp[] = {
0b01110000,
0b11111000,
0b11101000,
0b11110000,
0b01110000
};
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Initialize I2C for ESP32-C3 (Default pins: SDA=5, SCL=6)
Wire.begin(5, 6);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
for(;;); // Stop if OLED initialization fails
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
randomSeed(analogRead(0));
}
void resetGame() {
birdY = 32.0;
velocity = 0.0;
pipeX = 128;
gapY = random(10, SCREEN_HEIGHT - gapHeight - 10);
score = 0;
gameOver = false;
}
void loop() {
// Read button (LOW means pressed due to INPUT_PULLUP)
bool buttonPressed = (digitalRead(BUTTON_PIN) == LOW);
if (!gameStarted) {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(30, 20);
display.print("FLAPPY ROBOT");
display.setCursor(25, 40);
display.print("Press to Start");
display.display();
if (buttonPressed) {
gameStarted = true;
resetGame();
delay(300); // Debounce
}
return;
}
if (gameOver) {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(10, 10);
display.print("GAME OVER");
display.setTextSize(1);
display.setCursor(40, 35);
display.print("Score: ");
display.print(score);
display.setCursor(20, 50);
display.print("Press to Restart");
display.display();
if (buttonPressed) {
resetGame();
delay(300); // Debounce
}
return;
}
// --- GAME LOGIC ---
// Apply bird physics
if (buttonPressed) {
velocity = flapForce;
}
velocity += gravity;
birdY += velocity;
// Move pipes
pipeX -= pipeSpeed;
if (pipeX < -pipeWidth) {
pipeX = SCREEN_WIDTH;
gapY = random(10, SCREEN_HEIGHT - gapHeight - 10);
score++;
}
// Collision Detection: Floor or Ceiling
if (birdY - birdRadius < 0 || birdY + birdRadius > SCREEN_HEIGHT) {
gameOver = true;
}
// Collision Detection: Pipes
if (pipeX < (16 + birdRadius) && (pipeX + pipeWidth) > (16 - birdRadius)) {
if (birdY - birdRadius < gapY || birdY + birdRadius > (gapY + gapHeight)) {
gameOver = true;
}
}
// --- RENDER SCREEN ---
display.clearDisplay();
// Draw Bird (Offset slightly to center bitmap)
display.drawBitmap(16 - 2, (int)birdY - 2, bird_bmp, 5, 5, SSD1306_WHITE);
// Draw Top Pipe
display.fillRect(pipeX, 0, pipeWidth, gapY, SSD1306_WHITE);
// Draw Bottom Pipe
display.fillRect(pipeX, gapY + gapHeight, pipeWidth, SCREEN_HEIGHT - (gapY + gapHeight), SSD1306_WHITE);
// Draw Score
display.setTextSize(1);
display.setCursor(2, 2);
display.print(score);
display.display();
delay(20); // Frame rate controller (~50 FPS)
}
Loading
esp32-c3-devkitm-1
esp32-c3-devkitm-1