ESP8266 ile Renkli Flappy Bird Oyunu

Merhaba arkadaşlar ,

Bugünkü yazımızda çok sevilen bir oyunu paylaşmak istiyorum. Bu oyunda bazı değişiklikler yapılarak bunu ESP8266-12E ye uyarlanmış . Bu oyunu oynamak için kolları sıvadım tabiiki ama ne olduysa çok aramama rağmen buton bulamadım 🙂 bunun için çok uğraşmak istemedim ama projenin bağlantılarını yaparak çalışıp çalışmadığını kontrol ettim.

Programda ST7735 entegresi ile kontrol edilen 1.44 yada 1.8 ve 2.2 inçlik TFT ekran kullanabilirsiniz. tek yapılması gereken TFT ekranın boyutunu piksel olarak sisteme girmeniz.

Bunlar;

1.44 inç için 160×160 piksel

1.8 inç için 240×160 piksel

2.2 inç için 360×240 piksel

Bu değerleri girdikten sonra renkli TFT ekranınızın orta noktalarını belirtmeniz gerekiyor buda 1.44 inç için 80×80 oluyor.

Programın Bağlantı şekli aşağıdaki gibi olmalıdır.

ESP8266-12E
GPIO 15…..2.2K………….GND
EN…………………………….VCC
GPIO 2…….2.2K…………VCC
GPIO 2……buton……….GND

ESP8266-12E ST7735 TFT Ekran
3.3V VCC
GND GND
GPIO15 CS
RST RESET
GPIO5 A0
GPIO13 SDA
GPIO15 SCK
3.3V LED
GPIO12 Hoparlör
GND Hoparlör GND

Programımız Aşağıdaki gibidir.

// =============================================================================
//
// Arduino - Flappy Bird clone
// ---------------------------
// by Themistokle "mrt-prodz" Benetatos
//
// Converted to ESP8266 + ST7735 1.44" (or 1.8") by Slider2732 - Dec 2016
// Changes - Switch press method, yield(), watchdog reset, pipe draw over, 
// sound on Pin 12, Winner section, flap reduced for playability.
// Speaker to Pin 12 & Gnd, some piezo's work, can use transistor or other amp.
//
// It features an intro screen, a game over screen containing
// the player score and similar gameplay to the original game.
//www.arduinom.org sitesinde yayinlanmistir
// Dependencies:
// - https://github.com/adafruit/Adafruit-GFX-Library
// - https://github.com/adafruit/Adafruit-ST7735-Library
//
// References:
// - http://www.tweaking4all.com/hardware/arduino/sainsmart-arduino-color-display/
// - http://www.koonsolo.com/news/dewitters-gameloop/
// - http://www.arduino.cc/en/Reference/PortManipulation
//
// --------------------
// http://mrt-prodz.com
// http://github.com/mrt-prodz/ATmega328-Flappy-Bird-Clone
//
// =============================================================================

#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>

// initialize TFT screen
// (connect pins accordingly or change these values)
#define TFT_DC            5      // Sainsmart RS/DC
#define TFT_RST           18     // Sainsmart RES - mythical, not needed
#define TFT_CS            15     // Sainsmart CS
// initialize screen with pins
static Adafruit_ST7735 TFT = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);
// instead of using TFT.width() and TFT.height() set constant values
// (we can change the size of the game easily that way)
#define TFTW            128     // screen width
#define TFTH            160     // screen height runs ok on 128 pixel 1.44"
#define TFTW2            64     // half screen width
#define TFTH2            80     // half screen height
// game constant
#define SPEED             1
#define GRAVITY         9.8
#define JUMP_FORCE     2.15
#define SKIP_TICKS     20.0     // 1000 / 50fps
#define MAX_FRAMESKIP     5
// bird size
#define BIRDW             8     // bird width
#define BIRDH             8     // bird height
#define BIRDW2            4     // half width
#define BIRDH2            4     // half height
// pipe size
#define PIPEW            12     // pipe width
#define GAPHEIGHT        36     // pipe gap height
// floor size
#define FLOORH           20     // floor height (from bottom of the screen)
// grass size
#define GRASSH            4     // grass height (inside floor, starts at floor y)

