Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Игровой проект Arduino — копия Flappy Bird для Arduino

<основной класс="главный сайт" id="главный">

В этом проекте Arduino мы создадим крутую игру Arduino, фактически являющуюся копией популярной игры Flappy Bird для смартфонов, используя Arduino и сенсорный TFT-экран. Вы можете узнать, как это работает, посмотрев следующее видео или прочитав письменный текст ниже.

Обзор

Игра достаточно простая, но интересная и затягивающая. С помощью сенсорного экрана мы управляем птицей и пытаемся избежать движущихся столбов, скорость которых увеличивается по мере нашего продвижения. Также игра может сохранить ваш лучший результат, даже если вы отключите питание.[/column]

В предыдущем уроке (Учебник по Arduino TFT) мы подробно изучили, как использовать сенсорные экраны TFT с Arduino, и оставили пример игры для объяснения в этом уроке. Итак, теперь, как и в предыдущем уроке, мы шаг за шагом объясним код этой игры для Arduino.

Исходный код

Так как код немного длиннее и для лучшего понимания я буду размещать исходный код программы в разделах с описанием для каждого раздела. И в конце этой статьи я опубликую полный исходный код.

Мы будем использовать библиотеки UTFT и URTouch, созданные Хеннингом Карлсеном. Вы можете загрузить эти библиотеки с его сайта www.RinkyDinkElectronics.com. Также мы будем использовать библиотеку EEPROM для хранения наивысшего результата в EEPROM. EEPROM — это память, которая может хранить данные, даже когда плата выключена.

После того, как мы подключили библиотеки, нам нужно создать объекты UTFT и URTouch, а также определить переменные, необходимые для игры. В разделе настройки нам нужно инициировать отображение и касание, прочитать наивысший балл из EEPROM и запустить игру с помощью пользовательской функции инициироватьGame().

 #include <UTFT.h> 
#include <URTouch.h>
#include <EEPROM.h>

//==== Creating Objects
UTFT    myGLCD(SSD1289,38,39,40,41); //Parameters should be adjusted to your Display/Schield model
URTouch  myTouch( 6, 5, 4, 3, 2);

//==== Defining Fonts
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];

extern unsigned int bird01[0x41A]; // Bird Bitmap

int x, y; // Variables for the coordinates where the display has been pressed

// Floppy Bird
int xP = 319;
int yP = 100;
int yB = 50;
int movingRate = 3;
int fallRateInt = 0;
float fallRate = 0;
int score = 0;
int lastSpeedUpScore = 0;
int highestScore;
boolean screenPressed = false;
boolean gameStarted = false;

void setup() {
  // Initiate display
  myGLCD.InitLCD();
  myGLCD.clrScr();
  myTouch.InitTouch();
  myTouch.setPrecision(PREC_MEDIUM);
  
  highestScore = EEPROM.read(0); // Read the highest score from the EEPROM
  
  initiateGame(); // Initiate the game
}Code language: Arduino (arduino)

Итак, с помощью пользовательской функции инициироватьGame() мы нарисуем начальное состояние игры, и вот как мы это сделаем. Сначала нам нужно очистить экран, затем нарисовать синий фон, нарисовать нижнюю часть, добавить текст и вызвать пользовательскую функцию drawBird(), чтобы нарисовать птицу. После этого нам нужен цикл while, который предотвратит запуск игры, пока мы не коснемся экрана. Итак, пока мы находимся в этом состоянии, если мы нажмем правый верхний угол, мы можем сбросить наивысший балл до нуля, а если мы нажмем в любом другом месте экрана, мы выйдем из цикла while и попадем в основной цикл кода, который запустит игру.

