ESP32上的flappy bird
看到B站很多大佬都在单片机上运行flappy bird小游戏,自己也想试一试,顺便提升自己的编程思路!
开发平台:platform平台(不得不说这是一个好东西)+Arduino框架
硬件:ESP32、ILI9341
编程思路:
新建水管结构体,包含水管参数与水管更新删除函数:
struct Tube //管子结构体
{
int point;
int last_point;
int hole;
int hole_h;
void Init(int a, int b, int c)
{
point = a;
last_point = point;
hole = b;
hole_h = c;
}
void refresh() //绘制管子 在这里绘制管子是先用背景色覆盖上一次的,在绘制多余的管子部分
{
tft.fillRoundRect(0, point, hole - 10, TUBE_SPEED, 4, TUBE_COLOR);
tft.fillRoundRect(hole + hole_h + 10, point, 240 - hole - hole_h - 10, TUBE_SPEED, 4, TUBE_COLOR); //绘制管子
tft.fillRoundRect(hole - 10, point - 10, 10, 10, 4, TUBE_COLOR); //绘制管子边缘凸出部分
tft.fillRoundRect(hole + hole_h, point - 10, 10, 10, 4, TUBE_COLOR);
tft.fillRoundRect(hole - 10, point + TUBE_WIDTH + 6, 10, 7, 4, TUBE_COLOR); //绘制右边突出部分的圆角
tft.fillRoundRect(hole + hole_h, point + TUBE_WIDTH + 6, 10, 7, 4, TUBE_COLOR);
}
void delet() //删除管子
{
tft.fillRect(0, last_point + TUBE_WIDTH, hole - 10, TUBE_SPEED, COLOR_BK);
tft.fillRect(hole + hole_h + 10, last_point + TUBE_WIDTH, 240 - hole - hole_h - 10, TUBE_SPEED, COLOR_BK); //删除管子
tft.fillRect(hole - 10, last_point + TUBE_WIDTH + 6, 10, 10, COLOR_BK); //删除管子边缘突出部分
tft.fillRect(hole + hole_h, last_point + TUBE_WIDTH + 6, 10, 10, COLOR_BK);
}
};
小鸟结构体,包含小鸟的信息与图片更新删除函数
struct Bird //小鸟结构体
{
int g, v, point, last_point;
void refresh() //更新小鸟数据
{
v += g;
v = constrain(v, -5, 5);
point += v;
point = constrain(point, 0, 240);
if (point == 0)
{
v = 0;
}
if (v > 0) // 小鸟上升和下降的图片不一样的
tft.drawXBitmap(point, 50, pic1, pic_w, pic_w, bird_color);
else
tft.drawXBitmap(point, 50, pic2, pic_w, pic_w, bird_color);
tft.drawNumber(score, point, 20);
last_point = point;
}
void delet()
{
tft.fillRect(last_point, 50, 32, 32, COLOR_BK);
int black;
if (score < 10)
black = 10;
else if (score >= 10)
black = 25;
else
black = 60;
tft.fillRect(last_point, 20, black, 20, COLOR_BK); //抹去上一次的图像
}
};
绘制管子:
void protract_tube(void) //绘制管子
{
for (int i = 0; i < TUBE_NUM; i++)
{
tube[i].refresh();
tube[i].last_point = tube[i].point;
tube[i].point -= TUBE_SPEED;
if (tube[i].point < -40) //管子走到头了
{
tube[i].point = 300;
tube[i].hole = random(30, 100);
tube[i].hole_h = random(80, 100);
tft.fillRect(0, 0, 240, 20, COLOR_BK);
score++;
}
}
}
删除管子:
void cover_tube(void) //黑色覆盖管子
{
for (int i = 0; i < TUBE_NUM; i++)
tube[i].delet();
}
定时器回调函数,这个函数中更新小鸟与管子:
void tim1Interrupt() //定时器回调函数
{
if (tim1_tube++ > (TUBE_REFRESH_TIME)) //到时间了,可以进行更新了
{
tim1_tube = 0;
if (!game_over)
{
cover_tube();
protract_tube();
}
}
if (tim1_bird++ > (BIRD_REFRESH_TIME))
{
tim1_bird = 0;
if (!game_over)
{
game_over = knock_detect();
bird.delet();
bird.refresh();
}
}
}
按键向上运动函数以及重生:
void handle_key1() //按键中断函数
{
if (digitalRead(key1) == 0)
{
delay(10);//按键消抖
if (digitalRead(key1) == 0)
{
bird.v = 5;
if (game_over) //进行下一次游戏,并且给管子小鸟赋初值
{
tft.fillScreen(COLOR_BK);
score = 0;
game_over = 0;
bird.v = 0;
bird.point = 80;
tube[0].Init(300, 50, 120);
tube[1].Init(150, 50, 120);
}
}
}
}
碰撞检测,小鸟死亡变成红色:
bool knock_detect(void) //碰撞检测
{
int bird_top = bird.point + 28;
int bird_btm = bird.point;
int bird_left = 50;
int bird_right = 78;
for (int i = 0; i < 2; i++)
{
if ((tube[i].point <= bird_right) && ((tube[i].point + TUBE_WIDTH) >= bird_right) || (((tube[i].point + TUBE_WIDTH) > bird_left) && (tube[i].point + TUBE_WIDTH) < bird_right))
{
if (bird_btm < tube[i].hole || bird_top > (tube[i].hole + tube[i].hole_h))
{
bird_color = TFT_RED;
draw_over_page = 1;
return 1;
}
}
}
bird_color = TFT_YELLOW;
return 0;
}
剩下的就是一些初始化等等啦~~~
演示视频:
代码下载地址:点击我
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。