PCBX
Published

Building a Push Box Game with Arduino Nano and SSSD1306 OLED

Build a Push Box Game with Arduino Nano and SSD1306 OLED with PCBX Simulation! Create a fun, interactive experience.

BeginnerProtip141

Things used in this project

Story

Read more

Schematics

push_GxvCml9sXW.png

Code

Untitled file

Arduino
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET    -1 // Reset pin # (or -1 if sharing Arduino reset pin)

// 初始化OLED显示屏
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// 游戏地图的尺寸(以方块为单位)
#define MAP_WIDTH 16 // 地图宽度,方块数
#define MAP_HEIGHT 8 // 地图高度,方块数

// 玩家、箱子和目标的位置
int playerX = 1;
int playerY = 1;
int boxX[2] = {2, 4};
int boxY[2] = {1, 3};
int targetX[2] = {3, 5}; // 两个目标位置
int targetY[2] = {1, 3};
bool gameRunning = true;

// 按钮引脚
const int buttonUp = 2;
const int buttonDown = 3;
const int buttonLeft = 4;
const int buttonRight = 5;

void setup() {
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3C for 128x64
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.println("推箱子游戏");
  display.display();
  delay(2000); // 显示初始化效果2秒
  initGame();
  // 初始化按钮引脚为输入上拉模式
  pinMode(buttonUp, INPUT_PULLUP);
  pinMode(buttonDown, INPUT_PULLUP);
  pinMode(buttonLeft, INPUT_PULLUP);
  pinMode(buttonRight, INPUT_PULLUP);
}

void loop() {
  if (gameRunning) {
    readButtons();
    updateGame();
    drawMap();
    delay(100);
  }
}

void initGame() {
  // 初始化游戏状态
  playerX = 1;
  playerY = 1;
  boxX[0] = 2;
  boxY[0] = 1;
  boxX[1] = 4;
  boxY[1] = 3;
  gameRunning = true;
}

// 绘制游戏地图
void drawMap() {
  display.clearDisplay();
  // 绘制游戏边界框的线条
  display.drawLine(0, 0, MAP_WIDTH * 5 - 1, 0, BLACK); // 上边框
  display.drawLine(0, 5 * MAP_HEIGHT - 1, MAP_WIDTH * 5 - 1, 5 * MAP_HEIGHT - 1, WHITE); // 下边框
  display.drawLine(0, 0, 0, 5 * MAP_HEIGHT - 1, WHITE); // 左边框
  display.drawLine(5 * MAP_WIDTH - 1, 0, 5 * MAP_WIDTH - 1, 5 * MAP_HEIGHT - 1, WHITE); // 右边框

  // 绘制玩家位置
  display.drawRect(playerX * 5, playerY * 5, 5, 5, WHITE); // 玩家方块尺寸:5x5

  // 绘制箱子位置
  for (int i = 0; i < 2; i++) {
    display.fillRect(boxX[i] * 5, boxY[i] * 5, 5, 5, WHITE); // 箱子方块尺寸:5x5
  }

  // 绘制目标位置,使用黄色表示
  for (int i = 0; i < 2; i++) {
    display.drawRect(targetX[i] * 5, targetY[i] * 5, 5, 5, WHITE); // 目标方块尺寸:5x5,颜色:黄色(0xFFFF)
  }

  display.display();
}

// 按钮读取和消抖逻辑
void readButtons() {
  static unsigned long lastDebounceTime = 0;
  static unsigned long debounceDelay = 50;
  unsigned long currentMillis = millis();

  if (digitalRead(buttonUp) == LOW && (currentMillis - lastDebounceTime) > debounceDelay) {
    lastDebounceTime = currentMillis;
    movePlayer(0, -1);
  }
  if (digitalRead(buttonDown) == LOW && (currentMillis - lastDebounceTime) > debounceDelay) {
    lastDebounceTime = currentMillis;
    movePlayer(0, 1);
  }
  if (digitalRead(buttonLeft) == LOW && (currentMillis - lastDebounceTime) > debounceDelay) {
    lastDebounceTime = currentMillis;
    movePlayer(-1, 0);
  }
  if (digitalRead(buttonRight) == LOW && (currentMillis - lastDebounceTime) > debounceDelay) {
    lastDebounceTime = currentMillis;
    movePlayer(1, 0);
  }
}

void movePlayer(int dx, int dy) {
  // 玩家移动逻辑
  int newX = playerX + dx;
  int newY = playerY + dy;

  // 检查新位置是否在地图范围内
  if (newX >= 0 && newX < MAP_WIDTH && newY >= 0 && newY < MAP_HEIGHT) {
    // 检查新位置是否不是墙壁
    if (!isWall(newX, newY)) {
      // 检查新位置是否是箱子
      for (int i = 0; i < 2; i++) {
        if (newX == boxX[i] && newY == boxY[i]) {
          // 尝试推动箱子
          int boxNewX = boxX[i] + dx;
          int boxNewY = boxY[i] + dy;
          if (!isWall(boxNewX, boxNewY) && !isBox(boxNewX, boxNewY)) {
            boxX[i] = boxNewX;
            boxY[i] = boxNewY;
            playerX = newX;
            playerY = newY;
            checkWinCondition();
            return;
          }
        }
      }
      // 移动玩家
      playerX = newX;
      playerY = newY;
    }
  }
}

bool isWall(int x, int y) {
  // 定义墙壁位置
  return (x == 0 || x == MAP_WIDTH - 1) || (y == 0 || y == MAP_HEIGHT - 1);
}

bool isBox(int x, int y) {
  // 检查位置是否有箱子
  for (int i = 0; i < 2; i++) {
    if (x == boxX[i] && y == boxY[i]) {
      return true;
    }
  }
  return false;
}

void checkWinCondition() {
  // 检查所有箱子是否都在目标位置
  bool allBoxesAtTarget = true;
  for (int i = 0; i < 2; i++) {
    if (boxX[i] != targetX[i] || boxY[i] != targetY[i]) {
      allBoxesAtTarget = false;
      break;
    }
  }
  if (allBoxesAtTarget) {
    gameRunning = false;
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    display.println("Congratulations!!");
    display.println("You win!");
    display.display();
    delay(300);
    initGame(); // 重新开始游戏
  }
}

void updateGame() {
  // 游戏逻辑更新
}

Credits

PCBX
33 projects • 11 followers
Customer Success: Your one-stop solution for PCB and PCBA services, plus component sourcing. Enjoy FREE online simulation and EDA.
Contact

Comments

Please log in or sign up to comment.