【自制】單片機也能玩遊戲。up在esp32上寫了個flappy bird(box)
csdn:https://blog.csdn.net/zhong1213/article/details/105781758
個人博客:https://hanbaoaaa.xyz/index.php/archives/65/k.html
視頻地址:https://www.bilibili.com/video/BV1r7411U7ra/
代碼位於github:https://github.com/ActivePeter/esp32_flappy_bird
硬件平臺 ttgo-t-display (esp32)
軟件平臺platform io in vscode
(一)驅動部分
顯示屏
#include <TFT_eSPI.h>
按鍵
#include <Button2.h>
對顯示屏部分做出了一定的修改
加入了顯示信息緩衝區unsigned short buffer[32400]={0};
加入了往顯示屏緩衝區繪製長方體的函數
void drawRectToBuffer(int x,int y,int w,int h,u_short color){
int i,j;
if(x<0){
w=w+x;
x=0;
}
if(y<0){
h=h+y;
y=0;
}
if(x+w>ScreenW){//修正超出範圍
w=ScreenW-x;
}
if(y+h>ScreenH){//修正超出範圍
h=ScreenH-y;
}
for(i=0;i<h;i++){
for(j=0;j<w;j++){
buffer[(j+x)*ScreenH+(i+y)]=color;
}
}
}
初始化顯示屏
void initTFT(){
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextSize(2);
tft.setTextColor(TFT_WHITE);
tft.setCursor(0, 0);
tft.setTextDatum(MC_DATUM);
tft.setTextSize(1);
if (TFT_BL > 0)
{ // TFT_BL has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode
digitalWrite(TFT_BL, 1);
// Turn backlight on. TFT_BACKLIGHT_ON has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
}
}
(二)邏輯實現部分
兩個結構體
typedef struct{
float x;
u_char height;
} Pillar;
typedef struct{
float y;
float speed;
} Bird;
用來描述小鳥和障礙物。
整體結構
- 循環開頭,清空顯示屏緩衝區
- 更新數據
- 然後將新的數據對應的圖形繪製到緩衝區。
- 將緩衝區內容刷新到顯示屏
最主要的邏輯部分就在於更新數據
if(!dead){
drawRectToBuffer(birdX,(int)bird.y,birdW,birdW,0xFFE0);
updatePillars();
updateBird();
judgeColid();
}else{
drawRectToBuffer(birdX,(int)bird.y,birdW,birdW,0xF800)
}
(1)更新障礙物,每次增加的x值的大小決定了速度。
然後做一個判斷。有沒有超出屏幕範圍。如果超出了。就把他放到最前面。
void updatePillars(){
pillars[0].x+=0.6f;
pillars[1].x+=0.6f;
pillars[2].x+=0.6f;
if(pillars[0].x>=ScreenW){
pillars[0].x=pillars[2].x-PillarSpace-PillarW;
pillars[0].height=rand()%160+20;
}
if(pillars[1].x>=ScreenW){
pillars[1].x=pillars[0].x-PillarSpace-PillarW;
pillars[1].height=rand()%160+20;
}
if(pillars[2].x>=ScreenW){
pillars[2].x=pillars[1].x-PillarSpace-PillarW;
pillars[2].height=rand()%160+20;
}
}
(2)更新小鳥
1.每次速度都增加一定值(模擬重力)
2.再給速度減掉一個(t*速度^2)(模擬阻力)
3.將速度加到小鳥的y座標上
void updateBird(){
bird.speed+=0.15f;
bird.speed-=0.015f*(bird.speed*abs(bird.speed));
bird.y+=bird.speed;
}
(3)判斷碰撞
判斷x方向上,小鳥方塊是否和障礙物有交集
如果有交集就給curpillar賦值。
然後在判斷有交集的情況下y方向上有沒有碰撞就行了。
同時記錄lastpillar
如果上一次pillar值記錄爲1或2或3
這一次記錄爲0
對應的就是鳥從上一個障礙物中飛出,
此時對應的score++
void judgeColid(){
u_char curPillar=0;
if(pillars[0].x+PillarW>=birdX&&pillars[0].x<=birdX||pillars[0].x+PillarW>=birdX+birdW&&pillars[0].x<=birdX+birdW){
curPillar=1;
}else if(pillars[1].x+PillarW>=birdX&&pillars[1].x<=birdX||pillars[1].x+PillarW>=birdX+birdW&&pillars[1].x<=birdX+birdW){
curPillar=2;
}else if(pillars[2].x+PillarW>=birdX&&pillars[2].x<=birdX||pillars[2].x+PillarW>=birdX+birdW&&pillars[2].x<=birdX+birdW){
curPillar=3;
}
if(lastPillar&&(!curPillar)){
score++;
}
lastPillar=curPillar;
if(curPillar){
if(bird.y<=ScreenH - pillars[curPillar-1].height -KongxiHeight){
dead=true;
}else if(bird.y+birdW>=ScreenH - pillars[curPillar-1].height){
dead=true;
}
}else{
if(bird.y<0||bird.y+birdW>=ScreenH){
dead=true;
}
}
}