Làm game flappy bird

17/06/2019
lam-game-flappy-bird

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 :

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

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

  1. 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.

  1. drawPixel(int16_t x, int16_t y, uint16_t color);
  2. //Vẽ 1 điểm ảnh ở tọa độ x, y , màu color(LCD 5110 chj có màu đen)
  3.  
  4. drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
  5. //Vẽ đường thẳng từ (x0,y0) đến (x1,y1) ;
  6.  
  7. drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
  8. //Vẽ hình chữ nhật .
  9.  
  10. drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
  11. //Vẽ hình tròn.
  12.  
  13. void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,int16_t x2, int16_t y2, uint16_t color);
  14. //Vẽ hình tam giác
  15.  
  16. drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h,
  17. uint16_t color);
  18. //Vẽ hình ảnh có chiều dài w , chiều rộng h, tại vị trí x,y.
  19.  
  20. setCursor(int16_t x, int16_t y);
  21. //Đư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

  1. const int button1=9;
  2.  
  3. const int button2=10;
  4.  
  5. const int button3=11;
  6.  
  7. const int button4=12;
  8.  
  9. const int button5=13;

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

  1. int buttonTren=0;
  2.  
  3. int buttonPhai=0;
  4.  
  5. int buttonTrai=0;
  6.  
  7. int buttonDuoi=0;
  8.  
  9. int stopGame=0;

-Định nghĩa cổng ra

  1. pinMode(button2,INPUT);
  2.  
  3. pinMode(button3,INPUT);
  4.  
  5. pinMode(button4,INPUT);
  6.  
  7. pinMode(button5,INPUT);

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

  1. void DieuKhien()
  2.  
  3. {
  4.  
  5. buttonTren=digitalRead(button1); //đọc tín hiệu từ cổng 8
  6.  
  7. //Serial.println(buttonTren);
  8.  
  9. buttonPhai=digitalRead(button2);
  10.  
  11. buttonTrai=digitalRead(button3);
  12.  
  13. buttonDuoi=digitalRead(button4);
  14.  
  15. stopGame=digitalRead(button5);
  16.  
  17. Serial.println(stopGame);
  18.  
  19. }

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.

  1. 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,};

 

  1. 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:

  1. class Object
  2. {
  3. protected:
  4. unsigned char* PROGMEM image;
  5. int position_x;
  6. int position_y;
  7. int speed_x;
  8. int speed_y;
  9. int width;
  10. int heigh;
  11. public:
  12. void drawImage() //vẽ hình ảnh
  13. {
  14. display.drawBitmap(position_x,position_y,image,width,heigh,BLACK);
  15. }
  16. virtual void Update();
  17.  
  18. void SetPositiony(int y) //cài đặt tọa độ Y
  19. {
  20. position_y=y;
  21. }
  22. bool vaCham(Object &t) //hàm kiểm tra va chạm
  23. {
  24. 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))
  25. return true;
  26. else return false;
  27. }
  28. int GetPositionx() //lấy tọa độ x của đối tượng
  29. {
  30. return position_x;
  31. }
  32. int GetPositiony() //lấy tọa độ y của đối tượng
  33. {
  34. return position_y;
  35. }
  36. void SetPositionx(int x) // cài đặt tọa độ X
  37. {
  38. position_x=x;
  39. }
  40. };

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 

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

Đối tượng flappy bird

  1. class Bird:public Object
  2.  
  3. int frame;
  4. Bird()
  5. {
  6. frame=0;
  7. position_x=20;
  8. position_y=20;
  9. speed_y=1;
  10. width=16;
  11. heigh=12;
  12. }
  13. void Update() //cập nhật vị trí đối tượng
  14. {
  15. if(delaytime%5==0)position_y=position_y+speed_y;
  16. if(position_y>36) position_y=36;
  17. }
  18. void Fly()
  19. {
  20. position_y-=speed_y;
  21. }
  22. void drawBird() //Vẽ hình ảnh đối tượng
  23. {
  24. if(frame==0)
  25. {
  26. display.drawBitmap(position_x,position_y,flappybird,width,heigh,BLACK);
  27. if(delaytime%25==0){
  28. frame++;}
  29. }
  30. else if(frame==1)
  31. {
  32. display.drawBitmap(position_x,position_y,flappybird1,width,heigh,BLACK);
  33. if(delaytime%25==0){
  34. frame=0;}
  35. }
  36. delaytime++;
  37. };

