Day4 07-tetris

2024. 2. 4. 15:57arduino

  • OLED와 조이스틱을 이용한 테트리스 게임
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int restartButtonPin = 2;
const int xPin = A0;
const int yPin = A1;

int xPos = 0;
int yPos = 0;

const int BLOCK_SIZE = 4;
const int BLOCK_TYPES = 9;
const int BOARD_WIDTH = 15;
const int BOARD_HEIGHT = 15;

byte tetrominoes[BLOCK_TYPES][4] = {
    {B00001111, B00000000, B00000000, B00000000},
    {B00000110, B00000111, B00000000, B00000000},
    {B00001100, B00000111, B00000000, B00000000},
    {B00001100, B00001100, B00000000, B00000000},
    {B00000110, B00001100, B00000000, B00000000},
    {B00001100, B00001110, B00000000, B00000000},
    {B00000100, B00001111, B00000000, B00000000},
};

int board[BOARD_HEIGHT][BOARD_WIDTH] = {0};

int currentX = BOARD_WIDTH / 2;
int currentY = 0;
int currentBlock = 0;
int rotation = 0;

unsigned long previousMillis = 0;
const long interval = 500;

unsigned long lastRotationTime = 0;
const unsigned long rotationDelay = 200;
int score = 0;  // 추가된 부분: 점수 변수

void setup() {
  pinMode(restartButtonPin, INPUT_PULLUP);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  randomSeed(analogRead(A3));
  newBlock();
}

void loop() {
  xPos = analogRead(xPin);
  yPos = analogRead(yPin);

  handleInput();

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (!move(0, 1)) {
      updateBoard();
      int linesCleared = checkLines(); // 추가된 부분: 지워진 라인 수에 따라 점수 증가
      if (linesCleared > 0) {
        score += linesCleared * 100;  
        }
      newBlock();
    }
  }

  display.clearDisplay();
  drawBoard();
  drawBlock();
  display.setCursor(65, 0);
  display.print("Score:");
  display.print(score);
  display.display();
}

void handleInput() {
  if (analogRead(xPin) < 100) {
    move(-1, 0);
  } else if (analogRead(xPin) > 900) {
    move(1, 0);
  }

  if (analogRead(yPin) < 100) {
    rotateBlock();
  } else if (analogRead(yPin) > 900) {
    move(0, 1);
  }

  if (digitalRead(restartButtonPin) == LOW) {
    while (move(0, 1));
  }
}

bool move(int x, int y) {
  if (checkCollision(currentX + x, currentY + y, rotation)) {
    return false;
  }
  currentX += x;
  currentY += y;
  return true;
}

void rotateBlock() {
  unsigned long currentMillis = millis();
  if (currentMillis - lastRotationTime >= rotationDelay) {
    lastRotationTime = currentMillis;
    int newRotation = (rotation + 1) % 4;
    if (checkCollision(currentX, currentY, newRotation)) {
      return;
    }
    rotation = newRotation;
  }
}

bool checkCollision(int x, int y, int rot) {
  for (int row = 0; row < 4; row++) {
    for (int col = 0; col < 4; col++) {
      if (tetrominoes[currentBlock][rotate(row, col, rot)] &&
          (board[y + row][x + col] != 0 || x + col < 0 || x + col >= BOARD_WIDTH || y + row >= BOARD_HEIGHT)) {
        return true;
      }
    }
  }
  return false;
}

int rotate(int row, int col, int rot) {
  switch (rot) {
    case 0: return row * 4 + col;
    case 1: return 12 + row - col * 4;
    case 2: return 15 - row * 4 - col;
    case 3: return 3 - row + col * 4;
  }
  return 0;
}

void updateBoard() {
  for (int row = 0; row < 4; row++) {
    for (int col = 0; col < 4; col++) {
      if (tetrominoes[currentBlock][rotate(row, col, rotation)]) {
        board[currentY + row][currentX + col] = currentBlock + 1;
      }
    }
  }
} //스테이지

int checkLines() {
  int linesCleared = 0;
  for (int row = BOARD_HEIGHT - 1; row >= 0; row--) {
    bool lineIsFull = true;
    for (int col = 0; col < BOARD_WIDTH; col++) {
      if (board[row][col] == 0) {
        lineIsFull = false;
        break;
      }
    }
    if (lineIsFull) {
      linesCleared++;
      for (int j = row; j > 0; j--) {
        for (int col = 0; col < BOARD_WIDTH; col++) {
          board[j][col] = board[j - 1][col];
        }
      }
      for (int col = 0; col < BOARD_WIDTH; col++) {
        board[0][col] = 0;
      }

    }
  }
  return linesCleared;
}


void newBlock() {
  currentX = BOARD_WIDTH / 2;
  currentY = 0;
  currentBlock = random(0, BLOCK_TYPES);
  rotation = 0;
  if (checkCollision(currentX, currentY, rotation)) {
    for (int row = 0; row < BOARD_HEIGHT; row++) {
      for (int col = 0; col < BOARD_WIDTH; col++) {
        board[row][col] = 0;
      }
    }
    display.clearDisplay();
    display.setCursor(20, 20);
    display.print("GAME OVER");
    display.display();
    while (digitalRead(restartButtonPin) == HIGH); // 재시작 버튼이 눌릴 때까지 대기합니다.
    delay(200); // 디바운스를 위해 잠시 딜레이를 추가합니다.
    newBlock(); // 새 블록을 생성하여 새 게임을 시작합니다.
  }
}

void drawBoard() {
  // Draw the border
  display.drawRect(0, 0, BOARD_WIDTH * BLOCK_SIZE, BOARD_HEIGHT * BLOCK_SIZE, SSD1306_WHITE);

  for (int row = 0; row < BOARD_HEIGHT; row++) {
    for (int col = 0; col < BOARD_WIDTH; col++) {
      int blockType = board[row][col];
      if (blockType > 0) {
        display.fillRect(col * BLOCK_SIZE + 1, row * BLOCK_SIZE + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2, SSD1306_WHITE);
      }
    }
  }
}

void drawBlock() {
  for (int row = 0; row < 4; row++) {
    for (int col = 0; col < 4; col++) {
      if (tetrominoes[currentBlock][rotate(row, col, rotation)]) {
        int x = (currentX + col) * BLOCK_SIZE;
        int y = (currentY + row) * BLOCK_SIZE;
        display.fillRect(x, y, BLOCK_SIZE, BLOCK_SIZE, SSD1306_WHITE);
      }
    }
  }
}

'arduino' 카테고리의 다른 글

Day4 06-joystick  (0) 2024.02.04
Day4 05-DCmotor, button 2  (0) 2024.02.04
Day4 04-DCmotor, button  (0) 2024.02.04
Day4 03-DCmotor  (0) 2024.02.04
Day4 02-encoder  (0) 2024.02.04