esp32cam-摇杆配0.96寸oled实现贪吃蛇游戏

这是一个子项目

最近想利用手上的esp32做一个蓝牙键盘模拟项目, 比如6个按键, 每个按键包含一组真实键盘的快捷键, 比如ctr+c/ ctr+v
实现后发现既然已经有了键盘, 为何不再加个屏幕输出, 用来做个小游戏, 于是就有了本文

其实很简单, 就是使用oled画图, 四个点像素为蛇头跟食物, 撞到自己或者撞到边界就死亡, 至于食物就是随机出现即可

#include <Wire.h>
// 软件库中搜索即可
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

/**
 * 本project用于贪吃蛇, 使用软IIC接口 14-SCL 15SDA
 */

Adafruit_SSD1306 oled(128, 64, &Wire, -1);



#define RIGHT 0
#define LEFT  1
#define UP    2
#define DOWN  3

//摇杆相关变量
#define pinX  13
#define pinY  12

int valueX = 0;
int valueY = 0;
unsigned char keyValue = 0;


//蛇相关变量

const uint8_t block[] PROGMEM = {
  0xf0, //B1111000
  0xb0, //B1011000
  0xd0, //B1101000
  0xf0, //B1111000
};


uint8_t snake_head_x = 4;
uint8_t snake_head_y = 4;
uint8_t x[100];
uint8_t y[100];
uint8_t snake_len = 2;
uint8_t snake_dir = RIGHT;

uint8_t food_x;
uint8_t food_y;
bool food_eaten = true;

bool game_over = false;
int score = 0;
int level = 1;
int snake_speed = 150;
int i;

//按键扫描函数
void keyScan(void)
{
  static unsigned char keyUp = 1;

  valueX = analogRead(pinX);
  valueY = analogRead(pinY);

  if (keyUp && ((valueX <= 10) || (valueX >= 1010) || (valueY <= 10) || (valueY >= 1010)))
  {
    delay(10);
    keyUp = 0;
    if (valueX <= 10)
    {
      if (snake_dir != LEFT)
      {
        snake_dir = RIGHT;
      }
    }
    else if (valueX >= 1010)
    {
      if (snake_dir != RIGHT)
      {
        snake_dir = LEFT;
      }
    }
    else if (valueY <= 10)
    {
      if (snake_dir != UP)
      {
        snake_dir = DOWN;
      }
    }
    else if (valueY >= 1010)
    {
      if (snake_dir != DOWN)
      {
        snake_dir = UP;
      }
    }
  } else if ((valueX > 10) && (valueX < 1010) && (valueY > 10) && (valueY < 1010))keyUp = 1;
  return;
}

void draw_snake(int x, int y)
{
  oled.drawBitmap(x, y, block, 4, 4, 1);
}

void show_score(int x, int y, int data)
{
  oled.setCursor(x, y);//设置显示位置
  oled.println(data);

}

void screen(void)
{
  oled.clearDisplay();//清屏
  oled.setTextSize(1); //设置字体大小
  oled.drawRect(0, 1, 102, 62, 1);
  oled.drawRect(0, 0, 102, 64, 1);
  oled.setCursor(104, 12);//设置显示位置
  oled.println("LEVE");
  oled.setCursor(104, 40);//设置显示位置
  oled.println("SCOR");

  show_score(110, 25, level);
  show_score(110, 53, score);

  for (i = 0; i < snake_len; i++)
  {
    draw_snake(x[i], y[i]);
  }

  draw_snake(food_x, food_y);

  oled.display();

}

void draw_food(void)
{
  int food_out = 0; //判断食物是否在蛇体内

  if (food_eaten)
  {
    while (food_out == 0)
    {
      food_out = 1;

      food_x = (uint8_t)(random(4, 100) / 4) * 4;
      food_y = (uint8_t)(random(4, 60) / 4) * 4;

      for (int i = snake_len - 1; i > 0; i--) //遍历整个蛇身方块,若食物在蛇身内则重新生成
      {
        if (food_x == x[i] && food_y == y[i])
        {
          food_out = 0;
        }
      }
    }
  }

  food_eaten = false;
}

void snake_move(void)
{
  switch (snake_dir) {
    case RIGHT:
      snake_head_x += 4;
      break;
    case UP:
      snake_head_y -= 4;
      break;
    case LEFT:
      snake_head_x -= 4;
      break;
    case DOWN:
      snake_head_y += 4;
      break;
  }

  if ((snake_head_x == food_x) && (snake_head_y == food_y))
  {
    food_eaten = true; //可重新生成食物
    snake_len++;
    score++;
    level = score / 5 + 1;
    snake_speed -= level;
  }

  for (i = snake_len - 1; i > 0; i--)
  {
    x[i] = x[i - 1];
    y[i] = y[i - 1];
  }
  x[0] = snake_head_x;
  y[0] = snake_head_y;

  check_snake_die();
}

void draw_game_over()
{
  oled.clearDisplay();//清屏
  oled.setTextSize(2); //设置字体大小
  oled.setCursor(10, 10);//设置显示位置

  oled.println("GAME OVER");
  oled.setTextSize(1); //设置字体大小
  oled.setCursor(30, 35);//设置显示位置
  oled.println("LEVE:");
  oled.setCursor(30, 55);//设置显示位置
  oled.println("SCOR:");

  show_score(80, 35, level);
  show_score(80, 55, score);

  oled.display();
}



void check_snake_die(void)
{
  //撞墙
  if (snake_head_x < 4 || snake_head_x > 96 || snake_head_y < 1 || snake_head_y > 56)
  {
    game_over = true;
  }

  //自己吃自己
  if (snake_len > 4)
  {
    for (int i = 1; i < snake_len; i++)
    {
      if (snake_head_x == x[i] && snake_head_y == y[i])
      {
        game_over = true;
      }
    }
  }
}


/**
 * 初始化oled的软IIC设置, 
 * 注意在oled.begin中后面两个false是关闭Wire.begin的操作, 
 * 不然还是会使用默认的操作
 */
void oledInit() {
  Wire.begin(15,14); // SDA, SCL
//  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false);
}
void setup()
{
  oledInit();

  oled.setTextColor(WHITE);//开像素点发光
  randomSeed(analogRead(3));//初始化随机种子
}


void loop()
{
  if (game_over)
  {
    draw_game_over();
  } else {
    keyScan();
    snake_move();
    draw_food();
    screen();
  }
  delay(snake_speed);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落子无悔!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>