Znak - простой 2D игровой движок
Давно не было новостей, пора исправить этот недочет. Последний месяц занимался написанием простейшего 2D-движка, способного работать как на десктопе (win
/mac
), так и в вебе (webgl2-wasm
), похожего по своей структуре и апи на Unity, собирающийся за секунды в относительно небольшой размер, выдающий неплохую скорость рендера и с кодовой базой движка и пользовательского на одном языке.
Особенности
- Движок получил название Znak.
- Рендер реализован на
OpenGL 3.3
/WebGL2
, на десктопе используетсяGLFW 3.4
. Данные профили позволяют реализовывать кроссплатформенную и достаточную для инди-игр графику, повышениеOpenGL
-профиля не планируется. - В качестве языка был выбран Golang - низкий порог входа, неплохое быстродействие, неплохой конечный размер бинарника, быстрая сборка. Ну и основной плюс - отсутствие ООП в его классическом представлении.
- Внутри все реализовано как 3D-движок, при необходимости можно расширить апи и функционал для поддержки нового функционала.
- Весь рендер идет строго через инстансинг (instancing), даже если это 1 спрайт, присутствует автоматическое склеивание нескольких вызовов отрисовки одного меша одним материалом в один вызов.
- Есть поддержка бандлов/паков (архивов контента) со сжатием и шифрацией.
- Есть поддержка sdf-шрифтов с предварительным запеканием атласа (утилита в комплекте).
- Есть поддержка
BMFont
-шрифтов (импорт в формат движка). - Есть поддержка пользовательского ввода с клавиатуры/мыши, минимальная поддержка touch-скрина.
- Разрабатывается как решение без внешних зависимостей (библиотек), доступ к которым может пропасть в силу разных обстоятельств.
- Планировался как альтернатива Ebiten - но с большей скоростью работы, меньшим размером бинарника и большей схожестью с Unity.
Пример
Давайте рассмотрим реализацию bunnymark
- теста на вывод большого количества спрайтов, которые перемещаются, вращаются и выводятся на экран. За основу возьмем пример из Ebiten: https://ebitengine.org/en/examples/sprites.html, но будем красить в разные цвета, как в примере из Defold https://defold.com/examples/sprite/bunnymark/ - это “съест” порядка 15% максимальной производительности на десктопе и 30% в Web
-е, но будет более честным по отношению к Defold-тесту.
Для работы движка потребуется установка golang
, gcc
, tinygo
и binaryen
- последние 2 пакета опциональны и нужны только если необходима сборка сверхмалых приложений. Все эти приложения можно установить через https://scoop.sh/ под Windows
и https://brew.sh/ под Macos
, инструкции есть в документации движка.
Znak
реализован в качестве golang
-пакета, но он недоступен для скачивания по какому-то публичному адресу, поэтому его необходимо подключить локальной папкой через "go mod edit"
(инструкции есть в документации), после подключения станет доступным пакет с именем go.leopotam.ru/znak
.
Инициализация движка похожа на Ebiten за исключением загрузки контента через пак:
1 | import ( |
Вся логика разбивается на логические “сцены” (похоже на сцены в Unity с одним MonoBehaviour
-ом), у которых есть следующие методы:
1 | type IScene interface { |
В этом примере тип game1
реализует все эти методы. Полный код примера:
1 | package main |
Сборка
Для сборки вызываем утилиты из дистрибутива Znak, по умолчанию собирается под десктоп:
1 | go run go.leopotam.ru/znak/tools/build -prod -o ./dist . |
1 | Length Name |
Под Windows
получится 1 файл размером 2.5Мб
. Неплохой размер, в дальнейшем можно будет еще уменьшить.
Давайте соберем под web
штатным компилятором:
1 | go run go.leopotam.ru/znak/tools/build -t wasm -prod -o ./dist . |
Получим 3 файла:
1 | Length Name |
Размер главного файла - чуть больше 1Мб
- это уже лучше, чем 10Мб
у Ebiten.
Теперь попробуем сборку через TinyGO:
1 | go run go.leopotam.ru/znak/tools/build -t wasm-tinygo -prod -o ./dist . |
Получим 3 файла:
1 | Length Name |
Размер 280кб
- и это с контентом! Правда скорость работы сильно ниже из-за особенностей реализации tinygo
- придется выбирать либо полную скорость и больший размер, либо минимальный размер и более низкую производительность.
Тесты
Проверить и сравнить производительность можно по ссылкам ниже:
Znak Golang-версия
Znak TinyGO-версия
На одном и том же железе golang-версия выдает 60к спрайтов до просаживания ниже 60фпс, tinygo-версия не держит даже 10к. Так же текущие tinygo-сборки “текут” по памяти, хотя сборщик мусора не отключен - не рекомендуется к использованию, только для тестов.
Для сравнения:
- Znak-golang-версия выдает 60к спрайтов (размер
1Мб
) - Znak-tinygo-версия выдает примерно 9к спрайтов (размер
280кб
) - Ebiten-версия выдает 8к спрайтов (размер
9.57Мб
) - Defold-версия выдает 27к спрайтов (размер
1.4Мб
)
Znak доступен в виде обновляемого пакета для подписчиков.
Актуальные версии пакетов доступны в закрытом telegram-сервере для vk/boosty-подписчиков.