
Flappy Bird na arduino!!!
Założenia projektu:
Stworzenie prostej gry zaprogramowanej w arduino IED. Gra ma wykorzystywać maksymalnie 6 przycisków ale przede wszystkim ma być przyjemna dla oka i w rozgrywce.
Użyte części:
-arduino uno
-wyświetlacz OLED 16x16 z czterema wyjściowymi pinami
-płytka pcb z zamontowanymi 6-cioma guzikami i czterema wejściami na piny
główne narzędzia jakie wykorzystywaliśmy to chat gpt i nasze szare komórki.
Projekt został użyty przy pomocy narzędzia AI- chatGPT - na początku został poproszony o stworzenie najprostrzej wersji gry, następnie, z jego użyciem, naprawiono usterki i dodawano ulepszenia.
Kod został podzielony na oddzielne funkcje dodające konkretne elementy poruszanie się w nim i drobne modyfikacje były relatywnie proste.
Najcięższe było znalezienie ustawienie losowo generowanych się przeszkód oraz znalezienie idealnej prędkości lotu/opadania ptaka.
Ostatnimi modyfikacjami jakie zostały zrobione - było dodanie napisu "Game over" i podawaną ilość pokonanych przeszkód jako "score:".



#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 BIRD_SIZE 6
#define GRAVITY 0.2
#define JUMP_FORCE -2
#define PIPE_WIDTH 20
#define PIPE_GAP 24 // Stała przerwa między rurami
#define PIPE_SPEED 2
#define PIPE_DISTANCE 60
#define MIN_PIPE_GAP_TOP 5 // Minimalna odległość od góry
#define MIN_PIPE_GAP_BOTTOM 5 // Minimalna odległość od dołu
int birdX = SCREEN_WIDTH / 4;
float birdY = SCREEN_HEIGHT / 2;
float birdVelocityY = 0;
int pipeX[3];
int pipeGapY[3];
int score = 0;
void setup() {
Serial.begin(9600);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
pinMode(4, INPUT_PULLUP);
// Generowanie losowej wysokości dla wszystkich rur na początku gry
for (int i = 0; i < 3; i++) {
pipeX[i] = SCREEN_WIDTH + i * PIPE_DISTANCE;
int upperGap = random(MIN_PIPE_GAP_TOP, SCREEN_HEIGHT - PIPE_GAP - MIN_PIPE_GAP_BOTTOM); // Losowa wysokość dla górnej części otworu
pipeGapY[i] = upperGap;
}
}
void loop() {
handleInput();
updateBird();
updatePipes();
display.clearDisplay();
drawBird();
for (int i = 0; i < 3; i++) {
drawPipes(i);
}
drawScore();
display.display();
if (checkCollision()) {
displayGameOver();
resetGame();
}
delay(20);
}
void handleInput() {
if (digitalRead(4) == LOW) {
birdVelocityY = JUMP_FORCE;
}
}
void updateBird() {
birdVelocityY += GRAVITY;
birdY += birdVelocityY;
birdY = max(min(birdY, (float)SCREEN_HEIGHT - BIRD_SIZE), 0.0f);
}
void updatePipes() {
for (int i = 0; i < 3; i++) {
pipeX[i] -= PIPE_SPEED;
if (pipeX[i] < -PIPE_WIDTH) {
pipeX[i] += 3 * PIPE_DISTANCE;
int upperGap = random(MIN_PIPE_GAP_TOP, SCREEN_HEIGHT - PIPE_GAP - MIN_PIPE_GAP_BOTTOM); // Losowa wysokość dla górnej części otworu
pipeGapY[i] = upperGap;
score++;
}
}
}
bool checkCollision() {
for (int i = 0; i < 3; i++) {
if (birdX + BIRD_SIZE > pipeX[i] && birdX < pipeX[i] + PIPE_WIDTH) {
if (birdY < pipeGapY[i] || birdY + BIRD_SIZE > pipeGapY[i] + PIPE_GAP) {
return true;
}
}
}
if (birdY <= 0 || birdY >= SCREEN_HEIGHT - BIRD_SIZE) {
return true;
}
return false;
}
void drawBird() {
display.fillRect(birdX, birdY, BIRD_SIZE, BIRD_SIZE, SSD1306_WHITE);
}
void drawPipes(int i) {
display.fillRect(pipeX[i], 0, PIPE_WIDTH, pipeGapY[i], SSD1306_WHITE);
display.fillRect(pipeX[i], pipeGapY[i] + PIPE_GAP, PIPE_WIDTH, SCREEN_HEIGHT - pipeGapY[i] - PIPE_GAP, SSD1306_WHITE);
}
void drawScore() {
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Score: ");
display.println(score);
}
void displayGameOver() {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor((SCREEN_WIDTH - 6 * 12)/2, SCREEN_HEIGHT / 2 - 16); // Dostosowanie pozycji dla dwóch linii
display.println("GAME");
display.setCursor((SCREEN_WIDTH - 6 * 12)/2, SCREEN_HEIGHT / 2); // Nowa linia dla "OVER"
display.println("OVER");
int scoreX = (SCREEN_WIDTH - 6 * 12) / 2; // Ustawienie pozycji X na środek ekranu
int scoreY = (SCREEN_HEIGHT / 2) + 16; // Położenie poniżej "GAME OVER"
// Ustawienie kursora dla wyniku
display.setCursor(scoreX, scoreY);
drawScore();
display.display();
delay(1000);
}
void resetGame() {
birdY = SCREEN_HEIGHT / 2;
birdVelocityY = 0;
score = 0;
// Resetujemy rury przy restarcie gry
for (int i = 0; i < 3; i++) {
pipeX[i] = SCREEN_WIDTH + i * PIPE_DISTANCE;
int upperGap = random(MIN_PIPE_GAP_TOP, SCREEN_HEIGHT - PIPE_GAP - MIN_PIPE_GAP_BOTTOM); // Losowa wysokość dla górnej części otworu
pipeGapY[i] = upperGap;
}
delay(1000); // Krótka pauza przed restartem gry
}