Игра «Змейка» на Arduino и матрице 8×8 — сборка и код
Компоненты и материалы
| Arduino UNO | × | 1 |
| Модуль LED-матрицы 8×8 на MAX7219 (FC-16 или аналогичный) | × | 1 |
| Аналоговый джойстик (VRX, VRY, SW) | × | 1 |
| Arduino Proto Shield (удобно для питания и GND) | × | 1 |
| Перемычки Male/Female | × | 1 набор |
Схема подключения
Матрица 8×8 (MAX7219)
- VCC → 5V Arduino
- GND → GND Arduino
- DIN → D10
- CS → D9
- CLK → D8
Джойстик
- GND → GND
- +5V → 5V
- VRX → A0
- VRY → A1
- SW → D2 (с pull-up)
Shield надевается на Arduino — дополнительные шины 5V/GND удобны для питания матрицы и джойстика без макетки.
О проекте
Реализация классической «Змейки» на Arduino. Змейка движется постоянно, игрок управляет джойстиком, избегая столкновений с собой и границами. Поедание еды увеличивает длину и немного ускоряет игру. Базовый код — от Sergey Royz, добавлена плавность движения и рестарт по кнопке джойстика.
Код (полный скетч)
/**
* Snake — классическая игра на LED-матрице 8x8 (MAX7219)
* 23 Jun 2016, Sergey Royz & hunter Buzzell
*/
#include <LedControl.h>
/* Пины джойстика */
#define VRX A0
#define VRY A1
#define SW 2
/* Пины матрицы */
#define DIN 10
#define CLK 8
#define CS 9
#define SIZE 8
#define ADVANCE_DELAY 20 // мс между кадрами
int snake[SIZE*SIZE][2];
int length;
int food[2], v[2];
bool is_game_over = false;
long current_time, prev_advance;
int blink_count;
const short messageSpeed = 5;
LedControl lc = LedControl(DIN, CLK, CS, 1);
void init_game() {
prev_advance = current_time = 0;
blink_count = 3;
int half = SIZE / 2;
length = SIZE / 3;
for (int i = 0; i < length; i++) {
snake[i][0] = half - 1;
snake[i][1] = half + i;
}
food[0] = half + 1;
food[1] = half - 1;
v[0] = 0; v[1] = -1; // старт вверх
}
void render() {
for (int i = 0; i < length; i++)
lc.setLed(0, snake[i][0], snake[i][1], 1);
lc.setLed(0, food[0], food[1], 1);
}
void clearScreen() {
for (int x = 0; x < SIZE; x++)
for (int y = 0; y < SIZE; y++)
lc.setLed(0, x, y, 0);
}
/* Движение змейки. Возвращает true, если игра окончена */
bool advance() {
int head[2] = {snake[0][0] + v[0], snake[0][1] + v[1]};
// Столкновение со стенами
if (head[0] < 0 || head[0] >= SIZE || head[1] < 0 || head[1] >= SIZE) {
delay(1000); showGameOverMessage(); return true;
}
// Столкновение с собой
for (int i = 0; i < length; i++)
if (snake[i][0] == head[0] && snake[i][1] == head[1]) {
delay(1000); showGameOverMessage(); return true;
}
bool grow = (head[0] == food[0] && head[1] == food[1]);
if (grow) {
length++;
randomSeed(current_time);
food[0] = random(SIZE);
food[1] = random(SIZE);
}
// Сдвиг тела
for (int i = length - 1; i >= 0; i--) {
snake[i+1][0] = snake[i][0];
snake[i+1][1] = snake[i][1];
}
snake[0][0] += v[0];
snake[0][1] += v[1];
return false;
}
void setup() {
pinMode(SW, INPUT_PULLUP);
pinMode(VRX, INPUT); pinMode(VRY, INPUT);
attachInterrupt(digitalPinToInterrupt(SW), restart, RISING);
lc.shutdown(0, false);
lc.setIntensity(0, 8); // яркость 0-15
init_game();
render();
}
void loop() {
if (!is_game_over) {
clearScreen(); render();
if (current_time - prev_advance > ADVANCE_DELAY) {
is_game_over = advance();
prev_advance = current_time;
}
} else {
while (blink_count-- > 0) {
clearScreen(); delay(300);
render(); delay(300);
}
}
readControls();
current_time++;
}
void restart() { init_game(); is_game_over = false; }
void readControls() {
int dx = map(analogRead(VRX), 0, 906, 2, -2);
int dy = map(analogRead(VRY), 0, 906, -2, 2);
if (dx != 0) dx = dx / abs(dx);
if (dy != 0) dy = dy / abs(dy);
// Запрет разворота на 180°
if (dy != 0 && v[0] != 0) { v[0] = 0; v[1] = dy; }
if (dx != 0 && v[1] != 0) { v[0] = dx; v[1] = 0; }
}
/* Анимация "GAME OVER" прокручивается по матрице */
const PROGMEM bool gameOverMessage[8][90] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0}
};
void showGameOverMessage() {
for (int d = 0; d < sizeof(gameOverMessage[0]) - 7; d++) {
for (int col = 0; col < 8; col++) {
delay(messageSpeed);
for (int row = 0; row < 8; row++)
lc.setLed(0, row, col, pgm_read_byte(&(gameOverMessage[row][col + d])));
}
}
}
Библиотеки
- LedControl — работа с MAX7219
Идеи для улучшения
- Добавить звук (пьезо-зумер) при поедании/проигрыше.
- Сделать корпус (3D-печать, акрил, мессершмидт).
- Использовать RGB-матрицу для цветной змейки/еды.
- Добавить таблицу рекордов в EEPROM.
Производственный процесс
- DIY USB-геймпад на Arduino: собственный высокопроизводительный контроллер
- Сборка консоли Pong 24×16 на Arduino Nano и MAX7219
- Tetris на Arduino Nano: самостоятельная сборка 16×8 LED-матрицы на 74HC595
- Управление светодиодом по Bluetooth с Arduino: простой DIY-гид
- Интерактивный LED-дисплей в двери с PIR-датчиком — новогоднее приветствие на Arduino
- Пошаговое руководство: сборка умного четырёхногого робота на Arduino
- Pixel Chaser: игра на один тап с NeoPixel Ring и Arduino Nano
- Arduino Flip Clock на матрице 8×8 LED — DIY проект реального времени
- Arduino RGB-микшер цветов: Простой проект для начинающих
- Мастерство 8×8 LED-матрицы с Arduino Uno: Пошаговое руководство