Làm game flappy bird

Giới thiệu

Nhắc đến Flappy Bird thì chắc ai cũng biết rồi, một tựa game đơn giản nhưng từng làm mưa làm gió trên các nên tảng đi động. Nhưng bây giờ mình sẽ giới thiệu các bạn cách làm 1 phiên bản Flappy bird mới trên Arduino.

Ở đây mình giới thiệu 2 game : "Flappy bird ", và "Nuôi cá "(cái này mình tự đặt smiley) cùng trong 1 code và người chơi có thể di chuyển để chọn game .

Bài viết chủ yếu tập trung vào phần code , còn phần cứng khá đơn giản nên mình nói khá ngắn gọn.

Yêu cầu

  • Arduino
  • Màn hình LCD đơn sắc 48x84( vd:LCD 5110).
  • thư viện adafruit pcd8544 (thư viên này dùng cho việc vẽ ảnh trên LCD).
  • thư viện adafruit GFX
  • 5 cái nút bấm, và 1 số thứ khi mua LCD sẽ được khuyến mãi theo.

Kiến thức cơ bản về thư viện adafruit pcd8544.

Mình sẽ nói kĩ về thư viện này 1 chút nó khá quan trọng trong việc làm game.

Đây là thư viện được viết sẵn dành cho việc làm game trên arduino kết nối màn hình LCD download, ngoài ra các bạn phải tải thêm thư viện adafruit GFX, vì thư viện adafruit pcd8544 kế thừa thư viện này.

1. Khai báo và khởi tạo.

Để sử dụng thư viện adafruit pcd8544 ta khai báo :

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

Khởi tạo kết nối LCD với Arduino:

Adafruit_PCD8544 display = Adafruit_PCD8544(3,4,5,6,7);

 pin 3 - Serial clock out (CLK)

 pin 4 - Serial data out (DIN)

 pin 5 - Data/Command select (D/C)

 pin 6 - Chip enable (CE)

 pin 7 - LCD reset (RST)

2. Bộ lệnh của thư viện adafruit pcd8544.

drawPixel(int16_t x, int16_t y, uint16_t color);
//Vẽ 1 điểm ảnh ở tọa độ x, y , màu color(LCD 5110 chj có màu đen)

drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
//Vẽ đường thẳng từ (x0,y0) đến (x1,y1) ;

drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
//Vẽ hình chữ nhật .

drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
//Vẽ hình tròn.

void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,int16_t x2, int16_t y2, uint16_t color);
//Vẽ hình tam giác 

drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h,
uint16_t color);
//Vẽ hình ảnh có chiều dài w , chiều rộng h, tại vị trí x,y.

setCursor(int16_t x, int16_t y);
//Đưa con trỏ đến vị trí x, y .

Sơ đồ kết nối

Kết nối các chân.

  • pin 3 - Serial clock out (CLK)
  • pin 4 - Serial data out (DIN)
  • pin 5 - Data/Command select (D/C)
  • pin 6 - Chip enable (CE)
  • pin 7 - LCD reset (RST)

Kết nối các nút điều khiển.

  • pin8 – buttonTren
  • pin9 – buttonPhai
  • pin10 – buttonTrai
  • pin11 – buttonDuoi
  • pin12 - stopGame

Code:

1. Cài đặt bộ điều khiển.

a. Khai báo

 -Chọn các cổng đầu ra

const int button1=9;

const int button2=10;

const int button3=11;

const int button4=12;

const int button5=13;

-Trạng thái ban đầu của button

int buttonTren=0;

int buttonPhai=0;

int buttonTrai=0;

int buttonDuoi=0;

int stopGame=0;

-Định nghĩa cổng ra

pinMode(button2,INPUT);

pinMode(button3,INPUT);

pinMode(button4,INPUT);

pinMode(button5,INPUT);

b. Đọc tín hiệu điều khiển

void DieuKhien()

  {

    buttonTren=digitalRead(button1); //đọc tín hiệu từ cổng 8

  //Serial.println(buttonTren);

    buttonPhai=digitalRead(button2);

    buttonTrai=digitalRead(button3);

    buttonDuoi=digitalRead(button4);

    stopGame=digitalRead(button5);

    Serial.println(stopGame); 

  }

