Мини-аркада ATtiny85:Змейка
Компоненты и расходные материалы
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 |
Необходимые инструменты и машины
![]() |
| |||
![]() |
|
Приложения и онлайн-сервисы
![]() |
| |||
![]() |
|
Об этом проекте
Вдохновение и прошлый проект
В декабре 2017 года я создал портативную консоль Arduino Pong, в которой использовались Arduino Nano и OLED-экран, а также две кнопки.
В то время это было нормально, но консоль была слишком большой и громоздкой. Однако в последнее время я пытаюсь воссоздать некоторые из своих прошлых проектов. На этот раз я хотел сделать очень маленькую консоль, на которой люди могли бы играть в змейку.
Выбранные компоненты
Чтобы сделать консоль маленькой, я не мог использовать какую-либо плату для разработчиков Arduino, поэтому я выбрал ATtiny85.
Он имеет достаточно ввода-вывода для запуска игры, включая два вывода ADC, порт I2C и вывод GPIO. Я решил использовать простой 2-осевой модуль джойстика / переключателя, поскольку с ним легко взаимодействовать, и для передачи сигналов требуется всего 3 контакта.
Наконец, пришло время решить, какой дисплей нужен. Поскольку OLED-экран DFRobot 128 x 64 имеет небольшой размер, но большое разрешение, я согласился.
Пайка системы
Для начала я прикрепил ATtiny85 к монтажной плате SOP-8 - DIP-8 и припаял его к небольшому куску перфорированной платы. Затем я припаял два разъема - один для программирования, а другой для экрана. После этого я подключил контакты аналогового джойстика к монтажной плате и подключил их соответствующим образом. На последнем этапе я подключил коммутационную плату micro USB к остальной части системы для питания.
Проектирование корпуса
Корпус был разработан в Fusion 360. Я начал с создания и компоновки компонентов, которые использовал в реальной сборке, а затем создал корпус вокруг них.
Я хотел имитировать аркадную коробку 80-х годов, но при этом сохранить очень маленький размер. Ниже приведены некоторые изображения корпуса:
Программирование игры
Snake - довольно простая игра для программирования. Я установил максимальную длину змейки 30, чтобы сэкономить на оперативной памяти, это означает, что, как только змейка съела 29 пикселей, игрок выигрывает. Чтобы отслеживать сегменты змеи, я создал двумерный массив, в котором хранятся упорядоченные пары для каждого сегмента.
Всякий раз, когда голова перемещается в новое место, ее предыдущие положения спускаются каскадом вниз. Каждый раз, когда сегмент потребляется, в случайной точке создается новый. Проверка столкновений выполняется путем перебора координат каждого сегмента и проверки совпадения координат головы. Кроме того, попадание змеи по любой стене приведет к поражению игрока.
Играет Снейк
Я начал с того, что включил консоль и дождался загрузки экрана с едой и первым сегментом змейки. Затем я просто пилотировал змею, перемещая джойстик в правильном направлении, наблюдая, как она ест еду. В эту игру весело играть, и она является отличным убийцей скуки в крошечной упаковке.
Код
- Код ATTiny85
Код ATTiny85 C / C ++
Обязательно сначала установите U8g2lib// # include#include U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g (U8G2_R0, / * clock =/ 2, / data =/ 0, reset =* / U8X8); #define MAX_LENGTH 30 // 30 сегментов max # define X 0 # define Y 1 # define JOYSTICK_X 2 #define JOYSTICK_Y 3 #define DIR_THRESH 300 // Для countuint8_t segmentPositions [MAX_LENGTH] [ 2]; uint8_t headPosition [2] ={63, 31}; // Помещаем змейку в начало startuint8_t foodPosition [2]; // Где находится едаduint8_t tempPosition0 [2]; // Сохраняем позицию предыдущего сегмента для перехода к следующему uint8_t tempPosition1 [2]; // Сохранение позиции предыдущего сегмента для перехода к следующему сегменту segmentLength =1; void gameUpdate (); enum DIRECTIONS {RIGHT, DOWN, LEFT, UP} currentDirection; void setup () {//TinyWireM.begin (); u8g.begin (); u8g.setPowerSave (0); pinMode (ДЖОЙСТИК_X, ВХОД); pinMode (ДЖОЙСТИК_Y, ВХОД); randomSeed (analogRead (0)); beginGame ();} недействительный цикл () {u8g.firstPage (); сделать {gameUpdate (); u8g.setColorIndex (1); } в то время как (u8g.nextPage ());} void beginGame () {currentDirection =RIGHT; spawnFood (); delay (1000);} bool checkCollisions () {for (int i =1; i =128) return 1; иначе, если (headPosition [Y] <=0 || headPosition [Y]> =64) return 1; вернуть ложь;} void spawnFood () {int randomX =random (5, 123); int randomY =случайный (5, 60); foodPosition [X] =randomX; foodPosition [Y] =randomY;} void checkFoodEaten () {if (headPosition [X] ==foodPosition [X] || headPosition [Y] ==foodPosition [Y]) {segmentLength + =1; spawnFood (); }} void updateDirection () {int joy_x_val =analogRead (JOYSTICK_X); int joy_y_val =аналоговое чтение (JOYSTICK_Y); если (joy_x_val <=DIR_THRESH) currentDirection =LEFT; иначе, если (joy_x_val> =1023-DIR_THRESH) currentDirection =RIGHT; иначе, если (joy_y_val <=DIR_THRESH) currentDirection =UP; else if (joy_y_val> =1023-DIR_THRESH) currentDirection =DOWN;} void displaySegments () {for (int segment =0; segment =MAX_LENGTH) endGame (); задержка (50);} void endGame () {segmentLength =1; headPosition [0] =63; headPosition [1] =31; beginGame ();}
Изготовленные на заказ детали и корпуса
Схема

Производственный процесс
- Детектор языка TinyML на основе Edge Impulse и Arduino
- Игра с гироскопом Arduino с MPU-6050
- Цифровые игральные кости Arduino
- Рулетка DIY 37 LED
- Переносимый детектор дальности
- Реактивный настольный светильник для звука Arduino
- Гальваника медью
- NeoMatrix Arduino Pong
- Создатель световой последовательности
- Умная розетка