Гейминг на ПЛИС: во что поиграть?
Отрисовка объектов и проверка координат.
Создание игры ColorFlood на ПЛИС: от теории к «железу»
На профильных ресурсах, включая SE7EN, предостаточно материалов о разработке для ПЛИС. Однако большинство из них сосредоточено на сугубо утилитарных задачах: реализации вычислительных блоков, интерфейсов связи или алгоритмов ЦОС. Это, безусловно, важно, но как насчет игровых проектов? Речь пойдет не об эмуляции старых консолей, а о создании игровой логики «с нуля» на языках описания аппаратуры, таких как Verilog или SystemVerilog.
Моя первая попытка реализовать нечто подобное — проект DoodleJump — столкнулась с суровой реальностью. Чем сложнее механика, тем более громоздкой становится архитектура. В итоге я уперся в дефицит блочной памяти (BRAM) и избыточную асинхронность кода при попытке завести его на частоте 100 МГц. Проект пришлось заморозить, но идея создания полноценной игры на FPGA не давала покоя.
Архивные материалы: ранние этапы разработки (DoodleJump)


Формулировка концепции
Анализируя прошлые ошибки, я выработал критерии для нового проекта:
- Аппаратная независимость: использование чистого Verilog/SystemVerilog без привязки к вендорским IP-ядрам.
- Глубина геймплея: проект должен быть интереснее классического Pong.
- Вариативность: наличие нескольких режимов сложности и типов игры.
- Оптимизация: минимальное потребление ресурсов для запуска на бюджетных чипах.
Идеальным кандидатом стала игра ColorFlood. Её лаконичная графика и логика отлично ложатся на архитектуру ПЛИС. Ниже представлена демонстрация игрового процесса в режиме «Человек против ПЛИС»:
Посмотреть демонстрацию на YouTube
Разработка велась на базе платы Nexys A7 (Artix-7). Исходный код доступен в репозитории: GitHub: fpga_color_flood.
Техническая реализация

Ключевая проблема при выводе графики — отсутствие полноценного фреймбуфера в BRAM из-за его прожорливости. При разрешении 640х480 и цвете RGB444 классический массив пикселей не поместится в большинство ПЛИС. Решение пришло через дискретизацию: экран разбит на блоки 32х32 пикселя. Это позволило оперировать сеткой 20х15, что радикально снизило требования к памяти.
Управление реализовано интуитивно: сбоку от игрового поля находится панель выбора цвета. Кнопки навигации позволяют циклично переключаться между вариантами, а кнопка подтверждения совершает ход. Также добавлен визуальный прогресс-бар в нижней части экрана, отображающий степень захвата поля каждым игроком.
Игровые режимы
- Одиночный: классическая головоломка на захват поля за минимальное число ходов.
- VS ПЛИС: соревнование с алгоритмом. Реализовано два уровня сложности AI: от простого выбора первого доступного цвета до поиска наиболее выгодного хода на основе анализа соседних ячеек.
- PvP (Два игрока): поочередные ходы для двух человек.
Для генерации игрового поля используется массив из 128 псевдослучайных значений. Уникальность каждой партии обеспечивается смещением индекса в массиве, которое зависит от момента нажатия кнопки сброса (reset).
Настройка модуля game.sv
Для удобства адаптации под разные платы в основном модуле предусмотрены параметры:
- BG_COLOR: цвет фона.
- COLOR_1…5: палитра игровых блоков (совместима с RGB111).
- ANTI_BOUNCE_DELAY: настройка антидребезга кнопок (актуально для старых плат).
- DRAW_MARK: включение меток в центре квадратов для удобства подсчета.
- NEW_YEAR: пасхалка с праздничной елкой.
- ONLY_GAME_MODE_0: режим жесткой экономии ресурсов (отключает AI и PvP, снижая потребление до 5к LUT).
Пример визуализации с метками и праздничным режимом


Портирование на другие платформы
Если у вас не Nexys A7, для запуска потребуется создать обертку для файла game.sv:
- Настройте VGA-выход (или HDMI через конвертер типа
rgb2dvi). - Подайте тактовый сигнал 25 МГц (стандарт для 640×480 @ 60Hz).
- Назначьте кнопки управления (Select Up/Down, OK) и сигнал Reset (активный низкий уровень).
- Установите режим игры через двухбитный переключатель
mode_game.
Инструментарий: Скрипт на Python для конвертации графики
Этот скрипт преобразует любое изображение 32х32 в массив SystemVerilog для использования в игре.
from PIL import Image
import numpy as np
def convert_to_rgb444(r, g, b):
return ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4)
def image_to_sv(image_path, output_path):
img = Image.open(image_path).convert('RGB')
w, h = img.size
pixels = img.load()
with open(output_path, 'w') as f:
f.write(f"reg [11:0] image_array [{h-1}:0][{w-1}:0];\ninitial begin\n")
for y in range(h):
for x in range(w):
r, g, b = pixels[x, y]
val = convert_to_rgb444(r, g, b)
f.write(f" image_array[{y}][{x}] = 12'h{val:03X};\n")
f.write("end")
if __name__ == "__main__":
image_to_sv("icon.png", "image_init.sv")
Итоги
Проект показал, что даже без использования внешней памяти и сложных IP-ядер на ПЛИС можно реализовать полноценную игру с ИИ и графическим интерфейсом. Полная сборка со всеми функциями занимает около 11к LUT на Artix-7, что позволяет запустить её на большинстве современных отладочных плат.

Буду рад обратной связи и результатам тестов на ваших железных платформах. Ссылка на исходники: GitHub.
Экшен X-Men Origins: Wolverine удалось разработать без переработок благодаря переносу фильма
Разработчик Total War Warhammer 40000 рассказал о влиянии настольной игры на стратегию
Для модификации Dawn of the Tiberium Age вышла новая фанатская кампания
Blizzard внедрила онлайн-DRM в Warcraft III: Reforged после релиза кампании Forsaken Kingdom
Sony PlayStation добилась закрытия фанатского мультиплеера The Last of Us Part II на ПК
Геймдизайнер объяснила отказ от выпуска Kemuri на Xbox угрозой для здоровья разработчиков
Создатель популярного мода для Half-Life: Alyx выпустил шутер Gunman Contracts Stand Alone
Owlcat показала культовое оружие огринов в тизере Warhammer 40,000: Dark Heresy