c.  Cấu trúc hoạt động 1 Game.

        

d. Tạo hình ảnh bitmap

LCD 5110 chỉ hiện thị được hình ảnh ở dạng hex

Ta có thể dùng phần mềm LCDAssistant để chuyển hình ảnh sang mã hex.

 static unsigned char PROGMEM flappybird[]= {0x03, 0xF0, 0x0C, 0x48, 0x10, 0x84, 0x78, 0x8A, 0x84, 0x8A, 0x82, 0x42, 0x82, 0x3E, 0x44, 0x41,0x38, 0xBE, 0x20, 0x41, 0x18,     0x3E, 0x07, 0xC0,};

 

static unsigned char PROGMEM ca3 [] ={0x0F, 0xC0, 0x12, 0x30, 0x21, 0x09, 0x51, 0x0B, 0x51, 0x07, 0x42, 0x06, 0x7C, 0x97, 0x82, 0x63,0x7D, 0x05, 0x82, 0x08, 0x7C, 0x10, 0x03, 0xE0, };

2) Tạo các đối tượng (Object)

Đối tượng Object

Đây là dối tượng cơ sở mang các đặc điểm chung nhất của đối tượng:

class Object
{
  protected:
  unsigned char* PROGMEM image;
  int position_x;
  int position_y;
  int speed_x;
  int speed_y;
  int width;
  int heigh;
  public:
  void drawImage()     //vẽ hình ảnh
  {
    display.drawBitmap(position_x,position_y,image,width,heigh,BLACK);
  }
  virtual void Update();
  
  void SetPositiony(int y)       //cài đặt tọa độ Y
  {
    position_y=y;
  }
  bool vaCham(Object &t)   //hàm kiểm tra va chạm
  {
    if((position_x+width>t.position_x)&&(position_x<t.position_x+t.width)         &&(position_y+heigh>t.position_y)&&(position_y<t.position_y+t.heigh))
         return true;
    else return false;
  }  
  int GetPositionx()  //lấy tọa độ x của đối tượng
  {
    return position_x;
  }
  int GetPositiony()  //lấy tọa độ y của đối tượng
  {
    return position_y;
  }
  void SetPositionx(int x) // cài đặt tọa độ X
  {
    position_x=x;
  }  
};

Hàm kiểm tra va chạm.

Hàm này để kiểm tra đối tượng này có chạm vào đối tượng kia hay không

Sử dụng phương pháp kiểm tra hình chử nhật , kiểm tra 1 đỉnh của hình chữ nhật này có ở trong hình chử nhật kia hay không.

Nếu có trả về true, không trả về false 

