Drome Chino

Typ_projektu
Arduino
Zdjecie główne
Krótki opis projektu

Kultowa gra przeglądarkowa Chrome Dino teraz w odsłonie na ekranach OLED.

Niezbędne elementy

1. Płytka Arduino UNO

2. SIC Game Console

3. Ekran OLED 64x128

4. Kabel USB

Sprzęt

Komputer ze środowiskiem Arduino

Opis projektu

Kod implementuje prostą grę na platformie Arduino, w której gracz steruje postacią, unikając przeszkód poruszających się z lewej do prawej strony ekranu. Gra skupia się na szybkiej reakcji i precyzji gracza, gdyż nawet najmniejszy błąd może prowadzić do zderzenia z przeszkodą i zakończenia rozgrywki. Gracz porusza się za pomocą jednego przycisku, który odpowiada za skok postaci. Skok jest kluczowy w unikaniu przeszkód, dlatego precyzyjne naciśnięcie przycisku w odpowiednim momencie jest kluczowe dla sukcesu w grze. Skok jest kontrolowany poprzez długość naciśnięcia przycisku, po czym następuje opadanie z powrotem na ziemię. Symulacja grawitacji wprowadza element ryzyka, ponieważ gracz musi dobrze ocenić czas skoku, aby uniknąć przeszkód. Do tego w przypadku gdyby ocena była nieprecyzyjna lub przeszkoda była zbyt duża, można skok wydłużyć dodatkowym kliknięciem przycisku. Na drodze gracza pojawiają się przeszkody w postaci "dinozaurów", które przesuwają się w kierunku prawej strony ekranu. Punkty zdobywane są za każdą przeszkodę, którą udaje mu się przejść, zwiększając tym samym swoją ogólną liczbę punktów. Gra kończy się, gdy postać zderzy się z przeszkodą. Kolizje są wykrywane poprzez sprawdzanie, czy obszar dinozaura nakłada się na obszar przeszkody. Po zakończeniu gry wyświetlany jest ekran "Game Over" wraz z liczbą zdobytych punktów. Grę można na różne sposoby modyfikować we własnym zakresie , zmieniają długość i wysokość przeszkód, dodając ikonki startu czy pauzy i zmieniając wygląd postaci i przeszkód modyfikując odpowiednie bitmapy.

Zdjęcia
kod programu
#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 7

#define DINO_WIDTH 16
#define DINO_HEIGHT 16
#define OBSTACLE_WIDTH 25
#define OBSTACLE_HEIGHT 16
#define MAX_OBSTACLES 4

#define TIME 1.5
#define GRAVITY 0.3
#define JUMP_STRENGTH 3.9
#define MIN_OBSTACLE_DISTANCE 80
#define MAX_OBSTACLE_DISTANCE 150

int dinoX;
int dinoY;
float dinoYSpeed;
float treeSpeed = 2;
int treeShift;
bool isJumping = false;
int doubleJump = 0;
int counter = 0;

int obstacleX[MAX_OBSTACLES];
int obstacleY[MAX_OBSTACLES];

bool gameOver = false;

void setup() {
  display.setRotation(2);
  Serial.begin(9600);

  pinMode(BUTTON_PIN, INPUT_PULLUP);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }

  display.clearDisplay();

  dinoX = SCREEN_WIDTH / 10;
  dinoY = SCREEN_HEIGHT - DINO_HEIGHT;
  dinoYSpeed = 0;
}

void generateTrees(){
  for(int i = 0; i < MAX_OBSTACLES; i++) {
    if(i==0){
      obstacleX[i] = SCREEN_WIDTH/5 + random(MIN_OBSTACLE_DISTANCE, SCREEN_WIDTH);
    }
    else{
      obstacleX[i] = obstacleX[i-1] + random(MIN_OBSTACLE_DISTANCE, SCREEN_WIDTH);
    }
    obstacleY[i] = SCREEN_HEIGHT - OBSTACLE_HEIGHT;
  }
}

void generateTree(int i){
    if(i==0){
      obstacleX[i] = obstacleX[i+3] + random(MIN_OBSTACLE_DISTANCE, SCREEN_WIDTH);
    }
    else{
      obstacleX[i] = obstacleX[i-1] + random(MIN_OBSTACLE_DISTANCE, SCREEN_WIDTH);
    }
    obstacleY[i] = SCREEN_HEIGHT - OBSTACLE_HEIGHT;
  }


