Хотите что-то немного уникальное для своей следующей настольной ролевой игры? Как насчет электронного D20 с пользовательской графикой для критических попаданий и промахов? Сегодня я покажу вам, как создать свой собственный Arduino и несколько простых деталей.
Не беспокойтесь, если вы никогда ранее не использовали Arduino, у нас есть руководство по
План строительства
Это простой проект. Arduino будет управлять OLED-дисплеем, а кнопка прокручивает матрицу. Пользовательская графика будет отображаться для критических попаданий или бросков. Вы можете легко изменить код на D8, D10 или D12.
Что вам нужно
- 1 х Arduino
- 1 x 0,96 ″ I2C OLED дисплей
- 1 х кнопка
- 1 х 10к? резистор
- 1 х макет
- Ассорти подключить провода
- Полный код здесь , если вы не хотите следовать всем письменным инструкциям.
Это основные части, которые вам нужны, чтобы создать свой собственный D20. Вы можете установить его в корпус (см. Ниже) и припаять схему в более постоянное состояние. Вот дополнительные детали, которые вам понадобятся для этого:
- 4 болта M2 x 10 мм (0,4 дюйма)
- 4 х М2 гайки
- 4 х 7 мм (0,28 дюйма) шайбы
- 9В батарея (или подходящая альтернатива)
- Ассорти термоусадочная трубка
Эти OLED-дисплеи очень крутые. Обычно их можно приобрести в белом, синем, желтом цвете или в смеси из трех. Я купил один в синем, чтобы соответствовать моему случаю. Убедитесь, что вы получаете модель I2C вместо SPI .
Подойдет практически любой Arduino. Я выбрал Nano, так как они достаточно малы, чтобы поместиться в корпусе. Ознакомьтесь с нашим руководством по покупке купить для получения дополнительной информации о моделях Arduino.
Схема
Вот схема, которая вам нужна:
Подключите VCC и GND на OLED-дисплее к Arduino + 5V и заземлению . Подключите аналог 4 на Arduino к выводу с маркировкой SDA . Подключите аналог 5 к выводу SCL . Эти контакты содержат схему, необходимую для управления дисплеем по шине I2C. Точные контакты будут различаться в зависимости от модели, но A4 и A5 используются на Nano и Uno. Проверьте документацию библиотеки Wire для вашей модели, если вы не используете Uno или Nano.
Подключите аккумулятор к земле и контакт VIN . Это обозначает напряжение на входе и принимает различные напряжения постоянного тока, но сначала проверьте вашу конкретную модель, и она иногда может немного отличаться.
Подключите кнопку к цифровому контакту 2 . Обратите внимание, как 10k? резистор подключен к земле. Это очень важно! Это известно как понижающий резистор, и он предотвращает Arduino обнаружение паразитных данных или помех при нажатии кнопки. Он также служит для защиты доски. Если бы этот резистор не использовался, + 5 В пошел бы прямо в землю. Это известно как мертвый шорт и это простой способ убить Ардуино.
Если вы паяете эту цепь, защитите свои соединения с помощью термоусадочной трубки:
Убедитесь, что вы не нагреваете его слишком сильно, и делайте это только после того, как убедитесь, что схема работает. Вы можете также захотеть скрутить свои кабели в пары. Это сохраняет их аккуратными и помогает защитить их от чрезмерного стресса:
Тест кнопки
Теперь, когда вы построили схему, загрузите этот тестовый код (убедитесь, что вы выбрали правильную плату и порт из меню « Инструменты»> « Плата и инструменты»> «Порты» ):
const int buttonPin = 2; // the number of the button pin void setup() { pinMode(buttonPin, INPUT); // setup button Serial.begin(9600); // setup serial } void loop(){ if(digitalRead(buttonPin) == HIGH) { Serial.print("It Works"); delay(250); } }
После загрузки оставьте Arduino подключенным через USB и откройте последовательный монитор ( вверху справа> Serial Monitor ). Вы должны видеть, что слова It Works появляются каждый раз, когда вы нажимаете кнопку.
Если ничего не происходит, пойди и перепроверь свою схему.
Установка OLED
Вам нужно установить две библиотеки для управления дисплеем. Загрузите библиотеки Adafruit_SSD1306 и Adafruit-GFX [больше не доступны] с Github и сохраните их в своей папке библиотеки. Если вы не уверены, где находятся папки вашей библиотеки, прочитайте мое учебное пособие по ретро-играм , где я настраиваю этот же дисплей более подробно.
Перезапустите свою среду разработки Arduino и загрузите эскиз теста из меню « Файл»> «Примеры» . Выберите Adafruit SSD1306, а затем ssd1306_128x64_i2c . Загрузите этот код (это займет некоторое время), и вы должны увидеть множество форм и рисунков на дисплее:
Если ничего не происходит, дважды проверьте ваши соединения. Если после проверки он все равно не будет работать, вам нужно будет изменить пример кода.
Измените эту строку (в начале функции настройки ):
display.begin(SSD1306_SWITCHCAPVCC, 0x3D);
К этому:
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
Это сообщает библиотеке конкретные сведения об используемом вами дисплее. Теперь вы должны быть готовы продолжить сборку.
Дело
Если вы строите это на макете или не хотите его упаковывать, вы можете пропустить этот шаг.
Я разработал и напечатал 3D эту коробку. Получить файлы на Thingiverse . Не беспокойтесь, если у вас нет 3D-принтера — онлайн-сервисы 3D Hubs и Shapeways предоставляют услуги онлайн-печати.
Вы можете легко сделать эту коробку из дерева, или купив пластиковую коробку для проекта .
Крышка представляет собой простую конструкцию с плотной посадкой и содержит несколько вырезов для крепежа:
Код
Теперь, когда все готово, пришло время для кода. Вот как это будет работать в псевдокоде :
if button is pressed generate random number if random number is 20 show graphic else if random number is 1 show graphic else show number
Чтобы это работало должным образом, необходимо сгенерировать случайное число — это бросок кубика. Arduino имеет генератор случайных чисел, называемый random , но не должен его использовать. Хотя он достаточно хорош для базовых случайных задач, он не достаточно случайен для электронного кристалла. Причины несколько сложны, но вы можете прочитать больше, если вы заинтересованы в boallen.com .
Загрузите библиотеку TrueRandom от sirleech на Github. Добавьте это в свою библиотеку и перезапустите IDE.
Теперь создайте новый файл и настройте свой исходный код (или просто получите готовый код из GitHub ):
#include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <TrueRandom.h> Adafruit_SSD1306 display(4); void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // setup the OLED pinMode(buttonPin, INPUT); // setup button } void loop() { }
Этот код настраивает OLED и включает в себя все библиотеки, которые вам необходимы для связи с ним, а также новую библиотеку случайных чисел. Теперь добавьте это в основной цикл:
if(digitalRead(buttonPin) == HIGH) { delay(15); if(digitalRead(buttonPin) == HIGH) { display.fillScreen(BLACK); // erase the whole display display.setTextColor(WHITE); display.setTextSize(2); display.setCursor(0, 0); display.println(TrueRandom.random(1, 21)); // print random number display.display(); // write to display delay(100); } }
Это довольно просто на минуту, но это рабочий D20. При каждом нажатии кнопки на экране отображается случайное число от одного до 20:
Это хорошо работает, но немного скучно. Давайте сделаем это лучше. Создайте два новых метода, drawDie и eraseDie :
void drawDie() { display.drawRect(32, 0, 64, 64, WHITE); }
Они нарисуют кубик в середине экрана. Возможно, вы захотите сделать это более сложным, возможно, нарисовав D20 или D12 и так далее, но проще нарисовать базовый шестигранный кубик. Вот основное использование:
drawDie();
Затем измените ваш основной цикл, чтобы нарисовать случайное число, только больше и посередине. Измените размер текста и курсор на это:
display.setTextColor(WHITE); display.setCursor(57, 21);
Теперь это выглядит намного лучше:
Единственная проблема с числами больше девяти:
Исправить это просто. Для любых чисел меньше 10 курсор будет установлен в положение, отличное от этих цифр 10 или больше. Заменить эту строку:
display.setCursor(57, 21);
С этим:
int roll = TrueRandom.random(1, 21); // store the random number if (roll < 10) { // single character number display.setCursor(57, 21); } else { // dual character number display.setCursor(47, 21); }
Вот как это выглядит сейчас:
Теперь осталось только изображения, когда вы бросаете критический удар или промахиваетесь. Есть несколько шагов, но это достаточно простой процесс.
Найдите подходящее изображение, которое вы хотите использовать (чем проще, тем лучше, поскольку дисплей только одноцветный). Вот изображения, которые я использовал:
Любое изображение, которое вы хотите использовать, необходимо преобразовать в HEX-массив. Это представление изображения в виде кода. Для этого доступно множество инструментов, и некоторые из них написаны специально для OLED дисплеев. Самый простой способ — использовать онлайн-инструмент PicturetoC_Hex . Вот необходимые настройки:
Загрузите свое изображение и установите формат кода HEX: 0x . Установите Используется для на Черный / Белый для всех функций рисования изображения . Оставьте все остальные параметры по умолчанию. Вы можете изменить размер изображения здесь, если вам нужно. Нажмите Get C String, и вы должны увидеть данные изображения:
Вам понадобятся эти сгенерированные данные через минуту. Создайте две функции с именами drawExplosion и drawSkull (или подходящее имя для вашей версии). Вот код:
void drawExplosion() { // store image in EEPROM static const unsigned char PROGMEM imExp[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x78,0x7f,0xff,0xc0,0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xf0,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xfb,0x00,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0x00,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x1f,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x07,0xff,0xff,0xf9,0xff,0xd8,0x00,0x00,0x00,0x3f,0xff,0xf0,0x0f,0x00,0x00,0x00,0x00,0x1f,0x1f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xff,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0x00,0x00,0x00,0x07,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0xfc,0x00,0x00,0x01,0xbf,0xff,0xff,0xff,0x30,0x00,0x00,0x00,0x13,0xf7,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; display.drawBitmap(0, 0, imExp, 64, 62, 1); // draw mushroom cloud } void drawSkull() { // store image in EEPROM static const unsigned char PROGMEM imSku[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0xf0,0x00,0x00,0x00,0x00,0x78,0x00,0x07,0xf0,0x00,0x00,0x00,0x00,0xfc,0x00,0x07,0xf8,0x00,0x00,0x00,0x00,0xfe,0x00,0x07,0xf8,0x00,0x00,0x00,0x01,0xfe,0x00,0x07,0xfc,0x00,0x00,0x00,0x01,0xfe,0x00,0x07,0xfe,0x00,0x3f,0xc0,0x03,0xfe,0x00,0x01,0xff,0x81,0xff,0xfc,0x07,0xec,0x00,0x00,0x3f,0xc7,0xff,0xff,0x1f,0xc0,0x00,0x00,0x0f,0xcf,0xff,0xff,0xdf,0x00,0x00,0x00,0x07,0xbf,0xff,0xff,0xee,0x00,0x00,0x00,0x01,0x7f,0xff,0xff,0xf0,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x01,0xff,0xff,0xff,0xf8,0x00,0x00,0x00,0x03,0xff,0xff,0xff,0xfc,0x00,0x00,0x00,0x07,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1f,0xff,0xff,0xff,0xff,0x80,0x00,0x00,0x1e,0x3f,0xff,0x3f,0xc7,0x80,0x00,0x00,0x1e,0x0c,0x0f,0x00,0x07,0x80,0x00,0x00,0x1e,0x00,0x0f,0x00,0x0f,0x80,0x00,0x00,0x1e,0x00,0x19,0x80,0x0f,0x00,0x00,0x00,0x0f,0x00,0x19,0x80,0x0f,0x00,0x00,0x00,0x0d,0x00,0x30,0xc0,0x1f,0x00,0x00,0x00,0x05,0x80,0x70,0xc0,0x1e,0x00,0x00,0x00,0x05,0xf0,0xe0,0xe0,0x36,0x00,0x00,0x00,0x01,0xff,0xe0,0x7f,0xf0,0x00,0x00,0x00,0x03,0xff,0xc4,0x7f,0xf0,0x00,0x00,0x00,0x03,0xff,0xcc,0x7f,0xf0,0x00,0x00,0x00,0x03,0xff,0xcc,0x7f,0xf0,0x00,0x00,0x00,0x03,0xff,0x9e,0x7f,0xf0,0x00,0x00,0x00,0x00,0xff,0xfe,0x7f,0xc0,0x00,0x00,0x00,0x00,0x01,0xff,0xf8,0x1c,0x00,0x00,0x00,0x03,0xe0,0x3f,0x01,0xbf,0x00,0x00,0x00,0x07,0xa6,0x40,0x09,0x9f,0x80,0x00,0x00,0x1f,0x27,0x5a,0x39,0x9f,0xf8,0x00,0x01,0xff,0x27,0xdb,0x39,0x0f,0xfc,0x00,0x03,0xfe,0x31,0x7f,0x39,0x07,0xfc,0x00,0x03,0xfc,0x10,0x1a,0x02,0x03,0xf8,0x00,0x03,0xf8,0x10,0x00,0x02,0x01,0xf0,0x00,0x01,0xf8,0x10,0x00,0x02,0x01,0xe0,0x00,0x00,0x78,0x10,0x00,0x02,0x00,0xe0,0x00,0x00,0x70,0x30,0x00,0x02,0x00,0x00,0x00,0x00,0x30,0x20,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x64,0x00,0x1b,0x00,0x00,0x00,0x00,0x00,0x73,0x55,0x63,0x00,0x00,0x00,0x00,0x00,0xf9,0x55,0x4f,0x00,0x00,0x00,0x00,0x00,0x7f,0x14,0x1f,0x00,0x00,0x00,0x00,0x00,0x1f,0xe0,0xfe,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x03,0xff,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; display.drawBitmap(0, 0, imSku, 60, 64, 1); // draw skull cloud }
Если вы хотите использовать изображения, которые я использовал, тогда скопируйте код. Если вы хотите использовать свои собственные изображения, сгенерированные ранее, скопируйте байтовый код в массивы imSku и imExp по мере необходимости.
Вот как эти изображения выглядят на дисплее:
Наиболее важной частью этого кода является эта строка:
static const unsigned char PROGMEM imSku[]
Это говорит Arduino хранить ваши изображения в EEPROM ( что такое EEPROM? ) вместо его ОЗУ ( краткое руководство по ОЗУ ). Причина этого проста; Arduino имеет ограниченную оперативную память, и использование всего этого для хранения изображений может не оставить ничего для выполнения вашего кода
Измените ваш основной оператор if, чтобы показывать эти новые графики, когда выпадает единица или 20. Обратите внимание на строки кода, чтобы показать число, свернутое вместе с изображениями:
if(roll == 20) { drawExplosion(); display.setCursor(80, 21); display.println("20"); } else if(roll == 1) { display.setCursor(24, 21); display.println("1"); drawSkull(); } else if (roll < 10) { // single character number display.setCursor(57, 21); display.println(roll); // write the roll drawDie(); // draw the outline } else { // dual character number display.setCursor(47, 21); display.println(roll); // write the roll drawDie(); // draw the outline }
А вот как выглядят эти новые роллы:
Это все, что касается кода (иди, возьми код из GitHub, если ты пропустил все это). Вы можете легко изменить это на D12, D8 и так далее.
Финальная сборка
Теперь, когда все остальное закончено, пришло время собрать все вместе. Прикрутите дисплей, следя за тем, чтобы не перетянуть болты. Это, пожалуй, самая сложная часть. Я взломал дисплей, поэтому вы можете использовать некоторые пластиковые шайбы. Я вырезал несколько квадратов из Plasticard :
Маленькие гайки и болты могут быть сложны для подключения. Совет: Используйте маленький кусок Blu-Tack на конце отвертки, чтобы изначально посадить гайки:
Прикрутите кнопку, подключите аккумулятор и закройте крышку. Будьте осторожны, чтобы не защемить какие-либо провода или не сжать их слишком сильно, что может привести к короткому замыканию. В зависимости от длины ваших отводящих проводов вам может потребоваться защитить открытые соединения с некоторой изоляцией (последовательный блок работает хорошо):
Вот как это выглядит внутри:
И вот готовый продукт:
Теперь вы должны быть счастливым обладателем электронного D20!
Какие модификации вы сделали? Вы меняли изображения? Дайте нам знать в комментариях, мы будем рады видеть, что вы сделали!