
Собираем классическую игру Змейка на Arduino с LED-матрицей MAX7219 и джойстиком. Полный код, схема подключения и подробное объяснение игровой логики.
Змейка -- одна из самых узнаваемых игр в истории. Она стала культовой на телефонах Nokia в начале 2000-х, но сама концепция появилась ещё в 1976 году. Реализация Змейки на Arduino с LED-матрицей -- проект, который объединяет программирование, электронику и математику. Ученик работает с массивами, координатной системой на плоскости, генерацией случайных чисел, обнаружением столкновений и обработкой пользовательского ввода.
LED-матрица 8x8 на базе чипа MAX7219 идеально подходит для этого проекта. 64 светодиода формируют игровое поле, на котором змейка перемещается, растёт и ищет еду. Управление осуществляется аналоговым джойстиком -- интуитивно и удобно.
Уровень сложности: средний, подходит для 7-9 классов.

Подключение LED-матрицы MAX7219:
| MAX7219 | Arduino |
|---|---|
| VCC | 5V |
| GND | GND |
| DIN | пин 11 |
| CS | пин 10 |
| CLK | пин 13 |
Подключение джойстика:
| Джойстик | Arduino |
|---|---|
| VCC | 5V |
| GND | GND |
| VRx | A0 |
| VRy | A1 |
Модуль MAX7219 управляется тремя сигнальными проводами: DIN передаёт данные о том, какие светодиоды зажигать, CS выбирает устройство, CLK обеспечивает синхронизацию. Джойстик передаёт аналоговые значения от 0 до 1023 по осям X и Y через пины A0 и A1. В центральном положении значения около 512.
Перед загрузкой кода установите библиотеку LedControl через менеджер библиотек Arduino IDE: Скетч -- Подключить библиотеку -- Управлять библиотеками -- ввести LedControl -- Установить.