void drawDino() {
  static const unsigned char PROGMEM dinoBitmap[] =
  {
    B00000000, B00000000,
    B00000001, B11000000,
    B00011101, B11000000,
    B00111101, B11000000,
    B00111001, B11001110,
    B00111001, B11000110,
    B00111001, B11000110,
    B00011101, B11000110,
    B00001111, B11001110,
    B00000111, B11111000, 
    B00000001, B11100000,
    B00000001, B11000000,
    B00000001, B11000000,
    B00000001, B11000000,
    B00000001, B11000000,
    B00000001, B11000000,
  };
  display.drawBitmap(dinoX, dinoY, dinoBitmap, DINO_WIDTH, DINO_HEIGHT, WHITE);
}

void drawTree(int x, int y) {
  static const unsigned char PROGMEM treeBitmap[] =
  {
    B000000, B00000000, B00000000, B00000,
    B000111, B11111000, B00000000, B00000,
    B011111, B10011110, B00000000, B00000,
    B011111, B10011110, B00001000, B00000,
    B011111, B11111110, B00000100, B00000,
    B000000, B11111110, B00000010, B00000,
    B000001, B11111110, B00000011, B00000,
    B000000, B00111111, B11000001, B00110,
    B000000, B00111111, B11111101, B11100,
    B000000, B11111111, B11111111, B11100,
    B000000, B10011111, B11111111, B11000,
    B000000, B10000111, B11111111, B00000,
    B000000, B00000001, B10000110, B00000,
    B000000, B00000001, B10000100, B00000,
    B000000, B00000001, B00001100, B00000,
    B000000, B00000111, B00000000, B00000
  };
  display.drawBitmap(x, y, treeBitmap, OBSTACLE_WIDTH, OBSTACLE_HEIGHT, WHITE);
}

void drawObstacle(int x, int y) {
  display.fillRect(x, y, OBSTACLE_WIDTH, OBSTACLE_HEIGHT, WHITE);
}

void drawGameOver() {
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(20, 20);
  display.println("Game Over");
  display.setCursor(20, 40);
  display.println("Score:");
  display.setCursor(100, 40);
  display.println(counter);
}

void drawCounter(int counter) {
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(110, 20);
  display.println(counter);
}

void loop() {
  display.clearDisplay();

  drawCounter(counter);

  if (!gameOver) {
    // Ruch dinozaura
    if(digitalRead(BUTTON_PIN) == LOW && doubleJump < 5) {
      dinoYSpeed = JUMP_STRENGTH;
      isJumping = true;
      doubleJump++;
    }

    // Symulacja grawitacji
    dinoYSpeed -= GRAVITY*TIME;
    dinoY -= dinoYSpeed*TIME;

    //speed increase
    treeSpeed += 0.004;
    treeShift = treeSpeed*TIME;
    
    // Odbicie od podłoża
    if(dinoY > SCREEN_HEIGHT - DINO_HEIGHT) {
      dinoY = SCREEN_HEIGHT - DINO_HEIGHT;
      dinoYSpeed = 0;
      isJumping = false;
      doubleJump = 0;
    }

    // Rysowanie dinozaura
    drawDino();

    // Kolizja z przeszkodami
    for(int i = 0; i < MAX_OBSTACLES; i++) {
      if (obstacleX[i] <= dinoX + DINO_WIDTH && obstacleX[i] + OBSTACLE_WIDTH >= dinoX &&
          obstacleY[i] <= dinoY + DINO_HEIGHT && obstacleY[i] + OBSTACLE_HEIGHT >= dinoY) {
        gameOver = true;
      }
    }

    // Poruszanie przeszkodami
    for(int i = 0; i < MAX_OBSTACLES; i++) {
      obstacleX[i] = obstacleX[i] - treeShift;
      if(obstacleX[i] < -OBSTACLE_WIDTH) {
        generateTree(i);
        counter++;
      }
      drawTree(obstacleX[i], obstacleY[i]);
    }
  } else {
    // Wyświetlanie napisu "Game Over" przez 2 sekundy
    display.clearDisplay();
    drawGameOver();
    display.display();
    delay(2000);

    // Resetowanie gry
    gameOver = false;
    doubleJump = 0;
    dinoY = SCREEN_HEIGHT - DINO_HEIGHT;
    dinoYSpeed = 0;
    treeSpeed = 2;
    generateTrees();

    counter = 0;
  }

  // Aktualizacja wyświetlacza
  display.display();

  // Pauza
  delay(20);
}
Youtube
Tagi
#chromedino #arduino #game #dino #gameconsole #gra #oled