Для реализации игры змейка на понадобиться:
Ардуино нано
Джойстик
Матрица WS2812b 8x8 (3шт)
Блок питания 5v 1a
Для начало необходимо спаять 3 матрицы вместе. (можно использовать и одну матрицу и подкоретировать код, но поле для игры будет очень маленьким поэтому я взял 3шт) паяем по такой схемке и скрепляем матрицы(я просто приклеил на супер клей): dout – din, 5v – 5v, gnd – gnd.
Лицевая сторона выйдет так:
Подключение
Подключаем по такой схеме:
gnd джойстика – gnd ардуино нано, 5v джойстика – 5v ардуино нано, VRX – A0, VRY – A1, SW не подключаем.
din матрицы – D6, 5v – плюсовой провод блока питания(так как ардуине тяжело будет питать всю матрицу), gnd – gnd ардуино - минусовой провод блока питания.
Скетч
После всех проделанных действий загружаем скетч на ардуино нано:
#include <FastLED.h>
// Определения для светодиодной матрицы
#define LED_PIN 6
#define NUM_LEDS 192
#define WIDTH 8
#define HEIGHT 24
#define BRIGHTNESS 50
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
// Определения для джойстика
#define JOY_X A0
#define JOY_Y A1
// Переменные игры "Змейка"
int snakeLength;
int snakeX[NUM_LEDS], snakeY[NUM_LEDS];
int foodX, foodY;
int headX, headY;
int dirX, dirY;
bool gameOver;
unsigned long lastUpdate = 0;
const int updateInterval = 200; // Интервал обновления в миллисекундах
void setup() {
Serial.begin(9600);
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(BRIGHTNESS);
initGame();
}
void loop() {
if (!gameOver && millis() - lastUpdate > updateInterval) {
lastUpdate = millis();
readJoystick();
moveSnake();
checkFoodCollision();
drawFrame();
FastLED.show();
} else if (gameOver) {
showGameOver();
delay(2000); // Задержка на 2 секунды
initGame();
}
}
void initGame() {
snakeLength = 5;
headX = 4;
headY = 12;
dirX = 1;
dirY = 0;
gameOver = false;
for(int i = 0; i < snakeLength; i++) {
snakeX[i] = headX - i;
snakeY[i] = headY;
}
generateFood();
}
void generateFood() {
foodX = random(WIDTH);
foodY = random(HEIGHT);
}
void readJoystick() {
int joyXValue = analogRead(JOY_X);
int joyYValue = analogRead(JOY_Y);
if (joyXValue < 400 && dirX == 0) {
dirX = -1;
dirY = 0;
} else if (joyXValue > 600 && dirX == 0) {
dirX = 1;
dirY = 0;
} else if (joyYValue < 400 && dirY == 0) {
dirY = -1;
dirX = 0;
} else if (joyYValue > 600 && dirY == 0) {
dirY = 1;
dirX = 0;
}
}
void moveSnake() {
for (int i = snakeLength; i > 0; i--) {
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
headX += dirX;
headY += dirY;
if (headX < 0) headX = WIDTH - 1;
else if (headX >= WIDTH) headX = 0;
if (headY < 0) headY = HEIGHT - 1;
else if (headY >= HEIGHT) headY = 0;
snakeX[0] = headX;
snakeY[0] = headY;
checkSelfCollision();
}
void checkFoodCollision() {
if (headX == foodX && headY == foodY) {
snakeLength = min(snakeLength + 1, NUM_LEDS);
generateFood();
}
}
void checkSelfCollision() {
for (int i = 1; i < snakeLength; i++) {
if (snakeX[i] == headX && snakeY[i] == headY) {
gameOver = true;
break;
}
}
}
void drawFrame() {
fill_solid(leds, NUM_LEDS, CRGB::Black);
// Рисование змейки
for (int i = 0; i < snakeLength; i++) {
leds[XY(snakeX[i], snakeY[i])] = CRGB::Green;
}
// Рисование яблока
leds[XY(foodX, foodY)] = CRGB::Red;
}
void showGameOver() {
fill_solid(leds, NUM_LEDS, CRGB::Red);
FastLED.show();
}
uint16_t XY(uint8_t x, uint8_t y) {
return (y * WIDTH) + x;
}
После загрузки игра сразу же запуститься на матрице.
Логика игры проста, поедая яблоки змейка вырастает на один светодиод, если змейка натыкается на саму себя то вся матрица загорается красными светодиодами обозначая проигрыш. После этого игра начинается сначала.