// ===== initiateGame - Custom Function
void initiateGame() {
  myGLCD.clrScr();
  // Blue background
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRect(0,0,319,239);
  // Ground
  myGLCD.setColor(221,216,148);
  myGLCD.fillRect(0, 215, 319, 239);
  myGLCD.setColor(47,175,68);
  myGLCD.fillRect(0, 205, 319, 214);
  // Text
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(221, 216, 148);
  myGLCD.setFont(BigFont);
  myGLCD.print("Score:",5,220);
  myGLCD.setFont(SmallFont);
  myGLCD.print("HowToMechatronics.com", 140, 220); 
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(114, 198, 206);
  myGLCD.print("Highest Score: ",5,5);
  myGLCD.printNumI(highestScore, 120, 6);
  myGLCD.print(">RESET<",255,5);
  myGLCD.drawLine(0,23,319,23);
  myGLCD.print("TAP TO START",CENTER,100);
  
  drawBird(yB); // Draws the bird
  
  // Wait until we tap the sreen
  while (!gameStarted) {
    if (myTouch.dataAvailable()) {
    myTouch.read();
    x=myTouch.getX();
    y=myTouch.getY();        
    // Reset higest score
    if ((x>=250) && (x<=319) &&(y>=0) && (y<=28)) {
    highestScore = 0;
    myGLCD.setColor(114, 198, 206);
    myGLCD.fillRect(120, 0, 150, 22);
    myGLCD.setColor(0, 0, 0);
    myGLCD.printNumI(highestScore, 120, 5);
    } 
    if ((x>=0) && (x<=319) &&(y>=30) && (y<=239)) {
    gameStarted = true;
    myGLCD.setColor(114, 198, 206);
    myGLCD.fillRect(0, 0, 319, 32);
    }   
  }
  }
  // Clears the text "TAP TO START" before the game start
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRect(85, 100, 235, 116);
  
}Code language: Arduino (arduino)

В разделе основного цикла у нас есть переменная xP, которая используется для рисования столбов, а также переменная yP. В начале переменная xP имеет значение 319 в качестве размера экрана, а переменная yP имеет значение 100, которое является высотой первой стойки. На каждой итерации значение переменной xP уменьшается на значение переменной movingRate, которая в начале имеет значение 3, а по ходу игры увеличивается.

// The Main Loop Section
void loop() {
    xP=xP-movingRate; // xP - x coordinate of the pilars; range: 319 - (-51)   
    drawPilars(xP, yP); // Draws the pillars 
    
    // yB - y coordinate of the bird which depends on value of the fallingRate variable
    yB+=fallRateInt; 
    fallRate=fallRate+0.4; // Each inetration the fall rate increase so that we can the effect of acceleration/ gravity
    fallRateInt= int(fallRate);
    
    // Checks for collision
    if(yB>=180 || yB<=0){ // top and bottom
      gameOver();
    }
    if((xP<=85) && (xP>=5) && (yB<=yP-2)){ // upper pillar
      gameOver();
    }
    if((xP<=85) && (xP>=5) && (yB>=yP+60)){ // lower pillar
      gameOver();
    }
    
    // Draws the bird
    drawBird(yB);

    // After the pillar has passed through the screen
    if (xP<=-51){
      xP=319; // Resets xP to 319
      yP = rand() % 100+20; // Random number for the pillars height
      score++; // Increase score by one
    }
    //==== Controlling the bird
    if (myTouch.dataAvailable()&& !screenPressed) {
       fallRate=-6; // Setting the fallRate negative will make the bird jump
       screenPressed = true;
    }
    // Doesn't allow holding the screen / you must tap it
    else if ( !myTouch.dataAvailable() && screenPressed){
      screenPressed = false;
    }
    
    // After each five points, increases the moving rate of the pillars
    if ((score - lastSpeedUpScore) == 5) {
      lastSpeedUpScore = score;
      movingRate++;
    }
}Code language: Arduino (arduino)

Вот принцип работы игры:у нас есть столбы шириной 50 пикселей, которые движутся справа налево, и каждый следующий столб имеет разную случайную высоту. Логично, что для того, чтобы заставить их двигаться, после каждой итерации нам нужно очищать экран и перерисовывать графику со столбами в их новом положении. Однако мы не можем этого сделать из-за низкой частоты обновления экрана, что может привести к мерцанию графики. Для активации всех своих пикселей экрану требуется немного больше времени, поэтому нам придется импровизировать и перерисовывать только то, что движется.

Итак, давайте посмотрим, как это будет делать пользовательская функция drawPilars(). Он принимает переменные xP и yP и, используя их и функцию fillRect(), рисует столбы. Таким образом, на каждой итерации он рисует столбы в их новом месте с дополнительными синими прямоугольниками с левой и правой стороны, которые очищают предыдущий нарисованный столб, и таким образом мы фактически делаем импровизацию, просто перерисовывая движущиеся столбы. Операторы if здесь — дополнительная импровизация, потому что по какой-то причине функция fillRect() не работала, если ее параметр «x2» имел значение, выходящее за размер экрана. Кроме того, в конце этой пользовательской функции нам нужно напечатать значение достигнутого результата.

