Created
February 14, 2025 04:15
-
-
Save luis-c465/61d3abeed9d1fb80a5d70633b330fe2a to your computer and use it in GitHub Desktop.
Arduino flappy bird code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <SPI.h> | |
#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); | |
#define BUTTON_PIN 2 | |
// Game Variables | |
int birdX, birdY; | |
int birdVelocity; | |
int gravity = 1; | |
int flapStrength = -4; | |
int pipeX; | |
int pipeWidth = 20; | |
int pipeSpacing = 50; | |
int score = 0; | |
bool gameOver = false; | |
bool gameStarted = false; | |
// --- Enhanced Randomness Variables --- | |
int pipeHeightTop; | |
int pipeHeightBottom; | |
int minPipeGap = 35; // Slightly reduced min gap for more challenge | |
int maxPipeGap = 60; // Increased max gap for more variation | |
int pipeSpeed = 2; | |
int gameFrameDelay = 1; | |
int minGapCenter = SCREEN_HEIGHT / 4; // Minimum for pipeGapY (center of gap) | |
int maxGapCenter = SCREEN_HEIGHT * 3 / 4; // Maximum for pipeGapY (center of gap) | |
int pipeHeightVariation = 40; // Max variation from center for pipe heights | |
// --------------------------------------- | |
void setup() { | |
Serial.begin(9600); | |
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { | |
Serial.println(F("SSD1306 allocation failed")); | |
for(;;); | |
} | |
pinMode(BUTTON_PIN, INPUT_PULLUP); | |
startGame(); | |
drawStartScreen(); | |
} | |
void loop() { | |
if (!gameStarted) { | |
if (digitalRead(BUTTON_PIN) == LOW) { | |
gameStarted = true; | |
delay(200); | |
} | |
} else if (!gameOver) { | |
updateGame(); | |
drawGame(); | |
delay(gameFrameDelay); // Use the new gameFrameDelay | |
} else { | |
drawGameOverScreen(); | |
gameStarted = false; | |
if (digitalRead(BUTTON_PIN) == LOW) { | |
startGame(); | |
gameOver = false; | |
gameStarted = true; | |
delay(200); | |
} | |
} | |
} | |
void startGame() { | |
birdX = SCREEN_WIDTH / 4; | |
birdY = SCREEN_HEIGHT / 2; | |
birdVelocity = 0; | |
pipeX = SCREEN_WIDTH; | |
randomizePipes(); // Initialize pipes with random heights and gap | |
score = 0; | |
} | |
void randomizePipes() { | |
pipeSpeed = 2 + score / 3; | |
// --- More Independent and Wider Randomization --- | |
int gapSize = random(minPipeGap, maxPipeGap); // Random gap size | |
// Randomize the center of the gap more freely within the screen | |
int pipeGapY = random(minGapCenter, maxGapCenter); | |
// Calculate top pipe height - allow more variation from the gap center | |
pipeHeightTop = pipeGapY - gapSize / 2 + random(-pipeHeightVariation/2, pipeHeightVariation/2); | |
pipeHeightBottom = SCREEN_HEIGHT - (pipeGapY + gapSize / 2) + random(-pipeHeightVariation/2, pipeHeightVariation/2); | |
// Ensure pipes are within screen bounds and gaps are playable | |
pipeHeightTop = constrain(pipeHeightTop, 10, SCREEN_HEIGHT - minPipeGap - 10); | |
pipeHeightBottom = constrain(pipeHeightBottom, 10, SCREEN_HEIGHT - minPipeGap - 10); | |
// Recalculate pipeGapY based on new heights to ensure consistent gap center (optional but good to have) | |
pipeGapY = pipeHeightTop + gapSize / 2; // Re-establish the gap center based on top pipe height and gap size | |
} | |
void updateGame() { | |
if (gameOver) { | |
return; | |
} | |
if (digitalRead(BUTTON_PIN) == LOW) { | |
birdVelocity = flapStrength; | |
} | |
birdVelocity += gravity; | |
birdY += birdVelocity; | |
// Pipe movement - using increased pipeSpeed | |
pipeX -= pipeSpeed; | |
if (pipeX < -pipeWidth) { | |
pipeX = SCREEN_WIDTH + pipeSpacing; | |
randomizePipes(); // Randomize pipes when new pipe set enters | |
score++; | |
} | |
if (birdY < 0 || birdY > SCREEN_HEIGHT) { | |
gameOver = true; | |
} | |
if (birdX + 4 > pipeX && birdX - 4 < pipeX + pipeWidth) { | |
// Collision detection now uses pipeHeightTop and pipeHeightBottom | |
if (birdY - 4 < pipeHeightTop || birdY + 4 > SCREEN_HEIGHT - pipeHeightBottom) { | |
gameOver = true; | |
} | |
} | |
} | |
void drawGame() { | |
display.clearDisplay(); | |
display.fillCircle(birdX, birdY, 4, WHITE); | |
// Draw Pipes - Using pipeHeightTop and pipeHeightBottom | |
display.fillRect(pipeX, 0, pipeWidth, pipeHeightTop, WHITE); // Top pipe - height is now variable | |
display.fillRect(pipeX, SCREEN_HEIGHT - pipeHeightBottom, pipeWidth, pipeHeightBottom, WHITE); // Bottom pipe - height is now variable | |
display.setTextSize(1); | |
display.setTextColor(WHITE); | |
display.setCursor(10, 10); | |
display.print("Score: "); | |
display.print(score); | |
display.display(); | |
} | |
void drawStartScreen() { | |
display.clearDisplay(); | |
display.setTextSize(2); | |
display.setTextColor(WHITE); | |
display.setCursor(SCREEN_WIDTH / 2 - 40, SCREEN_HEIGHT / 2 - 20); | |
display.print("Flappy"); | |
display.setCursor(SCREEN_WIDTH / 2 - 40, SCREEN_HEIGHT / 2); | |
display.print("Bird"); | |
display.setTextSize(1); | |
display.setCursor(SCREEN_WIDTH / 2 - 50, SCREEN_HEIGHT - 10); | |
display.print("Press Button"); | |
display.display(); | |
} | |
void drawGameOverScreen() { | |
display.clearDisplay(); | |
display.setTextSize(2); | |
display.setTextColor(WHITE); | |
display.setCursor(SCREEN_WIDTH / 2 - 50, SCREEN_HEIGHT / 2 - 20); | |
display.print("Game Over"); | |
display.setTextSize(1); | |
display.setCursor(SCREEN_WIDTH / 2 - 40, SCREEN_HEIGHT / 2 + 10); | |
display.print("Score: "); | |
display.print(score); | |
display.setCursor(SCREEN_WIDTH / 2 - 60, SCREEN_HEIGHT / 2 + 20); | |
display.print("Press to Restart"); | |
display.display(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment