Гейминг на ПЛИС: во что поиграть?

Создание игры 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:

  1. Настройте VGA-выход (или HDMI через конвертер типа rgb2dvi).
  2. Подайте тактовый сигнал 25 МГц (стандарт для 640×480 @ 60Hz).
  3. Назначьте кнопки управления (Select Up/Down, OK) и сигнал Reset (активный низкий уровень).
  4. Установите режим игры через двухбитный переключатель 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.

 

Источник

Читайте также