Đối tượng Cột

  1. class Cot:public Object
  2. {
  3. public:
  4. Cot(unsigned char* t,int x,int y)
  5. {
  6. image=t;
  7. position_x=x;
  8. position_y=y;
  9. speed_x=-1;
  10. heigh=20;
  11. }
  12. void drawCot()
  13. {
  14. display.drawBitmap(position_x,position_y,image,width,heigh,BLACK);
  15. }
  16. void Update()
  17. {
  18. if(delaytime%7==0) position_x+=speed_x;
  19. }
  20. }

Đối tượng Cá.

  1. class Fish:public Object
  2. {
  3.  
  4. bool Phai;
  5. int An;
  6. public:
  7.  
  8. Fish()
  9. {
  10. position_x=20;
  11. position_y=20;
  12. speed_x=1;
  13. speed_y=1;
  14. width=16;
  15. heigh=12;
  16. Phai=true;
  17. An=0;
  18. }
  19. void drawFish()
  20. {
  21. if(buttonPhai) Phai=true;
  22. if(buttonTrai) Phai=false;
  23. if(Phai)
  24. {
  25. if(!An)
  26. display.drawBitmap(position_x,position_y,ca,width,heigh,BLACK);
  27. else display.drawBitmap(position_x,position_y,ca1,width,heigh,BLACK);
  28. }
  29.  
  30. else
  31. {
  32. if(!An)
  33. display.drawBitmap(position_x,position_y,ca3,width,heigh,BLACK);
  34. else display.drawBitmap(position_x,position_y,ca2,width,heigh,BLACK);
  35. }
  36. An--;
  37. if(An<0) An=0;
  38. }
  39.  
  40. void SetAn(int i)
  41. {
  42. An=i;
  43. }
  44. void Update()
  45. {
  46. if(buttonTren) position_y-=speed_y;
  47. if(buttonDuoi) position_y+=speed_y;
  48. if(buttonPhai) position_x+=speed_x;
  49. if(buttonTrai) position_x-=speed_x;
  50. if(position_y>36) position_y=36;
  51. if(position_y<0) position_y=0;
  52. if(position_x>83) position_x=-15;
  53. if(position_x<-15) position_x=83;
  54. }
  55. }

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

  1. class ThucAn:public Object
  2. {
  3. int lever;
  4. public:
  5. ThucAn()
  6. {
  7. position_x=0;
  8. position_y=0;
  9. speed_x=0;
  10. speed_y=1;
  11. width=5;
  12. heigh=5;
  13. lever=25;
  14. }
  15. void drawThucAn()
  16. {
  17. display.drawBitmap(position_x,position_y,thucan,width,heigh,BLACK);
  18. }
  19. void Random()
  20. {
  21. position_x=random()%78;
  22. speed_y=random()%3+1;
  23. }
  24. void SetLever(int i)
  25. {
  26. lever=i;
  27. }
  28. void Update()
  29. {
  30. if(delaytime%lever==0)
  31. position_y+=speed_y;
  32. }
  33. };

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 .

  1. //Game plappy bird
  2. void flappyBird()
  3. {
  4. Bird chim; //khởi tạo đối tượng
  5. Cot cott1(cottren,84,-10);
  6. Cot cotd1(cotduoi,84,30);
  7. Cot cott2(cottren,135,-10);
  8. Cot cotd2(cotduoi,135,30);
  9. bool play=true;
  10. int diem=0;
  11. while(1)
  12. {
  13. if(play)
  14. {
  15. display.clearDisplay();
  16. display.setCursor(70,0);
  17. display.print(diem); //in điểm ra màn hình
  18. chim.drawBird(); //vẽ chim
  19. chim.Update(); //cập nhật vị trí chim
  20. DieuKhien(); //đọc trang thái điều khiển
  21. if(buttonTren==HIGH) //nếu buttonTren được nhấn gọi hàm fly();
  22. {
  23. chim.Fly();
  24. }
  25.  
  26. cott1.drawImage(); //Vẽ cột
  27. cott2.drawImage();
  28. cotd1.drawImage();
  29. cotd2.drawImage();
  30. cott1.Update();
  31. cott2.Update();
  32. cotd1.Update();
  33. cotd2.Update();
  34.  
  35. if(cott1.vaCham(chim)||cotd1.vaCham(chim) //kiểm tra va chạm
  36. ||cott2.vaCham(chim)||cotd2.vaCham(chim))
  37. {
  38. play=false; //nếu va chạm thì gameOver
  39. }
  40. if(cott1.GetPositionx()<-9) // khi đối tượng cột đi hết màn hình cài đặt
  41. { // lại vị trí đối tượng
  42. int tam=random()%21-16;
  43. int tam1=tam+40;
  44. cott1.SetPositionx(84);
  45. cott1.SetPositiony(tam);
  46. cotd1.SetPositionx(84);
  47. cotd1.SetPositiony(tam1);
  48. diem++;
  49. }
  50. if(cott2.GetPositionx()<-9)
  51. {
  52. int tam2=random()%21-16;
  53. int tam3=tam2+40;
  54. cott2.SetPositiony(tam2);
  55. cotd2.SetPositiony(tam3);
  56. cotd2.SetPositionx(84);
  57. cott2.SetPositionx(84);
  58. diem++;
  59. }
  60.  
  61. display.display();
  62. if(stopGame==HIGH) //ấn nút stop thì dừng game , đưa CT vào 1 vòng lặp
  63. {
  64. while(1)
  65. {
  66. DieuKhien();
  67. if(buttonTren==HIGH) break; //ấn button Trên tiếp tục chơi
  68. if(buttonDuoi==HIGH) break; //ấn buttonDuoi quay lại màn hình chính
  69. }
  70. if(buttonDuoi==HIGH) break;
  71. }
  72. if(++delaytime>36000) delaytime=0;
  73. }
  74. else
  75. {
  76. display.clearDisplay();
  77. display.setCursor(15,10);
  78. display.print("Game Over");
  79. display.setCursor(40,20);
  80. display.print(diem);
  81. display.display();
  82. DieuKhien();
  83. if(buttonTrai==HIGH) //ấn button Trái tiếp tục chơi
  84. {
  85. play=true;
  86. diem=0;
  87. }
  88. if(buttonDuoi==HIGH){break;} //ấn buttonDuoi quay lại màn hình chính
  89. cott1.SetPositionx(84);
  90. cotd1.SetPositionx(84);
  91. cott2.SetPositionx(126);
  92. cotd2.SetPositionx(126);
  93. }
  94. }
  95. }

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

  1. void ChoCaAn()
  2. {
  3. Fish chuca; //Khởi tạo các đối tượng
  4. ThucAn thucans[10];
  5. bool Play=true;
  6. int mang=3;
  7. int diem=0;
  8. int lever=25; //cấp độ chơi
  9. for(int i=0;i<10;i++)
  10. {
  11. thucans[i].Random(); //khởi tạo ngẩu nhiên vị trị thức ăn
  12. }
  13. while(1)
  14. {
  15. if(Play)
  16. {
  17. display.clearDisplay();
  18. for(int i=0;i<10;i++)
  19. {
  20. thucans[i].Update(); //Cập nhật vị trí
  21. thucans[i].drawThucAn(); //vẽ đối tượng thức ăn
  22. if(thucans[i].vaCham(chuca)) // kiểm tra va chạm
  23. {
  24. diem++; //nếu va chạm tăng điểm lên 1
  25. if(diem%100==0) {lever--;if(lever<0)lever=0;thucans[i].SetLever(lever);}
  26. thucans[i].SetPositiony(0);
  27. thucans[i].Random(); //khởi tạo lại thức ăn
  28. chuca.SetAn(21);
  29. }
  30. if(thucans[i].GetPositiony()>=48)
  31. {
  32. thucans[i].SetPositiony(0);
  33. mang--;
  34. if(mang==0)Play=false;
  35. }
  36. }
  37. DieuKhien();
  38. chuca.Update();
  39. chuca.drawFish();
  40.  
  41. display.print(diem);
  42. display.setCursor(65,0);
  43. for(int i=0;i<mang;i++)
  44. {display.write(3);}
  45. display.display();
  46.  
  47. if(stopGame==HIGH) //Dừng game
  48. {
  49. while(1)
  50. {
  51. DieuKhien();
  52. if(buttonTren==HIGH) break;
  53. if(buttonDuoi==HIGH) break;
  54. }
  55. if(buttonDuoi==HIGH) break;
  56. }
  57.  
  58. if(++delaytime>36000) delaytime=0;
  59. }
  60. else
  61. {
  62. display.clearDisplay();
  63. display.setCursor(15,10);
  64. display.print("Game Over");
  65. display.setCursor(40,20);
  66. display.print(diem);
  67. display.display();
  68. DieuKhien();
  69. if(buttonTren==HIGH)
  70. {
  71. diem=0;
  72. mang=3;
  73. for(int i=0;i<10;i++)
  74. {
  75. thucans[i].Random();
  76. thucans[i].SetPositiony(0);
  77. thucans[i].SetLever(25);
  78. lever=25;
  79. }
  80. Play=true;
  81. }
  82. if(buttonDuoi==HIGH){break;}
  83. }
  84. }
  85. }

Demo

Bình luận
Nội dung này chưa có bình luận, hãy gửi bình luận đầu tiên của bạn.
VIẾT BÌNH LUẬN CỦA BẠN