// background
const unsigned int BCKGRDCOL = TFT.Color565(138,235,244);
// bird
const unsigned int BIRDCOL = TFT.Color565(255,254,174);
// pipe
const unsigned int PIPECOL  = TFT.Color565(99,255,78);
// pipe highlight
const unsigned int PIPEHIGHCOL  = TFT.Color565(250,255,250);
// pipe seam
const unsigned int PIPESEAMCOL  = TFT.Color565(0,0,0);
// floor
const unsigned int FLOORCOL = TFT.Color565(246,240,163);
// grass (col2 is the stripe color)
const unsigned int GRASSCOL  = TFT.Color565(141,225,87);
const unsigned int GRASSCOL2 = TFT.Color565(156,239,88);

// bird sprite
// bird sprite colors (Cx name for values to keep the array readable)
#define C0 BCKGRDCOL
#define C1 TFT.Color565(195,165,75)
#define C2 BIRDCOL
#define C3 ST7735_WHITE
#define C4 ST7735_RED
#define C5 TFT.Color565(251,216,114)

static unsigned int birdcol[] =
{ C0, C0, C1, C1, C1, C1, C1, C0,
  C0, C1, C2, C2, C2, C1, C3, C1,
  C0, C2, C2, C2, C2, C1, C3, C1,
  C1, C1, C1, C2, C2, C3, C1, C1,
  C1, C2, C2, C2, C2, C2, C4, C4,
  C1, C2, C2, C2, C1, C5, C4, C0,
  C0, C1, C2, C1, C5, C5, C5, C0,
  C0, C0, C1, C5, C5, C5, C0, C0};

// bird structure
static struct BIRD {
  unsigned char x, y, old_y;
  unsigned int col;
  float vel_y;
} bird;
// pipe structure
static struct PIPE {
  char x, gap_y;
  unsigned int col;
} pipe;

// score
static short score;
// temporary x and y var
static short tmpx, tmpy;

// ---------------
// draw pixel
// ---------------
// faster drawPixel method by inlining calls and using setAddrWindow and pushColor
// using macro to force inlining
#define drawPixel(a, b, c) TFT.setAddrWindow(a, b, a, b); TFT.pushColor(c)

// ---------------
// initial setup
// ---------------
void setup() {
  // initialize the push button on pin 2 as an input
  // initialize ST7735S chip, black tab
  TFT.initR(INITR_BLACKTAB);
}

// ---------------
// main loop
// ---------------
void loop() {
  game_start();
  game_loop();
  tone(12, 60, 1500); // Game Over tone
  game_over();
}