// ===== drawPlillars - Custom Function
void drawPilars(int x, int y) {
    if (x>=270){
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(318, 0, x, y-1);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(319, 0, x-1, y);

      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(318, y+81, x, 203);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(319, y+80, x-1, 204); 
    }
    else if( x<=268) {
      // Draws blue rectangle right of the pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x+51, 0, x+60, y);
      // Draws the pillar
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(x+49, 1, x+1, y-1);
      // Draws the black frame of the pillar
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(x+50, 0, x, y);
      // Draws the blue rectangle left of the pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x-1, 0, x-3, y);

      // The bottom pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x+51, y+80, x+60, 204);
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(x+49, y+81, x+1, 203);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(x+50, y+80, x, 204);
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x-1, y+80, x-3, 204);
  }
  // Draws the score
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(221, 216, 148);
  myGLCD.setFont(BigFont);
  myGLCD.printNumI(score, 100, 220);
}Code language: Arduino (arduino)

Вернувшись в раздел цикла, у нас есть переменная yB, которая представляет собой положение птицы по оси y, и она зависит от скорости падения, которая после каждой итерации увеличивается, и таким образом мы получаем эффект ускорения или гравитации. Кроме того, здесь мы проверяем наличие столкновений и используем операторы if, чтобы ограничить птицу так, что если она ударится о вершину, землю или столбы, игра закончится.

Далее идет пользовательская функция drawBird(), и давайте посмотрим, как она работает. Птица на самом деле является фотографией, преобразованной в растровое изображение с помощью инструмента ImageConverter565, созданного Хеннингом Карлсеном. Файл «.c», созданный с помощью инструмента, необходимо включить в каталог, чтобы он загружался при запуске скетча. Также мы должны определить растровое изображение таким образом, и с помощью функции drawBitmap() мы будем рисовать фотографию на экране. Птица имеет фиксированную координату X и переменную yB в качестве координаты Y. Как и в случае со столбами, мы очистим предыдущее состояние птицы, нарисовав два синих прямоугольника над и под птицей.

//====== drawBird() - Custom Function
void drawBird(int y) {
  // Draws the bird - bitmap
  myGLCD.drawBitmap (50, y, 35, 30, bird01);
  // Draws blue rectangles above and below the bird in order to clear its previus state
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRoundRect(50,y,85,y-6);
  myGLCD.fillRoundRect(50,y+30,85,y+36);
}Code language: Arduino (arduino)

Вернувшись в цикл, мы видим, что после того, как столб прошел через экран, переменная xP будет сброшена до 319, yP получит новое случайное значение от 20 до 100 для высоты столбов, а счет увеличится на единицу. Следующим оператором if мы управляем птицей. Если мы нажмем на экран, мы установим отрицательную скорость падения, что заставит птицу прыгать, а оператор else if не позволит этому случиться, если мы просто удерживаем экран. Последнее выражение if относится к сложности игры и увеличивает скорость движения столбов после каждого точного очка.

Хорошо, теперь осталось посмотреть, как работает пользовательская функция gameOver(). После задержки в одну секунду он очистит экран, напечатает счет и некоторый текст, если счет выше, чем самый высокий балл, он запишет его в EEPROM, он сбросит все переменные в их начальные значения позиции и в конце он вызовет пользовательскую функцию инициироватьGame() для перезапуска игры.

//======== gameOver() - Custom Function
void gameOver() {
  delay(1000); // 1 second
  // Clears the screen and prints the text
  myGLCD.clrScr();
  myGLCD.setColor(255, 255, 255);
  myGLCD.setBackColor(0, 0, 0);
  myGLCD.setFont(BigFont);
  myGLCD.print("GAME OVER", CENTER, 40);
  myGLCD.print("Score:", 100, 80);
  myGLCD.printNumI(score,200, 80);
  myGLCD.print("Restarting...", CENTER, 120);
  myGLCD.setFont(SevenSegNumFont);
  myGLCD.printNumI(2,CENTER, 150);
  delay(1000);
  myGLCD.printNumI(1,CENTER, 150);
  delay(1000);
  
  // Writes the highest score in the EEPROM
  if (score > highestScore) {
    highestScore = score;
    EEPROM.write(0,highestScore);
  }
  // Resets the variables to start position values
  xP=319;
  yB=50;
  fallRate=0;
  score = 0;
  lastSpeedUpScore = 0;
  movingRate = 3;  
  gameStarted = false;
  // Restart game
  initiateGame();
}Code language: Arduino (arduino)