bool vaCham(Object &t)   //hàm kiểm tra va chạm
  {
    if((position_x+width>t.position_x)&&(position_x<t.position_x+t.width)
         return true;
    else return false;
  }

Đối tượng flappy bird

class Bird:public Object

  int frame;
  Bird()
  {
    frame=0;
    position_x=20;
    position_y=20;
    speed_y=1;
    width=16;
    heigh=12;
  }
  void Update() //cập nhật vị trí đối tượng
  {
    if(delaytime%5==0)position_y=position_y+speed_y;
    if(position_y>36) position_y=36;
  }
  void Fly()    
  {
    position_y-=speed_y;
  }
  void drawBird()           //Vẽ hình ảnh đối tượng
  {
    if(frame==0)
    {
      display.drawBitmap(position_x,position_y,flappybird,width,heigh,BLACK);
      if(delaytime%25==0){
      frame++;}
    }
    else if(frame==1)
    {
      display.drawBitmap(position_x,position_y,flappybird1,width,heigh,BLACK);
      if(delaytime%25==0){
      frame=0;}
    }
    delaytime++;
  };

Đối tượng Cột

class Cot:public Object
{
  public:
  Cot(unsigned char* t,int x,int y)
  {
    image=t;
    position_x=x;
    position_y=y;
    speed_x=-1;
    heigh=20;
  }
  void drawCot()
  {
    display.drawBitmap(position_x,position_y,image,width,heigh,BLACK);
  }
  void Update()
  {
    if(delaytime%7==0) position_x+=speed_x;
  }
}

Đối tượng Cá.

class Fish:public Object
{

  bool Phai;
  int An;
  public:

  Fish()
  {
    position_x=20;
    position_y=20;
    speed_x=1;
    speed_y=1;
    width=16;
    heigh=12;
    Phai=true;
    An=0;
  }
  void drawFish()
  {
    if(buttonPhai) Phai=true;
    if(buttonTrai) Phai=false;
    if(Phai)
    {
      if(!An)
      display.drawBitmap(position_x,position_y,ca,width,heigh,BLACK);
      else display.drawBitmap(position_x,position_y,ca1,width,heigh,BLACK);
    }

    else
    {
      if(!An)
      display.drawBitmap(position_x,position_y,ca3,width,heigh,BLACK);
      else display.drawBitmap(position_x,position_y,ca2,width,heigh,BLACK);
    }
    An--;
    if(An<0) An=0;
  }

  void SetAn(int i)
  {
    An=i;
  }
  void Update()
  {
    if(buttonTren) position_y-=speed_y;
    if(buttonDuoi) position_y+=speed_y;
    if(buttonPhai) position_x+=speed_x;
    if(buttonTrai) position_x-=speed_x;
    if(position_y>36) position_y=36;
    if(position_y<0) position_y=0;
    if(position_x>83) position_x=-15;
    if(position_x<-15) position_x=83;
  } 
}

Đối tượng thức ăn.

class ThucAn:public Object
{
  int lever;
  public:
  ThucAn()
  {
    position_x=0;
    position_y=0;
    speed_x=0;
    speed_y=1;
    width=5;
    heigh=5;
    lever=25;
  }
  void drawThucAn()
  {
    display.drawBitmap(position_x,position_y,thucan,width,heigh,BLACK);
  }
  void Random()
  {
    position_x=random()%78;
    speed_y=random()%3+1;
  }
  void SetLever(int i)
  {
    lever=i;
  }
  void Update()
  {
    if(delaytime%lever==0)
    position_y+=speed_y;
  }
};

Game flappy bird

Điều khiển chim vượt qua được các chướng ngại vật, mỗi lần vượt qua được 1 cột thì cộng 1 điểm .

//Game plappy bird 
void flappyBird()
{
  Bird chim;           //khởi tạo đối tượng
  Cot cott1(cottren,84,-10);
  Cot cotd1(cotduoi,84,30);
  Cot cott2(cottren,135,-10);
  Cot cotd2(cotduoi,135,30);
  bool play=true;
  int diem=0;
  while(1)
  {
  if(play)
  {
  display.clearDisplay();
  display.setCursor(70,0); 
  display.print(diem);               //in điểm ra màn hình 
  chim.drawBird();                   //vẽ chim
  chim.Update();                      //cập nhật vị trí chim
  DieuKhien();                         //đọc trang thái điều khiển
  if(buttonTren==HIGH)        //nếu buttonTren được nhấn  gọi hàm fly();
    {
      chim.Fly();    
    }

  cott1.drawImage();  //Vẽ cột
  cott2.drawImage();
  cotd1.drawImage();
  cotd2.drawImage();
  cott1.Update();
  cott2.Update();
  cotd1.Update();
  cotd2.Update();
  
  if(cott1.vaCham(chim)||cotd1.vaCham(chim)   //kiểm tra va chạm
  ||cott2.vaCham(chim)||cotd2.vaCham(chim))
  {
    play=false;                                   //nếu va chạm thì gameOver
  }
  if(cott1.GetPositionx()<-9)            // khi đối tượng cột đi hết màn hình cài đặt
  {                                                   // lại vị trí đối tượng
     int tam=random()%21-16;
     int tam1=tam+40;
     cott1.SetPositionx(84);
     cott1.SetPositiony(tam);
     cotd1.SetPositionx(84);
     cotd1.SetPositiony(tam1);
     diem++;
  }
  if(cott2.GetPositionx()<-9)
  {
    int tam2=random()%21-16;
    int tam3=tam2+40;
    cott2.SetPositiony(tam2);
    cotd2.SetPositiony(tam3);
    cotd2.SetPositionx(84);  
    cott2.SetPositionx(84);
    diem++;
  } 
   
  display.display();
  if(stopGame==HIGH)   //ấn nút stop thì dừng game , đưa CT vào 1 vòng lặp
  {
    while(1)
     { 
        DieuKhien(); 
        if(buttonTren==HIGH) break;      //ấn button Trên tiếp tục chơi
        if(buttonDuoi==HIGH) break;      //ấn buttonDuoi quay lại màn hình chính
      }
      if(buttonDuoi==HIGH) break;
  }    
  if(++delaytime>36000) delaytime=0;
  }
   else
   {
     display.clearDisplay();
     display.setCursor(15,10);
     display.print("Game Over");
     display.setCursor(40,20);
     display.print(diem);
     display.display();
     DieuKhien();
     if(buttonTrai==HIGH)     //ấn button Trái tiếp tục chơi
     {
       play=true;
       diem=0;
     }
     if(buttonDuoi==HIGH){break;}   //ấn buttonDuoi quay lại màn hình chính
     cott1.SetPositionx(84);
     cotd1.SetPositionx(84);
     cott2.SetPositionx(126);
     cotd2.SetPositionx(126);    
   }
  }
}

Game nuôi cá

Điều khiển chú cá ăn hết các thức ăn được thả xuổng,ăn 1 thức ăn được + 1 điểm , thức ăn rơi xuống đáy thì mất 1 mạng, hết 3 mạng thì thua

void ChoCaAn()
{
  Fish chuca;                  //Khởi tạo các đối tượng
  ThucAn thucans[10];
  bool Play=true;
  int mang=3;
  int diem=0;
  int lever=25;                 //cấp độ chơi
  for(int i=0;i<10;i++)
     {
       thucans[i].Random();      //khởi tạo ngẩu nhiên vị trị thức ăn
     }
  while(1)
  {
    if(Play)
    {
     display.clearDisplay();
     for(int i=0;i<10;i++)
     {
       thucans[i].Update();        //Cập nhật vị trí
       thucans[i].drawThucAn();   //vẽ đối tượng thức ăn
       if(thucans[i].vaCham(chuca))   // kiểm tra va chạm
      {
        diem++;                                 //nếu va chạm tăng điểm lên 1
        if(diem%100==0) {lever--;if(lever<0)lever=0;thucans[i].SetLever(lever);}
        thucans[i].SetPositiony(0);
        thucans[i].Random();         //khởi tạo lại thức ăn
        chuca.SetAn(21);       
      }
       if(thucans[i].GetPositiony()>=48)
      {
        thucans[i].SetPositiony(0);
        mang--;
        if(mang==0)Play=false;
      } 
     }
     DieuKhien();
     chuca.Update();
     chuca.drawFish();
     
     display.print(diem);
     display.setCursor(65,0);
     for(int i=0;i<mang;i++)
     {display.write(3);}
     display.display();
     
       if(stopGame==HIGH)     //Dừng game
       {
         while(1)
         {  
          DieuKhien(); 
          if(buttonTren==HIGH) break;
          if(buttonDuoi==HIGH) break;
         }
          if(buttonDuoi==HIGH) break;
       }
    
     if(++delaytime>36000) delaytime=0;
    }
    else
    {
      display.clearDisplay();
      display.setCursor(15,10);
      display.print("Game Over");
      display.setCursor(40,20);
      display.print(diem);
      display.display();
      DieuKhien();
      if(buttonTren==HIGH)
      {
        diem=0;
        mang=3;
        for(int i=0;i<10;i++)
        {
          thucans[i].Random();
          thucans[i].SetPositiony(0);
          thucans[i].SetLever(25);
          lever=25;
        }
        Play=true;
      }
      if(buttonDuoi==HIGH){break;}
    }
  }
}

Demo

Sample

file code [mirror]

 

lên
2 thành viên đã đánh giá bài viết này hữu ích.
Chuyên mục: 
Các dự án được truyền cảm hứng

Select any filter and click on Apply to see results