Оглавление:
Видео: Игра Arduino OLED Snake: 3 шага
2024 Автор: John Day | [email protected]. Последнее изменение: 2024-01-30 11:51
Привет и добро пожаловать, в наши инструкции по созданию OLED-игры для arduino, этот проект появился в то время, когда мы пытались сделать нашу первую игру с Arduino, ооооо, мы подумали, с чего лучше начать, чем с классической игры Snake от nokia (ну в хоть змеиный клон:)).
Что тебе понадобится
Запасы
Arduino UNO или клон
OLED-дисплей
4 диода
Резистор 500-1к
4 кнопки контроллера
Пассивный пьезо-зуммер
по желанию
Доска для хлеба без пайки
Обратите внимание, что эти ссылки приведены только для примера.
Шаг 1: Схема
На изображении выше вы можете видеть нашу схему, мы используем вывод d3 на Arduino в качестве вывода запроса прерывания, так что Arduino будет отдавать приоритет чтению входов контроллера, которые являются d4 d5 d6 d7. Основа схемы заключается в том, что нажимается кнопка направления, которая достигает высокого уровня 5 В, это активирует вывод запроса прерывания (фиолетовый провод d3) и соответствующий вывод направления, функция прерывания вызывает функцию направления обновления, и этот код соответственно перемещает змейку. Вывод 9 используется в качестве звукового вывода, поскольку это ШИМ (~ широтно-импульсная модуляция), который подключен непосредственно к пьезоэлементу 5 В на выводе +, а - возвращается к 0 В / земля.
(К вашему сведению, на arduino uno и клонах только d2 и d3 могут действовать как контакты запроса прерывания).
Штифты направления:
d4 Вверх ОРАНЖЕВЫЙ
d5 вниз РОЗОВЫЙ
d6 Левый СИНИЙ
d7 Правый КОРИЧНЕВЫЙ
d9 звук СЕРЫЙ
Каждая кнопка имеет вход для подключения 5 В и выход, который сначала подключается к соответствующему цифровому входу на Arduino, этот же выход каждой кнопки затем подключается к собственному диоду, мы используем диоды, чтобы остановить обратную подачу напряжения на другие кнопки и их активация. На катодном (-) конце всех 4 диодов мы соединяем их вместе, чтобы создать выходной переход, который подключается к d3, а затем через резистор к 0 В / землю, чтобы подтянуть контакты Arduino к низкому уровню, чтобы не оставлять плавающие контакты, когда они не подключены. активирован.
(К вашему сведению, плавающий вывод может получить фантомное напряжение и вызвать необычное поведение)
2 аналоговых вывода используются для управления дисплеем, это выводы i2c оборудования Arduino.
A5 подключен к SCL ЖЕЛТЫЙ
A4 подключен к SDA GREEN
Выходы + 5 В и 0 В (земля) от Arduino используются в качестве источника питания для всей цепи, которая может питаться от USB или зарядного устройства для телефона.
Шаг 2: Код
// ------------------------ ANJAWARE SNAKE Games С помощью людей сети --------------- -------
#включают
#include // https://github.com/adafruit/Adafruit-GFX-Library #include // https://github.com/adafruit/Adafruit-GFX-Library // отображение набора (ширина, высота) Adafruit_SSD1306 display (128, 64); // определяем входные контакты это контакты на Arduino, они никогда не меняются, поэтому #define #define INTPIN 3 // только контакты 2 и 3 могут быть прерваны контактами на UNO #define UPPIN 4 // это контакты, подключенные к соответствующему переключателю #define DWNPIN 5 #define LFTPIN 6 #define RHTPIN 7 #define SND 9 // определение направлений #define DIRUP 1 // на эти значения «змея» смотрит, чтобы решить- #define DIRDOWN 2 // направление, в котором будет двигаться змея # define DIRLEFT 3 #define DIRRIGHT 4
// устанавливаем переменные кнопки
// volitile, потому что нам нужно, чтобы он обновлялся с помощью прерывания, поэтому может быть любым битом значения цикла
// никогда не превышает 4, поэтому для экономии ресурсов требуется только 8-битное int volatile uint8_t buttonpressed = 0; bool butup = 0; bool butdown = 0; // мы используем это, чтобы установить true, чтобы «определять», в каком направлении нажимается bool butleft = 0; bool butright = 0;
// змеиные вставки
byte snakePosX [30]; // массив для создания тела змеи байтом snakePosY [30];
int snakeX = 30; // положение головы змеи
int snakeY = 30; int snakeSize = 1; // счетчик размера змейки ограничен размером массива
// мировые целые числа
uint8_t worldMinX = 0; // они устанавливают пределы игровой области
uint8_t worldMaxX = 128; uint8_t worldMinY = 10; uint8_t worldMaxY = 63;
// сбор мусора (еды) и положение мусора
bool scranAte = 0; uint8_t scranPosX = 0; uint8_t scranPosY = 0;
// оценивает переменные
long playscore = 0; длинный рекорд = 30; // устанавливаем высокий балл на 3 сбор в качестве отправной точки
// --------------------------- это то, что выполняет прерывание при повышении напряжения ------------ -------------
void interruptpressed () {задержка (150); // небольшая задержка для добавления защиты от «дребезга» updatedirection (); } // ------------------ обновить значение направления после нажатия кнопки ----------------- void updatedirection () { // Serial.println ("направление обновления"); butup = digitalRead (UPPIN); // проверяем, какой вход стал высоким, и устанавливаем соответствующий bool true butdown = digitalRead (DWNPIN); butleft = digitalRead (LFTPIN); butright = digitalRead (RHTPIN); // это, если средства состояния смотрят, какой вход был повышен, и вводят соответствующее значение в переменную "buttonpressed" //, эта переменная определяет направление движения if (butup == true) {buttonpressed = DIRUP; // Serial.println ("нажата кнопка ВВЕРХ"); // Serial.println (кнопка нажата); butup = false; тон (СНД, 1500, 10); } если (butdown == true) {buttonpressed = DIRDOWN; // Serial.println ("ВНИЗ нажата"); // Serial.println (кнопка нажата); butdown = false; тон (СНД, 1500, 10); }
если (butleft == true)
{buttonpressed = DIRLEFT; // Serial.println ("Нажата ВЛЕВО"); // Serial.println (кнопка нажата); butleft = false; тон (СНД, 1500, 10); } если (butright == true) {buttonpressed = DIRRIGHT; // Serial.println ("Нажат ВПРАВО"); // Serial.println (кнопка нажата); butright = false; тон (СНД, 1500, 10); }}
// -------------------------- отрисовываем процедуры отображения ------------------ -----------------
void updateDisplay () // рисуем оценки и контуры
{// Serial.println ("Обновить отображение");
display.fillRect (0, 0, display.width () - 1, 8, ЧЕРНЫЙ);
display.setTextSize (0); display.setTextColor (БЕЛЫЙ); // выводим результаты display.setCursor (2, 1); display.print ("Оценка:"); display.print (String (playscore, DEC)); display.setCursor (66, 1); display.print ("Высокий:"); display.print (String (рейтинг, DEC)); // рисуем игровую область // pos 1x, 1y, 2x, 2y, color display.drawLine (0, 0, 127, 0, WHITE); // самая верхняя граница display.drawLine (63, 0, 63, 9, БЕЛЫЙ); // разделитель очков display.drawLine (0, 9, 127, 9, БЕЛЫЙ); // под рамкой текста display.drawLine (0, 63, 127, 63, БЕЛЫЙ); // нижняя граница display.drawLine (0, 0, 0, 63, БЕЛЫЙ); // левая граница display.drawLine (127, 0, 127, 63, БЕЛЫЙ); // правая граница
}
// ----------------------------------- обновить игровую зону ---------- --------------------
void updateGame () // это обновляет отображение игровой области
{display.clearDisplay ();
display.drawPixel (scranPosX, scranPosY, БЕЛЫЙ);
scranAte = scranFood ();
// проверяем подпрограммы змейки
если (outOfArea () || selfCollision ())
{ игра закончена(); }
// отображаем змейку
для (int i = 0; i0; i--) {snakePosX = snakePosX [i-1]; snakePosY = snakePosY [i-1]; } // добавляем дополнительный пиксель к змейке if (scranAte) {snakeSize + = 1; snakePosX [snakeSize-1] = snakeX; snakePosY [snakeSize-1] = snakeY; }
переключатель (кнопка нажата) // было snakeDirection
{case DIRUP: snakeY- = 1; перерыв; case DIRDOWN: snakeY + = 1; перерыв; case DIRLEFT: snakeX- = 1; перерыв; case DIRRIGHT: snakeX + = 1; перерыв; } snakePosX [0] = snakeX; snakePosY [0] = snakeY; updateDisplay (); display.display (); // --------------------- размещаем скран -------------------
пусто местоScran ()
{scranPosX = random (worldMinX + 1, worldMaxX-1); scranPosY = random (worldMinY + 1, worldMaxY-1); } // ------------------------ СКАНИРОВАТЬ ТОЧКУ ВВЕРХ ---------------- bool scranFood () {если (snakeX == scranPosX && snakeY == scranPosY) {playscore = playscore + 10; тон (СНД, 2000, 10); updateDisplay (); placeScran (); возврат 1; } else {return 0; }} // --------------------- вне зоны действия ---------------------- bool outOfArea () {return snakeX = worldMaxX || snakeY = worldMaxY; } //---------------------- игра закончена----------------------- --- void gameOver () {uint8_t rectX1, rectY1, rectX2, rectY2; rectX1 = 38; rectY1 = 28; rectX2 = 58; rectY2 = 12; display.clearDisplay (); display.setCursor (40, 30); display.setTextSize (1); тон (СНД, 2000, 50); display.print («ИГРА»); тон (СНД, 1000, 50); display.print («НАВЕРХ»); if (playscore> = highscore) // проверяем, выше ли результат, чем high score {highscore = playscore; // одиночный, если статус для обновления рекорда} for (int i = 0; i <= 16; i ++) // это для рисования прямоугольников вокруг игры над {display.drawRect (rectX1, rectY1, rectX2, rectY2, WHITE); Serial.println ("если цикл"); display.display (); rectX1- = 2; // сдвиг на 2 пикселя rectY1- = 2; rectX2 + = 4; // сдвиг на 2 пикселя от последней точки rectY2 + = 4; тон (СНД, i * 200, 3); } display.display (); // Очистка экрана после фейма над rectX1 = 0; // устанавливаем начальную позицию строки rectY1 = 0; rectX2 = 0; rectY2 = 63; для (int я = 0; я <= 127; я ++) {uint8_t cnt = 0; display.drawLine (rectX1, rectY1, rectX2, rectY2, ЧЕРНЫЙ); rectX1 ++; rectX2 ++; display.display (); } display.clearDisplay (); playscore = 0; // сбросить данные змейки и игрока snakeSize = 1; snakeX = display.width () / 2; snakeY = display.height () / 2; waitForPress (); // ждем, пока игрок начнет игру} // ------------------------- ждать цикла нажатий ---------- --------------- void waitForPress () {bool wait = 0; // цикл заканчивается, если это правда display.clearDisplay (); пока (ожидание == 0) {drawALineForMe (БЕЛЫЙ); // рисуем случайную белую линию drawALineForMe (BLACK); // рисуем случайную черную линию, чтобы экран не полностью заполнял белый цвет display.fillRect (19, 20, 90, 32, ЧЕРНЫЙ); // пустой фон для текста display.setTextColor (WHITE); display.setCursor (35, 25); display.setTextSize (2); // более крупный шрифт display.println ("SNAKE"); // x y w h r col display.drawRoundRect (33, 22, 62, 20, 4, БЕЛЫЙ); // граница змейки display.drawRect (19, 20, 90, 32, БЕЛЫЙ); // рамка рамки - 3 display.setCursor (28, 42); display.setTextSize (0); // возврат шрифта к нормальному display.println ("нажать любую клавишу"); display.display (); ожидание = digitalRead (INTPIN); // проверяем, изменится ли ожидание нажатия клавиши на 1, заканчивающееся при нажатой кнопке = 0; // нажать кнопку сброса}} // -------------------- НАРИСИМ случайный цвет линии ввода uint8_t -------------- ----- void drawALineForMe (uint8_t clr) {uint8_t line1X, line1Y, line2X, line2Y = 0; // задаем случайные координаты для линии, затем рисуем ее // переменная не менее не более line1X = random (worldMinX + 1, worldMaxX-1); line1Y = random (worldMinY + 1, worldMaxY-1); line2X = случайный (worldMinX + 1, worldMaxX-1); line2Y = random (worldMinY + 1, worldMaxY-1); display.drawLine (line1X, line1Y, line2X, line2Y, clr); } // ------------------------------------- обнаружение столкновений -------- -----------------------
for (byte i = 4; i <snakeSize; i ++) {if (snakeX == snakePosX && snakeY == snakePosy ) {return 1; тон (СНД, 2000, 20); тон (СНД, 1000, 20); } return 0; }
//-------------------------------- НАСТРАИВАТЬ--------------- -------------------------------
void setup () {задержка (100); // просто даем возможность "загрузиться" // Serial.begin (9600); // снимите этот флажок, если хотите видеть последовательные выходы display.begin (SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay (); // начать с чистого дисплея display.setTextColor (WHITE); // установить размер поворота цвета текста и т. д. display.setRotation (0); display.setTextWrap (ложь); display.dim (0); // устанавливаем яркость отображения pinMode (INTPIN, INPUT); // установить правильные порты на входы pinMode (UPPIN, INPUT); pinMode (DWNPIN, ВХОД); pinMode (LFTPIN, ВХОД); pinMode (RHTPIN, ВХОД); // это команда прерывания, которая "останавливает" arduino для чтения входов // команда-функция-контакт-функция для выполнения-условия на контакте attachInterrupt (digitalPinToInterrupt (INTPIN), interruptpressed, RISING); // Serial.println ("Настройка прошла"); waitForPress (); // отображаем стартовый экран змейки placeScran (); // размещаем первый кусочек еды} // --------------------- ГЛАВНЫЙ ЦИКЛ ----------------- ---------------------- void loop () {updateGame (); // эта функция несет основной код}
Шаг 3:
Рекомендуемые:
Игра в рулетку DIY 37 Leds Arduino: 3 шага (с изображениями)
DIY 37 Leds Arduino Roulette Game: Roulette - это игра в казино, названная в честь французского слова, означающего маленькое колесо
Цифровая игра Ludo Dice с 7-сегментным дисплеем Arduino: 3 шага
Digital Ludo Dice с проектом 7-сегментного дисплея Arduino: в этом проекте 7-сегментный дисплей используется для случайного отображения числа от 1 до 6 всякий раз, когда мы нажимаем кнопку. Это один из самых крутых проектов, который нравится делать всем. Чтобы узнать, как работать с 7-сегментным дисплеем, нажмите здесь: -7 segme
Игра Jumping Man с использованием Arduino: 3 шага
Игра Jumping Man с использованием Arduino: Всем привет !!! Добро пожаловать в мой первый учебник. Я был большим поклонником игры Jumping Dinosaur, поэтому я попытался создать аналогичную игру с помощью Arduino UNO и ЖК-экрана. Это интересный проект, требующий лишь усилий
Автоматизированная игра в динозавров с использованием Arduino: 4 шага
Автоматическая игра с динозаврами с использованием Arduino: Итак, привет, парень, добро пожаловать обратно в новую статью в этой статье, мы создадим автоматизированную игру с динозаврами с использованием Arduino. Эту автоматизированную игру с динозаврами очень легко сделать. За несколько шагов вы можете сделать эту игру с динозаврами дома, когда я смотрел Тик-Ток несколько дней назад, я иду
Игра Саймона - Веселая игра !: 5 шагов
Simon Game - Fun Game !: Справка: После долгих выходных вы должны очень постараться, чтобы выполнить все задания и работу, за которые вы отвечаете. Пора нам тренировать мозг, не так ли? Помимо этих скучных и бессмысленных игр, есть игра под названием Simon Game