Розробка ігор для консолі на Arduino в літньому таборі

В минулому році ми в літній комп’ютерної школі проводили гурток з Arduino. Там взяли участь і викладачі, в результаті чого з’явилася 8-бітова ігрова консоль з екраном 64×64.

Тепер же ми вирішили зробити гурток, в якому діти зможуть створити власні ігри для цієї консолі. Завдяки її мінімалізму, коду повинне вийти трохи. Всього на гурток було заплановано близько 14 годин протягом зміни, так що низький поріг входу в програмування таких ігор був важливою особливістю.


4095 світлодіодів і всі-всі-всі

API для створення ігор

Залізка у нас була тільки одна, тому спочатку треба було зробити емулятор. Адже над іграми буде працювати кілька команд. Крім того, початково весь код був в одному *.ino файлі, тому треба було розбити його на частини, щоб додавання нових ігор зводилося до програмування їх поведінки і відтворення. Середовище збірки ми залишили Arduino IDE, щоб спростити налаштування робочих машин.

Для виводу зображення на екран, процесор постійно сканує його і завантажує в зсувні регістри кольору пікселів. Тому правильна процедура оновлення екрану повинна віддавати тільки одну лінію пікселів. Але такий інтерфейс був би дуже незручним, тому ми зробили набір функцій типу game_draw_sprite, game_draw_text, а вони вже всередині перевіряють яку лінію треба виводити (і чи потрібно взагалі). З-за цього виникає деякий оверхед, так як всі дзвінки будуть робитися для кожного рядка, а не тільки для вибраних.

Емулятор надає ті ж функції, але він малює все у фреймбуфере, до того ж працює набагато швидше, ніж консоль. Тому не завжди можна оцінити те, що вийде на залозі. Зате він вирішує більшість проблем з налагодженням, тому що можна запустити Visual Studio (або gdb) і подивитися, як працює програма. Всі скріншоти тут саме з цього емулятора.

Читайте також  Генетичний «Ноїв ковчег» врятує 66 000 видів

Розробник повинен реалізувати дві функції, щоб вийшла гра: відображення екрану і оновлення внутрішнього стану. Оновлення відбувається з наперед заданою періодичністю. Функція викликається для відтворення кожного рядка екрана (насправді для груп по 4 рядки відразу через особливості адресації).

Функція оновлення реагує на натиснуті на джойстику клавіші і змінює внутрішні дані ігри (наприклад, координати об’єктів, щоб їх перемістити). Так як в кожний момент часу виконується лише одна гра, немає сенсу в кожній з них оголошувати статичні змінні. Адже все у нас 2 кілобайти пам’яті. Тому робота з пам’яттю у нас трохи незручна — всі дані зберігаються в структурі, до якої доводиться звертатися через вказівник.

Щоб перевірити працездатність API, а також меню для вибору ігор, ми реалізували гру «Змійка». Робили злегка в поспіху, тому кілька багів залишилося. Діти їх потім з радістю виявляли.

Спільна розробка

Для початку ми розмістили наш проект з гитхаба на внутрішньому сервері gitlab. Хлопці працювали з форками цього репозиторію, а потім надсилали пулл реквесты, щоб зібрати все в купу. В цілому все пройшло вдало, але глибоко в пояснення принципів роботи git ми не занурювалися.

Всього учасників проектів було не надто багато. Спочатку заявилося 4 команди, але до кінця дійшли тільки 2. Це були хлопці з групи, тільки починає вивчати алгоритми, тому було цікаво, чи вийде у них що-небудь.

Сапер

Перша команда вирішила робити класичний сапер. Міни розміщувалися дуже хитро — по одній у стовпці — тому їм знадобилися тільки спрайт з цифрами від 1 до 3. Програма складається з 475 рядків, але там є сміття і залишені коментарі з шаблону. Чіплятися до коду в пулл реквестах вже не залишалося часу.

Читайте також  Як відсканувати документ: Windows, В Mac OS X, На iPhone, На Android

Найбільша складність у реалізації сапера — це відкривання всіх вільних клітин, суміжних з тієї вільної, на яку натиснув користувач. Обхід в ширину було пояснювати довго. Та й пам’ять він під чергу займає. Тому хлопці просто кілька разів сканували масив і відкривали сусідні і відкритими клітини. Це нечаста операція, тому все пройшло нормально.

Ще тут як раз виникли проблеми з відображенням — якщо кожен раз намагатися промалювати все поле, то виходить занадто повільно, і картинка починає мерехтіти. Довелося зробити невеликий милицю — функцію, яка дозволяє скипать цілі рядки з спрайтів, якщо вони не потрапляють на відображувану рядок. Далі ми плануємо оновити процесор до ATmega2560, щоб вистачило пам’яті на фреймбуфер. Тоді всі проблеми з мерехтінням для подібних ігор изчезнут.

Breakout

Гра називається Breakout, тому що хлопці спочатку хотіли робити саме його. Але потім вирішили, що все складно і у них вийшов Pong. У грі кілька режимів — гра двох гравців, гра з комп’ютером, демонстрація (гра комп’ютера проти себе). Правда от комп’ютер програвати не вміє — йому завжди вдається відбити м’яч. Більш хитрий алгоритм хлопці придумати не встигли. Всього файл з грою займає 272 рядка.

Flappy submarine

Паралельно з дітьми я зробив «Flappy submarine», щоб показувати їм, як працювати зі спрайтами і управлінням.

Усіх цих ігор вистачило, щоб забити 32 кілобайти програмної пам’яті. Але після апргейда до ATmega2560 пам’яті 256 кілобайт, так що в наступному році ми плануємо повторити цей гурток не викидаючи вже створені гри.

→ Вихідні коди проекту на гітхабі

Степан Лютий

Обожнюю технології в сучасному світі. Хоча частенько і замислююся над тим, як далеко вони нас заведуть. Не те, щоб я прям і знаюся на ядрах, пікселях, коллайдерах і інших парсеках. Просто приходжу в захват від того, що може в творчому пориві вигадати людський розум.

You may also like...

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *