看到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;
}

剩下的就是一些初始化等等啦~~~
演示视频:

代码下载地址:点击我