```cpp
// Змейка на Arduino с LED-матрицей 8x8 (MAX7219)
// Управление аналоговым джойстиком
#include <LedControl.h>
// Подключение MAX7219: DIN, CLK, CS, количество матриц
LedControl lc = LedControl(11, 13, 10, 1);
// Пины джойстика
const int JOY_X = A0;
const int JOY_Y = A1;
// Максимальная длина змейки
const int MAX_LENGTH = 30;
// Координаты тела змейки (массивы X и Y)
int snakeX[MAX_LENGTH];
int snakeY[MAX_LENGTH];
int snakeLength = 3; // начальная длина
// Направление движения: 0=вверх, 1=вправо, 2=вниз, 3=влево
int direction = 1;
// Координаты еды на поле
int foodX, foodY;
// Скорость игры (задержка между шагами в мс)
int gameSpeed = 300;
// Флаг окончания игры
bool gameOver = false;
void setup() {
// Включаем и настраиваем матрицу
lc.shutdown(0, false); // выводим из спящего режима
lc.setIntensity(0, 4); // яркость (0-15)
lc.clearDisplay(0); // очищаем экран
// Инициализация генератора случайных чисел
// Читаем шум с неподключённого пина A2
randomSeed(analogRead(A2));
// Начальная позиция змейки в центре поля
snakeX[0] = 4; snakeY[0] = 3; // голова
snakeX[1] = 3; snakeY[1] = 3; // тело
snakeX[2] = 2; snakeY[2] = 3; // хвост
// Размещаем первую еду
spawnFood();
}
// Генерация еды в случайной свободной ячейке
void spawnFood() {
bool onSnake;
do {
foodX = random(0, 8);
foodY = random(0, 8);
// Проверяем, не попала ли еда на тело змейки
onSnake = false;
for (int i = 0; i < snakeLength; i++) {
if (snakeX[i] == foodX && snakeY[i] == foodY) {
onSnake = true;
break;
}
}
} while (onSnake);
}
// Чтение направления с джойстика
void readJoystick() {
int x = analogRead(JOY_X);
int y = analogRead(JOY_Y);
// Пороги отклонения от центра (512)
// Змейка не может развернуться на 180 градусов
if (x < 300 && direction != 1) direction = 3; // влево
else if (x > 700 && direction != 3) direction = 1; // вправо
else if (y < 300 && direction != 2) direction = 0; // вверх
else if (y > 700 && direction != 0) direction = 2; // вниз
}
// Перемещение змейки на один шаг
void moveSnake() {
// Вычисляем новую позицию головы
int newX = snakeX[0];
int newY = snakeY[0];
switch (direction) {
case 0: newY--; break; // вверх (уменьшаем Y)
case 1: newX++; break; // вправо (увеличиваем X)
case 2: newY++; break; // вниз (увеличиваем Y)
case 3: newX--; break; // влево (уменьшаем X)
}
// Проверка столкновения со стенками поля
if (newX < 0 || newX > 7 || newY < 0 || newY > 7) {
gameOver = true;
return;
}
// Проверка столкновения с собственным телом
for (int i = 0; i < snakeLength; i++) {
if (snakeX[i] == newX && snakeY[i] == newY) {
gameOver = true;
return;
}
}
// Проверяем, съела ли змейка еду
bool ate = (newX == foodX && newY == foodY);
if (!ate) {
// Обычное движение: сдвигаем каждый сегмент на место предыдущего
for (int i = snakeLength - 1; i > 0; i--) {
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
} else {
// Змейка съела еду -- увеличиваем длину
if (snakeLength < MAX_LENGTH) {
for (int i = snakeLength; i > 0; i--) {
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
snakeLength++;
// Ускоряем игру с каждой съеденной едой
if (gameSpeed > 100) gameSpeed -= 20;
// Генерируем новую еду
spawnFood();
}
}
// Устанавливаем новую позицию головы
snakeX[0] = newX;
snakeY[0] = newY;
}
// Отрисовка игрового поля на матрице
void drawGame() {
lc.clearDisplay(0);
// Рисуем все сегменты змейки
for (int i = 0; i < snakeLength; i++) {
lc.setLed(0, snakeY[i], snakeX[i], true);
}
// Рисуем еду
lc.setLed(0, foodY, foodX, true);
}
// Анимация проигрыша -- мигание всей матрицы
void showGameOver() {
for (int k = 0; k < 3; k++) {
for (int row = 0; row < 8; row++) {
lc.setRow(0, row, 0xFF); // зажигаем всю строку
}
delay(300);
lc.clearDisplay(0);
delay(300);
}
// Сброс игры к начальным параметрам
snakeLength = 3;
snakeX[0] = 4; snakeY[0] = 3;
snakeX[1] = 3; snakeY[1] = 3;
snakeX[2] = 2; snakeY[2] = 3;
direction = 1;
gameSpeed = 300;
gameOver = false;
spawnFood();
}
void loop() {
if (gameOver) {
showGameOver();
return;
}
readJoystick(); // считываем положение джойстика
moveSnake(); // перемещаем змейку
if (!gameOver) {
drawGame(); // перерисовываем поле
}
delay(gameSpeed); // ждём перед следующим шагом
}
`
Библиотека LedControl. Для работы с матрицей MAX7219 используется библиотека LedControl. Метод setLed(матрица, строка, столбец, вкл/выкл) зажигает или гасит отдельный светодиод. Метод setRow() управляет целой строкой -- мы используем его для анимации проигрыша, заливая все строки разом.
Хранение тела змейки. Координаты каждого сегмента хранятся в двух массивах: snakeX[] и snakeY[]. Индекс 0 -- это всегда голова. При движении каждый сегмент принимает координаты предыдущего, а голова получает новую позицию на основе текущего направления. Этот алгоритм -- ключ к пониманию того, как работают очереди и связные структуры данных.
Чтение джойстика. Аналоговый джойстик возвращает значения от 0 до 1023. В покое -- около 512. Пороги 300 и 700 дают надёжное определение отклонения. Важная деталь: проверка direction != противоположное предотвращает мгновенный разворот на 180 градусов, который привёл бы к немедленному столкновению с собственным телом.
Обнаружение столкновений. Перед каждым шагом проверяются два условия: не вышла ли голова за границы поля 8x8 и не совпала ли новая позиция головы с одним из сегментов тела. Любое из этих условий означает конец игры.
Динамическая сложность. Каждая съеденная еда уменьшает gameSpeed на 20 мс, но не ниже 100 мс. Это означает, что на старте между шагами 300 мс (комфортная скорость), а после 10 съеденных объектов -- 100 мс (серьёзный вызов для рефлексов).
Начните с объяснения координат. Прежде чем писать код, нарисуйте на доске сетку 8x8 и покажите, как координаты (X, Y) определяют позицию на поле. Пусть ученики вручную «проиграют» несколько шагов змейки, записывая координаты каждого сегмента.
Отладка через Serial Monitor. Добавьте Serial.begin(9600) в setup() и выводите координаты головы и направление в loop(). Это поможет ученикам понять, что происходит внутри программы, когда на матрице что-то идёт не так.
Задания для продвинутых. Реализуйте прохождение сквозь стены -- змейка выходит с противоположной стороны поля. Добавьте подсчёт очков через семисегментный дисплей. Подключите пьезодинамик для звуковых эффектов при поедании еды и столкновении.
В каталоге Alashed Hardware доступны готовые комплекты с LED-матрицей MAX7219, джойстиком и Arduino Uno -- всё необходимое для этого проекта в одной коробке. Среда Alashed CodeStudio позволяет писать код, компилировать и загружать скетчи прямо из браузера, что особенно удобно в классе, где нет возможности устанавливать программы на каждый компьютер.
Подключите школу к пилоту. Генерируйте КМЖ за 2 минуты, ведите CodeStudio уроки, заказывайте оборудование — всё в одном месте.