#include <FastLED.h>
// Настройки матрицы WS2812
#define LED_PIN 6 // Пин подключения матрицы WS2812
#define NUM_LEDS 64 // 8x8 матрица = 64 светодиодов
#define BRIGHTNESS 50 // Яркость матрицы
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS]; // Массив для хранения состояния каждого светодиода на матрице
// Пины для кнопок управления
#define BUTTON_UP 2
#define BUTTON_DOWN 3
#define BUTTON_LEFT 4
#define BUTTON_RIGHT 5
#define BUTTON_RESTART 7 // Кнопка для перезапуска игры
// Структура для хранения координат змейки
struct SnakeSegment {
int x, y; // Координаты сегмента змейки на матрице
};
SnakeSegment snake[NUM_LEDS]; // Массив для хранения координат всех сегментов змейки
int snakeLength = 1; // Начальная длина змейки
int appleX = -1, appleY = -1; // Координаты яблока
// Направление змейки
enum Direction { UP, DOWN, LEFT, RIGHT };
Direction dir = RIGHT; // Начальное направление змейки — вправо
// Очки
int score = 0;
void setup() {
// Инициализация последовательного порта для вывода информации о счете
Serial.begin(9600);
// Инициализация матрицы светодиодов
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS); // Установка яркости
// Инициализация пинов кнопок
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
pinMode(BUTTON_LEFT, INPUT_PULLUP);
pinMode(BUTTON_RIGHT, INPUT_PULLUP);
pinMode(BUTTON_RESTART, INPUT_PULLUP);
// Начальная позиция змейки
snake[0].x = 1;
snake[0].y = 1;
applePosition(); // Генерация начальной позиции яблока
}
void loop() {
updateDirection(); // Проверка нажатия кнопок и обновление направления
moveSnake(); // Движение змейки
displayGame(); // Отображение состояния игры на матрице
delay(100); // Задержка для контроля скорости игры
}
// Функция для перемещения змейки
void moveSnake() {
// Сдвигаем каждый сегмент змейки в массиве на одно место
for (int i = snakeLength - 1; i > 0; i--) {
snake[i] = snake[i - 1];
}
// Перемещаем голову змейки в направлении, заданном переменной 'dir'
switch (dir) {
case UP: snake[0].y--; break;
case DOWN: snake[0].y++; break;
case LEFT: snake[0].x--; break;
case RIGHT: snake[0].x++; break;
}
// Проверка на столкновение с границами игрового поля
if (snake[0].x < 0 || snake[0].x >= 16 && snake[0].y < 0 || snake[0].y >= 16) {
gameOver(); // Игра завершена
}
// Проверка на столкновение с собственным хвостом
for (int i = 1; i < snakeLength; i++) {
if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
gameOver(); // Игра завершена
}
}
// Проверка на поедание яблока
if (snake[0].x == appleX && snake[0].y == appleY) {
score++; // Увеличиваем очки
snakeLength++; // Увеличиваем длину змейки
applePosition(); // Генерация нового яблока
}
}
// Функция для генерации случайных координат для яблока
void applePosition() {
appleX = random(0, 16); // Случайная координата X яблока
appleY = random(0, 16); // Случайная координата Y яблока
}
// Функция для отображения игры на матрице WS2812
void displayGame() {
fill_solid(leds, NUM_LEDS, CRGB::Black); // Очистка экрана (выключаем все светодиоды)
// Отображаем каждый сегмент змейки на экране
for (int i = 0; i < snakeLength; i++) {
leds[snake[i].y * 16 + snake[i].x] = CRGB::Green; // Зеленый для змейки
}
// Отображаем яблоко на экране
leds[appleY * 16 + appleX] = CRGB::Red; // Красный для яблока
FastLED.show(); // Обновляем матрицу, чтобы отобразить изменения
// Выводим текущий счет в последовательный порт
Serial.print("Score: ");
Serial.println(score);
}
// Функция для обновления направления движения змейки
void updateDirection() {
// Проверка нажатия кнопок и изменение направления змейки
if (digitalRead(BUTTON_UP) == LOW && dir != DOWN) {
dir = UP; // Если кнопка вверх нажата, змейка идет вверх
}
if (digitalRead(BUTTON_DOWN) == LOW && dir != UP) {
dir = DOWN; // Если кнопка вниз нажата, змейка идет вниз
}
if (digitalRead(BUTTON_LEFT) == LOW && dir != RIGHT) {
dir = LEFT; // Если кнопка влево нажата, змейка идет влево
}
if (digitalRead(BUTTON_RIGHT) == LOW && dir != LEFT) {
dir = RIGHT; // Если кнопка вправо нажата, змейка идет вправо
}
}
// Функция для завершения игры и перезапуска
void gameOver() {
Serial.print("Game Over! Score: ");
Serial.println(score);
delay(1000); // Задержка перед перезапуском игры
// Ожидаем нажатия кнопки для перезапуска игры
while (digitalRead(BUTTON_RESTART) == HIGH) {
// Ждем нажатие кнопки для перезапуска
}
restartGame(); // Перезапускаем игру
}
// Функция для перезапуска игры
void restartGame() {
score = 0; // Сбрасываем счет
snakeLength = 1; // Сбрасываем длину змейки
snake[0].x = 0; // Начальная позиция головы змейки
snake[0].y = 0;
applePosition(); // Генерируем новое яблоко
dir = RIGHT; // Направление змейки на старте — вправо
}