// ---------------
// game loop
// ---------------
void game_loop() {
  // ===============
  // prepare game variables
  // draw floor
  // ===============
  // instead of calculating the distance of the floor from the screen height each time store it in a variable
  unsigned char GAMEH = TFTH - FLOORH;
  // draw the floor once, we will not overwrite on this area in-game
  // black line
  TFT.drawFastHLine(0, GAMEH, TFTW+32, ST7735_BLACK);
  // grass and stripe
  TFT.fillRect(0, GAMEH+1, TFTW2+16, GRASSH, GRASSCOL);
  TFT.fillRect(TFTW2, GAMEH+1, TFTW2+16, GRASSH, GRASSCOL2);
  // black line
  TFT.drawFastHLine(0, GAMEH+GRASSH, TFTW+32, ST7735_BLACK);
  // mud
  TFT.fillRect(0, GAMEH+GRASSH+1, TFTW+32, FLOORH-GRASSH, FLOORCOL);
  // grass x position (for stripe animation)
  char grassx = TFTW+32;
  // game loop time variables
  double delta, old_time, next_game_tick, current_time;
  next_game_tick = current_time = millis();
  int loops;
  // passed pipe flag to count score
  bool passed_pipe = false;
  // temp var for setAddrWindow
  unsigned char px;
  
      while (1) {
      wdt_reset();
      loops = 0;
      while( millis() > next_game_tick && loops < MAX_FRAMESKIP) {
      // ===============
      // input
      // ===============
      if ( !(digitalRead(2)) ) {
        // if the bird is not too close to the top of the screen apply jump force
        if (bird.y > BIRDH2*0.5){  bird.vel_y = -JUMP_FORCE /2;
        // make flap sound 
        tone(12, 800, 10); // tone on Pin 12
      }
        // else zero velocity
        else bird.vel_y = 0;
      }
      
      // ===============
      // update
      // ===============
      // calculate delta time
      // ---------------
      old_time = current_time;
      current_time = millis();
      delta = (current_time-old_time)/1000;

      // bird
      // ---------------
      bird.vel_y += GRAVITY * delta;
      bird.y += bird.vel_y;

      // pipe
      // ---------------
      pipe.x -= SPEED;
      // if pipe reached edge of the screen reset its position and gap
      if (pipe.x < (-PIPEW +20)) {
      pipe.x = TFTW;
      randomSeed(analogRead(0));
      pipe.gap_y = random(20, TFTH-60);
      }

      // ---------------
      next_game_tick += SKIP_TICKS;
      loops++;
    }

      // ===============
      // draw
      // ===============
      // pipe
      // ---------------
      // we save cycles if we avoid drawing the pipe when outside the screen
      if (pipe.x >= -20 && pipe.x < TFTW) {
      // pipe color
      TFT.drawFastVLine(pipe.x+3, 0, pipe.gap_y, PIPECOL);
      TFT.drawFastVLine(pipe.x+3, pipe.gap_y+GAPHEIGHT+1, GAMEH-(pipe.gap_y+GAPHEIGHT+1), PIPECOL);
      // highlight
      TFT.drawFastVLine(pipe.x, 0, pipe.gap_y, PIPEHIGHCOL);
      TFT.drawFastVLine(pipe.x, pipe.gap_y+GAPHEIGHT+1, GAMEH-(pipe.gap_y+GAPHEIGHT+1), PIPEHIGHCOL);
      // bottom and top border of pipe
      drawPixel(pipe.x, pipe.gap_y, PIPESEAMCOL);
      drawPixel(pipe.x, pipe.gap_y+GAPHEIGHT, PIPESEAMCOL);
      // pipe seam
      drawPixel(pipe.x, pipe.gap_y-6, PIPESEAMCOL);
      drawPixel(pipe.x, pipe.gap_y+GAPHEIGHT+6, PIPESEAMCOL);
      drawPixel(pipe.x+3, pipe.gap_y-6, PIPESEAMCOL);
      drawPixel(pipe.x+3, pipe.gap_y+GAPHEIGHT+6, PIPESEAMCOL);
    }
      // erase behind pipe
      if (pipe.x <= TFTW) {
      TFT.drawFastVLine(pipe.x+PIPEW, 0, GAMEH, BCKGRDCOL);
      TFT.fillRect(0, 32, 26, 108, BCKGRDCOL); // Slider2732
    }
          // bird
          // ---------------
          tmpx = BIRDW-1;
          do {
          px = bird.x+tmpx+BIRDW;
          // clear bird at previous position stored in old_y
          // we can't just erase the pixels before and after current position
          // because of the non-linear bird movement (it would leave 'dirty' pixels)
          tmpy = BIRDH - 1;
          do {
            drawPixel(px, bird.old_y + tmpy, BCKGRDCOL);
          } while (tmpy--);
          // draw bird sprite at new position
          tmpy = BIRDH - 1;
          do {
            drawPixel(px, bird.y + tmpy, birdcol[tmpx + (tmpy * BIRDW)]);
          } while (tmpy--);
          } while (tmpx--);
          // save position to erase bird on next draw
          bird.old_y = bird.y;

    // grass stripes
    // ---------------
    grassx -= SPEED;
    if (grassx < 0) grassx = TFTW;
    TFT.drawFastVLine( grassx    %TFTW, GAMEH+1, GRASSH-1, GRASSCOL);
    TFT.drawFastVLine((grassx+64)%TFTW, GAMEH+1, GRASSH-1, GRASSCOL2);

    // ===============
    // collision
    // ===============
    // if the bird hit the ground game over
    if (bird.y > GAMEH-BIRDH) break;
    // checking for bird collision with pipe
    if (bird.x+BIRDW >= pipe.x-BIRDW2 && bird.x <= pipe.x+PIPEW-BIRDW) {
    // bird entered a pipe, check for collision
    if (bird.y < pipe.gap_y || bird.y+BIRDH > pipe.gap_y+GAPHEIGHT) break;
    else passed_pipe = true;
    tone(12, 1000, 50);
     
    }
      // if bird has passed the pipe increase score
      else if (bird.x > pipe.x+PIPEW-BIRDW && passed_pipe) {
      passed_pipe = false;
      // erase score with background color
      TFT.setTextColor(BCKGRDCOL);
      TFT.setCursor( TFTW-16, 34);
      TFT.print(score);
      // set text color back to white for new score
      TFT.setTextColor(ST7735_BLACK);
      // increase score since we successfully passed a pipe
      score++;
      if (score >= 25)
      { winner();
      }
    }

    // update score
    // ---------------
    TFT.setCursor( TFTW-16, 34);
    TFT.print(score);
  }
  
   // add a small delay to show how the player lost
   delay(1200);
}

