-
-
-
Tổng tiền thanh toán:
-
Làm game flappy bird
17/06/2019
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 ) 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