nguoimegame gửi vào
- 27318 lượt xem
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 ) 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