l #include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define JOY_X A0
#define JOY_Y A1
#define JOY_BTN 2
#define BUZZER 3 // Новый пин для звука
#define BLOCK_SIZE 5
#define BOARD_WIDTH 10
#define BOARD_HEIGHT 12
int board[BOARD_HEIGHT][BOARD_WIDTH] = {0};
struct Piece {
const int blocks[4][2];
int size;
};
Piece tetrominoes[] = {
{{{0,0},{1,0},{0,1},{1,1}}, 2},
{{{0,0},{1,0},{2,0},{3,0}}, 4},
{{{0,0},{1,0},{2,0},{2,1}}, 3},
{{{0,0},{1,0},{2,0},{0,1}}, 3},
{{{0,0},{1,0},{1,1},{2,1}}, 3},
{{{1,0},{2,0},{0,1},{1,1}}, 3},
{{{1,0},{0,1},{1,1},{2,1}}, 3},
};
int currentPiece, rotation = 0;
int posX = 3, posY = 0;
unsigned long lastFall = 0;
int fallDelay = 500;
// === ЗВУК ===
void playTone(int freq, int duration) {
tone(BUZZER, freq, duration);
delay(duration);
noTone(BUZZER);
}
// === ГРАФИКА ===
void drawBlock(int x, int y) {
display.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, SSD1306_WHITE);
}
void drawBoard() {
display.clearDisplay();
for (int y = 0; y < BOARD_HEIGHT; y++) {
for (int x = 0; x < BOARD_WIDTH; x++) {
if (board[y][x])
drawBlock(x, y);
}
}
Piece piece = tetrominoes[currentPiece];
for (int i = 0; i < 4; i++) {
int px = posX + rotateX(piece.blocks[i][0], piece.blocks[i][1], rotation);
int py = posY + rotateY(piece.blocks[i][0], piece.blocks[i][1], rotation);
drawBlock(px, py);
}
display.display();
}
int rotateX(int x, int y, int r) {
switch (r % 4) {
case 0: return x;
case 1: return y;
case 2: return -x;
case 3: return -y;
}
return x;
}
int rotateY(int x, int y, int r) {
switch (r % 4) {
case 0: return y;
case 1: return -x;
case 2: return -y;
case 3: return x;
}
return y;
}
bool checkCollision(int dx, int dy, int r) {
Piece piece = tetrominoes[currentPiece];
for (int i = 0; i < 4; i++) {
int x = posX + dx + rotateX(piece.blocks[i][0], piece.blocks[i][1], r);
int y = posY + dy + rotateY(piece.blocks[i][0], piece.blocks[i][1], r);
if (x < 0 || x >= BOARD_WIDTH || y >= BOARD_HEIGHT || (y >= 0 && board[y][x]))
return true;
}
return false;
}
void fixPiece() {
Piece piece = tetrominoes[currentPiece];
for (int i = 0; i < 4; i++) {
int x = posX + rotateX(piece.blocks[i][0], piece.blocks[i][1], rotation);
int y = posY + rotateY(piece.blocks[i][0], piece.blocks[i][1], rotation);
if (y >= 0) board[y][x] = 1;
}
playTone(100, 100); // Звук посадки
}
void clearLines() {
bool cleared = false;
for (int y = BOARD_HEIGHT - 1; y >= 0; y--) {
bool full = true;
for (int x = 0; x < BOARD_WIDTH; x++) {
if (!board[y][x]) {
full = false;
break;
}
}
if (full) {
cleared = true;
for (int yy = y; yy > 0; yy--)
for (int x = 0; x < BOARD_WIDTH; x++)
board[yy][x] = board[yy - 1][x];
for (int x = 0; x < BOARD_WIDTH; x++)
board[0][x] = 0;
y++;
}
}
if (cleared) {
playTone(300, 150); // Звук очистки линии
}
}
void spawnPiece() {
currentPiece = random(0, 7);
posX = 3;
posY = -1;
rotation = 0;
if (checkCollision(0, 1, rotation)) {
// GAME OVER
display.clearDisplay();
display.setCursor(20, 30);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.println("GAME OVER");
display.display();
for (int i = 0; i < 3; i++) {
playTone(200 - i * 50, 200);
}
while (1);
}
}
void setup() {
pinMode(JOY_BTN, INPUT_PULLUP);
pinMode(BUZZER, OUTPUT);
randomSeed(analogRead(0));
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();
spawnPiece();
}
void handleInput() {
int x = analogRead(JOY_X);
int y = analogRead(JOY_Y);
static unsigned long lastMove = 0;
static bool btnPressed = false;
if (millis() - lastMove > 150) {
if (x < 400 && !checkCollision(-1, 0, rotation)) {
posX--;
playTone(700, 50);
lastMove = millis();
} else if (x > 600 && !checkCollision(1, 0, rotation)) {
posX++;
playTone(700, 50);
lastMove = millis();
}
if (y > 600 && !checkCollision(0, 1, rotation)) {
posY++;
playTone(600, 50);
lastMove = millis();
}
}
if (digitalRead(JOY_BTN) == LOW && !btnPressed) {
int newRot = (rotation + 1) % 4;
if (!checkCollision(0, 0, newRot)) {
rotation = newRot;
playTone(800, 50); // Звук поворота
}
btnPressed = true;
}
if (digitalRead(JOY_BTN) == HIGH) {
btnPressed = false;
}
}
void loop() {
handleInput();
if (millis() - lastFall > fallDelay) {
if (!checkCollision(0, 1, rotation)) {
posY++;
} else {
fixPiece();
clearLines();
spawnPiece();
}
lastFall = millis();
}
drawBoard();
}