Вот и все, и я надеюсь, что объяснение кода было достаточно ясным. Если у вас есть какие-либо вопросы, не стесняйтесь задавать их в разделе комментариев ниже.

Вот полный код игры:

/*  Arduino Game Proejct
 *  Program made by Dejan Nedelkovski,
 *  www.HowToMechatronics.com 
 */
 
/*  This program uses the UTFT and URTouch libraries
 *  made by Henning Karlsen. 
 *  You can find and download them at:
 *  www.RinkyDinkElectronics.com
 */
 
#include <UTFT.h> 
#include <URTouch.h>
#include <EEPROM.h>

//==== Creating Objects
UTFT    myGLCD(SSD1289,38,39,40,41); //Parameters should be adjusted to your Display/Schield model
URTouch  myTouch( 6, 5, 4, 3, 2);

//==== Defining Fonts
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];

extern unsigned int bird01[0x41A]; // Bird Bitmap

int x, y; // Variables for the coordinates where the display has been pressed

// Floppy Bird
int xP = 319;
int yP = 100;
int yB = 50;
int movingRate = 3;
int fallRateInt = 0;
float fallRate = 0;
int score = 0;
int lastSpeedUpScore = 0;
int highestScore;
boolean screenPressed = false;
boolean gameStarted = false;

void setup() {
  // Initiate display
  myGLCD.InitLCD();
  myGLCD.clrScr();
  myTouch.InitTouch();
  myTouch.setPrecision(PREC_MEDIUM);
  
  highestScore = EEPROM.read(0); // Read the highest score from the EEPROM
  
  initiateGame(); // Initiate the game
}

void loop() {
    xP=xP-movingRate; // xP - x coordinate of the pilars; range: 319 - (-51)   
    drawPilars(xP, yP); // Draws the pillars 
    
    // yB - y coordinate of the bird which depends on value of the fallingRate variable
    yB+=fallRateInt; 
    fallRate=fallRate+0.4; // Each inetration the fall rate increase so that we can the effect of acceleration/ gravity
    fallRateInt= int(fallRate);
    
    // Checks for collision
    if(yB>=180 || yB<=0){ // top and bottom
      gameOver();
    }
    if((xP<=85) && (xP>=5) && (yB<=yP-2)){ // upper pillar
      gameOver();
    }
    if((xP<=85) && (xP>=5) && (yB>=yP+60)){ // lower pillar
      gameOver();
    }
    
    // Draws the bird
    drawBird(yB);

    // After the pillar has passed through the screen
    if (xP<=-51){
      xP=319; // Resets xP to 319
      yP = rand() % 100+20; // Random number for the pillars height
      score++; // Increase score by one
    }
    //==== Controlling the bird
    if (myTouch.dataAvailable()&& !screenPressed) {
       fallRate=-6; // Setting the fallRate negative will make the bird jump
       screenPressed = true;
    }
    // Doesn't allow holding the screen / you must tap it
    else if ( !myTouch.dataAvailable() && screenPressed){
      screenPressed = false;
    }
    
    // After each five points, increases the moving rate of the pillars
    if ((score - lastSpeedUpScore) == 5) {
      lastSpeedUpScore = score;
      movingRate++;
    }
}
// ===== initiateGame - Custom Function
void initiateGame() {
  myGLCD.clrScr();
  // Blue background
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRect(0,0,319,239);
  // Ground
  myGLCD.setColor(221,216,148);
  myGLCD.fillRect(0, 215, 319, 239);
  myGLCD.setColor(47,175,68);
  myGLCD.fillRect(0, 205, 319, 214);
  // Text
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(221, 216, 148);
  myGLCD.setFont(BigFont);
  myGLCD.print("Score:",5,220);
  myGLCD.setFont(SmallFont);
  myGLCD.print("HowToMechatronics.com", 140, 220); 
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(114, 198, 206);
  myGLCD.print("Highest Score: ",5,5);
  myGLCD.printNumI(highestScore, 120, 6);
  myGLCD.print(">RESET<",255,5);
  myGLCD.drawLine(0,23,319,23);
  myGLCD.print("TAP TO START",CENTER,100);
  
  drawBird(yB); // Draws the bird
  
  // Wait until we tap the sreen
  while (!gameStarted) {
    if (myTouch.dataAvailable()) {
    myTouch.read();
    x=myTouch.getX();
    y=myTouch.getY();        
    // Reset higest score
    if ((x>=250) && (x<=319) &&(y>=0) && (y<=28)) {
    highestScore = 0;
    myGLCD.setColor(114, 198, 206);
    myGLCD.fillRect(120, 0, 150, 22);
    myGLCD.setColor(0, 0, 0);
    myGLCD.printNumI(highestScore, 120, 5);
    } 
    if ((x>=0) && (x<=319) &&(y>=30) && (y<=239)) {
    gameStarted = true;
    myGLCD.setColor(114, 198, 206);
    myGLCD.fillRect(0, 0, 319, 32);
    }   
  }
  }
  // Clears the text "TAP TO START" before the game start
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRect(85, 100, 235, 116);
  
}
// ===== drawPlillars - Custom Function
void drawPilars(int x, int y) {
    if (x>=270){
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(318, 0, x, y-1);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(319, 0, x-1, y);

      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(318, y+81, x, 203);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(319, y+80, x-1, 204); 
    }
    else if( x<=268) {
      // Draws blue rectangle right of the pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x+51, 0, x+60, y);
      // Draws the pillar
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(x+49, 1, x+1, y-1);
      // Draws the black frame of the pillar
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(x+50, 0, x, y);
      // Draws the blue rectangle left of the pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x-1, 0, x-3, y);

      // The bottom pillar
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x+51, y+80, x+60, 204);
      myGLCD.setColor(0, 200, 20);
      myGLCD.fillRect(x+49, y+81, x+1, 203);
      myGLCD.setColor(0, 0, 0);
      myGLCD.drawRect(x+50, y+80, x, 204);
      myGLCD.setColor(114, 198, 206);
      myGLCD.fillRect(x-1, y+80, x-3, 204);
  }
  // Draws the score
  myGLCD.setColor(0, 0, 0);
  myGLCD.setBackColor(221, 216, 148);
  myGLCD.setFont(BigFont);
  myGLCD.printNumI(score, 100, 220);
}