// ---------------
// game start
// ---------------
void game_start() {
  TFT.fillScreen(ST7735_BLACK);
  TFT.fillRect(10, TFTH2 - 20, TFTW-20, 1, ST7735_YELLOW);
  TFT.fillRect(10, TFTH2 + 32, TFTW-20, 1, ST7735_YELLOW);
  TFT.setTextColor(ST7735_WHITE);
  TFT.setTextSize(3);
  // half width - num char * char width in pixels
  TFT.setCursor( TFTW2-(6*9), TFTH2 - 16);
  TFT.println("FLAPPY");
  TFT.setTextSize(3);
  TFT.setCursor( TFTW2-(6*9), TFTH2 + 8);
  TFT.println("-BIRD-");
  TFT.setTextSize(0);
  TFT.setCursor( 10, TFTH2 - 28);
  TFT.println("ESP8266");
  TFT.setCursor( TFTW2 - (12*3) - 1, TFTH2 + 54);
  TFT.println("Press Start");
  while (1) {
  yield();
  // wait for push button
  if (digitalRead(2) == LOW ) break;
  }
   // Start tune
   tone(12, 200, 500);
   delay(200);
   tone(12, 400, 100);
   delay(200);
   tone(12, 480, 500);
   delay(200);
   tone(12, 600, 1000);
   // init game settings
   game_init();
}

// ---------------
// game init
// ---------------
void game_init() {
  // clear screen
  TFT.fillScreen(BCKGRDCOL);
  // reset score
  score = 0;
  // init bird
  bird.x = 20;
  bird.y = bird.old_y = TFTH2 - BIRDH;
  bird.vel_y = -JUMP_FORCE;
  tmpx = tmpy = 0;
  // generate new random seed for the pipe gap
  randomSeed(analogRead(0));
  // init pipe
  pipe.x = TFTW;
  pipe.gap_y = random(20, TFTH-60);
}

// ---------------
// game over
// ---------------
void game_over() {
  TFT.fillScreen(ST7735_BLACK);
  TFT.setTextColor(ST7735_WHITE);
  TFT.setTextSize(2);
  // half width - num char * char width in pixels
  TFT.setCursor( TFTW2 - (9*6), TFTH2);
  TFT.println("GAME OVER");
  TFT.setTextSize(0);
  TFT.setCursor( 10, TFTH2 - 16);
  TFT.print("Score: ");
  TFT.print(score);
  TFT.print("");
  TFT.setCursor( 26, TFTH2 + 40);
  delay(1000);
  TFT.println("Press Start");
  while (1) {
  yield();
  analogWrite(12,0); // speaker off, else tick sound on piezos
  // wait for push button
  if (digitalRead(2) == LOW ) break;
  }
}

void winner()
{
  TFT.fillScreen(ST7735_BLACK);
  TFT.setTextColor(ST7735_CYAN);
  TFT.setTextSize(2);
    
  while (1) {
  yield();
  TFT.fillScreen(ST7735_BLACK);
  int d = random(160);
  tone(12,random(120,8000),d);
  //delay(200);
  delay(random(100));
  TFT.setCursor(d,d);
  TFT.println("WINNER !");
  // wait for push button
  // if (digitalRead(2) == LOW ) game_over(); // add in for game reset 
  
  }
}



Bir Cevap Yazın

Time limit is exhausted. Please reload CAPTCHA.