Итак, немного о движке. Движок я начал разрабатывать примерно в 2007 году. До этого долго вынашивал идею. В то время движков было очень не много и многие писали свои. Я тоже решил пойти по этому увлекательному пути. За это время (почти 20 лет) движок 3 раза переписывался с нуля и каждый раз архитектура казалась все лучше и лучше. Последнее "переписывание" ядра было примерно 6-7 назад. И кажется сейчас, она выглядит достаточно стабильной и гибкой.
❤2
О возможностях движка. Движок написан на языке С++. Имеет редактор и утилиты для финальной сборки игрового билда. Он разрабатывается по модульному принципу. Пользователи могу добавлять собственные модули расширяя возможности как самого движка так и его редактора.
На данный момент я написал несколько основных модулей для работы с графикой:
- Рендер (OpenGL)
- Редактор Материалов (Shader Graph)
- Редактор текстур (Работа с атласами и прочее)
- Редактор эффектов
Так-же есть модуль отвечающий за обработку физики на основе Bullet3
Модуль скриптового движка (Angel Script)
А так-же ряд различных конвертеров игровых ресурсов.
На данный момент я написал несколько основных модулей для работы с графикой:
- Рендер (OpenGL)
- Редактор Материалов (Shader Graph)
- Редактор текстур (Работа с атласами и прочее)
- Редактор эффектов
Так-же есть модуль отвечающий за обработку физики на основе Bullet3
Модуль скриптового движка (Angel Script)
А так-же ряд различных конвертеров игровых ресурсов.
🔥2
Цель проекта не сделать "убийцу" UE5 или Unity, а сделать небольшой, удобный движок сопоставимый по качеству с Godot. Догнать любой из этих движков в одиночку НЕ ВОЗМОЖНО! Чисто человеческий ресурс не даст сделать это. Поэтому я просто пишу движок и стараюсь получить от этого удовольствие. Написание движков дает очень хороший буст к планированию архитектур и пониманию как оно работает "под капотом". Эти навыки были применены в различных профессиональных областях. Так, что если вам интересно, добро пожаловать в эту глубокую кроличью нору. 😏
🔥6
Во всех игровых движках можно выделить 3 основных части:
1. Система игровых ресурсов - это загрузка ресурсов с диска или процедурная генерация.
2. Обработка игровой логики - отвечает за организацию игрового цикла и правила игры.
3. Вывод результатов работы - это рендеры графики, источников звука и т.п.
Так-же можно выделить (опционально) систему синхронизации состояний между игроками.
Основой всех игр являются данные, поэтому поговорим о системе ресурсов в Thunder Engine. Есть несколько базовых типов ресурсов и несколько вспомогательных. Полный список и их назначение я сейчас приводить не буду.
Во только некоторые из них:
- Texture - Ресурс хранящий в себе картинку которую можно показать на экране (Используется материалом)
- Material - По сути представляет из себя набор шейдеров, определяющих как визуально будет выглядеть объект. (Его цвет и фактура)
- Mesh - Ресурс отвечающий за форму игрового объекта. Состоит из набора треугольников и дополнительных служебных атрибутов.
Thunder Engine использует собственный формат хранения ресурсов. Он нужен для обеспечения скорости загрузки и избегания использования различных загрузчиков в момент работы игры. Конвертация ресурсов происходит в момент импорта ресурсов в редакторе. Конвертированная версия ресурса сохраняется в отдельню папку, для последующей упаковки.
1. Система игровых ресурсов - это загрузка ресурсов с диска или процедурная генерация.
2. Обработка игровой логики - отвечает за организацию игрового цикла и правила игры.
3. Вывод результатов работы - это рендеры графики, источников звука и т.п.
Так-же можно выделить (опционально) систему синхронизации состояний между игроками.
Основой всех игр являются данные, поэтому поговорим о системе ресурсов в Thunder Engine. Есть несколько базовых типов ресурсов и несколько вспомогательных. Полный список и их назначение я сейчас приводить не буду.
Во только некоторые из них:
- Texture - Ресурс хранящий в себе картинку которую можно показать на экране (Используется материалом)
- Material - По сути представляет из себя набор шейдеров, определяющих как визуально будет выглядеть объект. (Его цвет и фактура)
- Mesh - Ресурс отвечающий за форму игрового объекта. Состоит из набора треугольников и дополнительных служебных атрибутов.
Thunder Engine использует собственный формат хранения ресурсов. Он нужен для обеспечения скорости загрузки и избегания использования различных загрузчиков в момент работы игры. Конвертация ресурсов происходит в момент импорта ресурсов в редакторе. Конвертированная версия ресурса сохраняется в отдельню папку, для последующей упаковки.
❤3🔥1
Вторым неотъемлемым компонентом игры является игровая логика. в Thunder Engine базовым объектом является Actor. Вы найдете много схожих черт с GameObject в Unity. Каждый Actor может вмещать в себя коллекцию различных Компонент (Component) эти компоненты могут отвечать за различные аспекты игрового процесса. Отображение игровых ресурсов (Mesh, Sprite и т.п.). Источники звука. Триггеры и прочее. Пользователи могут создавать свои компоненты и добавлять их к Актерам на сцене. (Опять же очень похоже на Unity не так ли?). В целом для упрощения работы с движком, я постарался сделать API похожим на популярные решения. Так будет проще для всех. 😇
❤3🔥1
Последним столпом ядра движка являются Системы. Системы это невидимые пользователю труженики, обеспечивающие последовательность обработки игрового цикла. К примеру ResourceSystem отвечает за жизненный цикл всех игровых ресурсов. Она загружает их с диска и удаляет их когда они больше не требуются. RenderSystem отвечает за отрисовку игрового мира. Есть системы для обработки физики. Скриптовых сценариев и прочие веселые штуки. Обычно система работает либо с компонентами принадлежащими ей либо с ресурсами. Разумеется разработчики могут добавлять собственные системы в игровой цикл.
❤3
Итак после небольшого экскурса в историю и подводки к базовой архитектуре движка. Настало время рассказать чем я занимаюсь на данный момент. Чтош приступим. Относительно недавно я занялся рефакторингом модуля отвечающего за пользовательский интерфейс. В предыдущей версии вся система виджетов была частью основного ядра. Решение это было вынужденное и связанное с зависимостями на соседние модули. Благо их удалось развязать и выделить GUI в отдельный модуль. Что в свою очередь даст возможность отказаться пользователям от лишнего (если их не устроят мои кнопочки и панельки). Но это еще не все. Я обратил внимание на UI Toolkit в Юнити и некоторые полезные фичи решил сделать и у себя.
Встречайте:
UiLoader - компонент который может принимать в себя новый ассет UiDocument представляющий из себя xml репрезентацию вашего UI. Так-же этот XML можно положить из кода и он загрузит его! Чудеса не так-ли?
StyleSheet - Новый тип ассетов который представляет из себя CSS файл. Да да! Тот самый CSS!
Так-же CSS стили можно настраивать и из XML документа.
Разумеется система реализована очень базово и CSS возможности сильно обрезаны. Но фундамент заложен и в дальнейшем возможности можно будет расширять!
Встречайте:
UiLoader - компонент который может принимать в себя новый ассет UiDocument представляющий из себя xml репрезентацию вашего UI. Так-же этот XML можно положить из кода и он загрузит его! Чудеса не так-ли?
StyleSheet - Новый тип ассетов который представляет из себя CSS файл. Да да! Тот самый CSS!
Так-же CSS стили можно настраивать и из XML документа.
Разумеется система реализована очень базово и CSS возможности сильно обрезаны. Но фундамент заложен и в дальнейшем возможности можно будет расширять!
❤3
Давненько хотел добавить поддержку формата Spine 2D. Эта задача лежала в бэклоге аж с 2018 года. Как быстро летит время! Наконец, я на это решился! Формат файла (в JSON варианте) вызывает двойственные чувства. С одной стороны, он кажется избыточным в некоторых полях. А с другой стороны рядом с JSON находится файл атласа, который выглядит как нашлепка. Я не понимаю, почему нельзя было эти данные положить в сам JSON файл? Я специально не хотел использовать существующие рантаймы для отрисовки спайнов т.к. приводит к дублированию функционала и, одновременно, усложняет интеграцию. Поэтому решил попробовать конвертировать структуру в известные моему движку компоненты и ресурсы. Да возможно не все фичи будут поддерживаться на старте (привет бленд шейпы) но я обязательно расширю недостающие элементы (когда-нибудь >_<)
🔥3❤1
Первые, вменяемые, результаты конвертирования из Spine2D. Пока поддерживается: Импорт одностраничного атласа с поворотами элементами в атласе. Импорт Иерархии скелета и размещении слотов для спрайтов на нем. А также, Импорт спрайтов в виде регионов и сеток (но не сеток для скелета). Еще много предстоит сделать. Очень хочется добавить поддержку сеток для скелета и анимацию. Самой последней частью интеграции будут бленд шейп анимации.
🔥4
Решил немного прерваться со спайном и поправить баги которые нашел Павел Танонов в редакторе. Т.к. скоро релиз очередной версии (по плану конец Марта), необходимо максимально отполировать найденные проблемы. Очень помогает взгляд на движок со стороны. Спасибо большое Паше за эту возможность!
🔥4❤3
Эх сколько раз я зарекался делать крупный рефакторинг перед релизом! Но каждый раз хочется что-то улучшить в архитектуре. Вот и сейчас решил переработать Sprite ассет. До этого этот тип ассета был Solid (все данные хранились в нем самом) к такому типу относятся простейшие ассеты, которые нельзя разделить (текстуры, меши и т.п.). Противоположностью solid ассетам являются ассеты-контейнеры. Контейнеры, обычно, содержат в себе ссылки на другие ассеты и дополнительные, внутренние параметры, отвечающие за соединение solid ассетов. В новом релизе Sprite будет ассетом контейнером. т.к. теперь он будет поддерживать несколько страниц текстур, а так-же различные шейпы, представленные в виде мешей. Такой подход, в теории, позволит в будущем использовать повторно некоторые элементы, что положительно скажется на потреблении памяти. После этого рефакторинга, возможно возникновение новых проблем и регрессий. Но, со временем, я их все отловлю! Обещаю!
❤4
Интересную багу нашел Павел в системе скриптов! На данный момент движок поддерживает программирование игровой логики на скриптовом движке AngelScript. Очень достойный и недооцененный движок с поддержкой ООП, компиляцией кода в исполняемый байткод (что ускоряет загрузку) и клевой виртуальной средой исполнения. Короче оказалось, что в редакторе между сессиями симуляции игрового процесса не сбрасывались глобальные переменные, что приводило к странному поведению игровых юнитов (они отказывались двигаться). Фикс занял условно 10 строк. Спасибо Паша!
🔥4❤3
Пока фикшу баги и готовлю релиз, расскажу немного о том, с какими сложностями сталкивается каждая архитектура, которая добавляет любой скриптовый движок. Сюда для удобства включу и C# и Java. Все дело в том, что эти движки работают на основе "managed" сред исполнения. Код написанный на этих движках компилируется в псевдо байт код (иногда вперемешку с реальным байт кодом). Так вот, если разработчик хочет вызывать из нативного кода (С++) функцию написанную скриптом или наоборот из скриптов вызвать код написанный на нативном языке. Для этого у скриптовых движков существует система регистрации "биндигов"
Биндинги это мостики между виртуальной машиной для исполнения и нативным кодом. Проблема в том, что эти биндинги приходится писать зачастую в ручную для каждого класса и для каждой функции. Если у вас много кода поддержка это безобразия превращается в сущий ад. Можно ли облегчить эту работу? Отчасти. Существенно, регистрацию байндингов облегчает так называемая "рефлексия". Рефлексией в программировании называется способность объекта рассказать о себе. Какие методы у него есть, какие свойства и другую важную информацию. К сожалению в C++ по умолчанию нет средств рефлексии классов. Разработчики вынуждены реализовывать ее самостоятельно. Но мы этого не боимся! Механизмы рефлексии есть во многих движках. Мета компилятор в UE, таблицы в Godot. Возможно что-то есть и в Unity. Но не факт! Используя рефлексию мы можем пройтись по всем известным нам классам и зарегистрировать их в системе скриптового движка. При изменении структуры класса, произойдет автоматическое обновление представление его в байндингах. К сожалению это работает только на классе поддерживающем рефлексию. Как правило унаследованном от базового класса типа "Object" для остальных классов и функций (математика, работа с файловой системой и пр.) по старинке приходится писать байндинги ручками. Но таких функций, благо, не много!
❤1🔥1🤯1
Как мы уже разобрали, рефлексия это полезно! Она помогает не только в работе со скриптовыми движками, но и с сериализацией объектов (способность объекта сохранять информацию о своем в буфер с дальнейшим сохранением на диск или отправкой по сети). Это очень существенный шаг от ООП к КОП (Компонентно Ориентированному Программированию). Общий принцип хранения информации о классе сводится к формированию специальных статических таблиц хранящих эту информацию. По необходимости эта информация извлекается и используется в ваших корыстных целях! Различия состоят лишь в том, каким образом формируются эти таблицы. По большому счету варианта 2. Либо программист заносит эту информацию в ручную и часто ошибается либо за него, ориентируясь по меткам, это делает Мета Компилятор. Мета компилятор это отдельная программа которая проходится по всем вашим исходникам и формирует эти таблички за вас. У обоих методов есть как плюсы, так и минусы:
Для ручного метода.
Плюсы:
- Не нужно писать утилиту отвечающую за парсинг и генерацию кода.
- Можно легко расширить и дополнить информацию.
Минусы:
- Необходимо описывать каждый класс вручную и поддерживать актуальность этих данных.
Для утилиты.
Плюсы:
- Автоматически обновляет все данные.
Минусы:
- Необходимо написать этот инструмент и встроить его в процесс построения игровых билдов.
- Расширение фичей может быть проблемным.
Для ручного метода.
Плюсы:
- Не нужно писать утилиту отвечающую за парсинг и генерацию кода.
- Можно легко расширить и дополнить информацию.
Минусы:
- Необходимо описывать каждый класс вручную и поддерживать актуальность этих данных.
Для утилиты.
Плюсы:
- Автоматически обновляет все данные.
Минусы:
- Необходимо написать этот инструмент и встроить его в процесс построения игровых билдов.
- Расширение фичей может быть проблемным.
Так как же обстоит дело с Thunder Engine? Хорошая новость в том, что в нем тоже есть рефлексия! Реализована она по первому принципу с небольшой модификацией предоставляющей небольшую защиту программиста от ошибок. Она основана на системе макросов и шаблонов. Позволяет разбирать методы и типы в полу автоматическом режиме. Подробней ознакомиться с ней можно здесь. А если вам интересно как оно устроено или вы желаете вынести себе мозг, добро пожаловать сюда, сюда, сюда и сюда. Но я вас предупреждал! Однако, платой за защиту от ошибок, является ухудшение возможностей расширения. Так, что этот метод, условно, можно назвать компромиссным. Но я не исключаю, что в будущем возьму курс на написание утилиты, отвечающей за интроспекцию и генерацию кода!
GitHub
thunder/thirdparty/next/inc/core/macros.h at master · thunder-engine/thunder
Thunder Engine – Cross-platform 2D and 3D game engine with modular architecture - thunder-engine/thunder
🔥2🥰1
Немного переделал систему управления стейт машиной рендеринга. Если вы не в курсе, помимо шейдера у пайплайна рендеринга есть и неуправляемые из шейдера части. Однако их можно дополнительно настраивать. Мне давно не нравилось как у меня сделана эта часть в OpenGL (кстати очень неудобная часть т.к. требует множество вызовов). В Vulkan все немного удобней. Эти изменения будут прокинуты в систему материалов и доступны для редактирования пользователями. Еще один шажок к большей гибкости!
🔥1🥰1🤯1
👻1
Усиленно готовлю доклад на эту тему. Очень хочется сделать его минимально нудным. Но ничего не обещаю =(
🔥4
До релиза остается неделя. И настало время подумать о том, что я бы хотел делать в следующем релизе. Напомню, что релизы у меня случаются каждые 3 месяца (если не происходит форс мажоров). Значит следующий релиз случится в конце Июня. Хотелось бы сделать многое, но руки у меня, к сожалению, всего 2 и необходимость еще работать на своей основной работе. Итак:
1. У меня есть изменения связанные с рефакторингом жизненного цикла ресурсов. Их бы я хотел закинуть как можно раньше, что-бы отловить возможные проблемы.
2. Продолжить начатый ранее рефакторинг материалов. Я поменял формат немного, приблизив его к представлению графических API. Теперь нужно дать возможность пользователям менять эти параметры.
3. Закончить импортер Spine 2D (возможно без бленд шейпов)
4. Хотелось бы переработать редактор эффектов (сейчас он сделан на QML частично). Хочу переделать на графы
5. Нужно продолжать совершенствовать редактор графов у себя. Добавить проброс редакторов и вертикальные порты.
6. Если останется времени поработать над системой анимации.
1. У меня есть изменения связанные с рефакторингом жизненного цикла ресурсов. Их бы я хотел закинуть как можно раньше, что-бы отловить возможные проблемы.
2. Продолжить начатый ранее рефакторинг материалов. Я поменял формат немного, приблизив его к представлению графических API. Теперь нужно дать возможность пользователям менять эти параметры.
3. Закончить импортер Spine 2D (возможно без бленд шейпов)
4. Хотелось бы переработать редактор эффектов (сейчас он сделан на QML частично). Хочу переделать на графы
5. Нужно продолжать совершенствовать редактор графов у себя. Добавить проброс редакторов и вертикальные порты.
6. Если останется времени поработать над системой анимации.
❤3👍2
Решил сегодня немного поработать над рендером с использованием вулкана. В целом началось все довольно безобидно. Я исправил работу Bloom фильтра. (он конечно далек от идеального). И тут остро встала проблема, которая зрела довольно давно. А именно ресурс текстур требует небольших изменений. Дело в том, что у меня довольно неочевидно создаются текстуры, используемые в качестве рендер таргетов. Мне давно не нравился текущий способ их объявления. Так что сегодня я заделал рефакторинг этого ресурса. В целом, его формат не поменялся. Я добавил дополнительную систему флагов, которые можно устанавливать для ресурса. На их основе система будет создавать (или не создавать) CPU части для текстур.
❤1🔥1🤯1