//====== drawBird() - Custom Function
void drawBird(int y) {
  // Draws the bird - bitmap
  myGLCD.drawBitmap (50, y, 35, 30, bird01);
  // Draws blue rectangles above and below the bird in order to clear its previus state
  myGLCD.setColor(114, 198, 206);
  myGLCD.fillRoundRect(50,y,85,y-6);
  myGLCD.fillRoundRect(50,y+30,85,y+36);
}
//======== gameOver() - Custom Function
void gameOver() {
  delay(3000); // 1 second
  // Clears the screen and prints the text
  myGLCD.clrScr();
  myGLCD.setColor(255, 255, 255);
  myGLCD.setBackColor(0, 0, 0);
  myGLCD.setFont(BigFont);
  myGLCD.print("GAME OVER", CENTER, 40);
  myGLCD.print("Score:", 100, 80);
  myGLCD.printNumI(score,200, 80);
  myGLCD.print("Restarting...", CENTER, 120);
  myGLCD.setFont(SevenSegNumFont);
  myGLCD.printNumI(2,CENTER, 150);
  delay(1000);
  myGLCD.printNumI(1,CENTER, 150);
  delay(1000);
  
  // Writes the highest score in the EEPROM
  if (score > highestScore) {
    highestScore = score;
    EEPROM.write(0,highestScore);
  }
  // Resets the variables to start position values
  xP=319;
  yB=50;
  fallRate=0;
  score = 0;
  lastSpeedUpScore = 0;
  movingRate = 3;  
  gameStarted = false;
  // Restart game
  initiateGame();
}Code language: Arduino (arduino)

Вот файл для загрузки с эскизом Arduino, изображением птицы и растровым файлом для птицы.


Производственный процесс

  1. Создание монитора Ambilight с помощью Arduino
  2. Игра Arduino Pong - OLED-дисплей
  3. Игровой контроллер Arduino
  4. Игра Arduino Touch Breakout
  5. Игра Giant Animatronics Lego Minfig Operation Game
  6. Детектор звуковой частоты
  7. Tech-TicTacToe
  8. Таймер обратного отсчета Arduino
  9. Игра Pixel Chaser
  10. Радиоуправляемый автомобиль Porsche (проект Arduino)