Разработка 2D Fantasy Kingdom Sim с нуля. Часть 1: Язык, Движок, Редактор и Графический API
Небольшое введение, задачи прототипа, и разбор технологий которые мне видятся актуальными на 2022 год для основы 2D игры, если вы по каким-то причинам решили не использовать Unity, Unreal или Godot.
Технологии выбирал исходя из задач закончить прототип к ноябрю и личных предпочтений. Поскольку у меня нет опыта коммерчески успешных игр за плечами, то и не стоит воспринимать эту статью в качестве туториала о том как правильно делать игры 🙂
В своем первом посте на DTF пару дней назад я задал вопрос стоит ли здесь делиться подробностями разработки прототипа 2D симулятора в духе RimWorld и Majesty. Поскольку мой пост с одним лишь обрезанным скриншотом из прототипа и редактором кода набрал 30+ лайков, то я решил что это явный успех и принялся за написание статей. Иметь хоть и небольшую, на преданную аудиторию для вопросов, обмена опытом, и обратной связи на данном этапе это предел моих мечтаний 🙂
Обо мне и краткая предыстория
Мне 31 год и последние 10 лет я живу в США, сначала в ЛА и Сан Франциско, а в последние 2 года перебрался в Остин в Техасе. По своей основной специальности я программист и математик. Еще я в детстве 10 лет ходил в художественную школу и последние 6 лет занимался съемкой и цвето-кором в качестве хоби, так что есть некоторые навыки не только в техническом направлении. Тем не менее, после учебы я 8 лет проработал в нескольких FANG компаниях и мой основной опыт это программирование нагруженных бекендов и немного ML и роботов. В основном это примерно поровну Go, C++ и Rust. И немного Typescript и Python для интерфейсов и ML.
Хотя многие вещи из моего прошлого, особенно в robotics применимы в играх, собственно, в геймдеве у меня нет нормального опыта. Поэтому обратная связь это одна из причин почему я задумался начать писать на DTF. Играми я интересуюсь давно, еще в 16 лет в физмат лицее программировал поиск пути и простенькие 2d игры, но фуллтайм этим никогда не занимался. До этого момента я несколько раз пробовал писать свою игру в свободное, сначала на голом C++ и Vulkan, потом со своим знакомым на Unity, но как-то эти попытки затухали через несколько месяцев. В этот раз я решил взять что-то не настолько низкоуровневое как чистый Vulkan, и не настолько высокоуровневое как Unity и попробовать заново.
Концепция и задачи прототипа
Как я уже писал выше игра будет в жанре симулятора фэнтезийного королевства, эдакая смесь RimWorld и Majesty. Вы управляете поселением в духе RimWorld, а ваши герои выполняют квесты истребляя опасных монстров, прокачивая уровни, зарабатывая опыт, лут и деньги на которые они покупают новое оружие, зелья и прочее. В этом, в целом, и будет основной геймлей. Больше деталей и подробностей буду раскрывать в следующих статьях.
Majesty и RimWorld – идейное вдохновление.
С технической точки зрения, прототип должен уметь делать следующее:
- Загружать мир, сущности и ассеты из файловой системы.
- Уметь рисовать спрайты, gizmos, поддерживать слои, 2D меши.
- 2D анимации через спрайты.
- Камера с ортографической проекцией, возможность менять масштаб.
- Уметь обрабатывать сотни сущностей, и взаимодействий: 1) Герои, фауна, монстры. 2) Собираемые ресурсы. 3) Динамические структуры –постройки, мебель, предметы мира. 4) Здоровье. 5) Подбираемые предметы. 6) Стеки и хранилища предметов. 7) Инвентарь героев. 8) Простая система прокачки – опыт и скиллы. 8) Экономика.
- Состояние сущностей – отдыхает, бодрствует, идет к цели и пр.
- Игровой AI который понимает цепочки подзадач для выполнения целей, может симулировать простые решения и взаимодействия. Собственно это один из основных фокусов игры. То, что, как по мне, сложнее всего концептуализировать и то что должно быть сделано наиболее интересным способом для развития игры: 1) Сбор и обработка ресурсов. 2) Строительство. 3) Ремесло. 4) Простая система квестов для героев. Квесты будут раздавать не-герои поселения, например – собери 10 ресурсов для кузница. 5) Ближний бой. 6) Система выживания – героям нужно что-то есть и отдыхать. 7) Базовая торговля – герои должны покупать предметы и оружие, платить за жилье и еду. 8) Поведение монстров и фауны.
- Свойства проходимости ландшафта, навигация, динамические препятствия. Много разных поисков пути. Как на карте, так и в пространстве задач.
- 2D коллизии.
- Календарь, смена дня и ночи.
- Базовое аудио.
- 2D интерфейс: окна, меню, drag & drop, hotkeys, рендер текста, выделение сущностей, задание целей, инвентарь и карточка сущностей (аватар, описание, состояние, статы), меню строительства, счетчики ресурсов экономики.
- Туман войны.
- Найм героев за ресурсы.
Что бы хотелось еще, но этого скорее всего не будет в прототипе в 2022.
- 2D материалы, эффекты, тени и освещение, системы частиц.
- Водные пространства.
- События мира.
- Процедурная генерации мира. Может только самая базовая для автоматизации.
- Подземелья.
- Мультиплеера, но я буду держать его в уме и добавлю при первой возможности.
- Сюжет, диалоги, сценарии, сюжетные предметы, квесты, локации и персонажи. В прототипе только песочница с симуляцией.
- Магия и дальный бой.
- Симуляция социальных связей.
- Фракции. Пока что только один игрок.
- Биомы и бесконечный мир.
- Поддержки чего то кроме PC и Mac.
- Модификаторы и сложная система здоровья (повреждение частей тела и пр.).
- Партии и гильдии.
- Симуляция погоды.
- Нечеткое принятие решений через нейронные сети. Есть идея сделать что-то в духе идеи из Black & White 2 2006 года, где существа принимали решения через запрос к нейронной сети, без жестко прописанных правил. По сути игра должна генерировать набор всех решений для персонажей, а NN модель должна их ранжировать и выбирать наиболее подходящее исходя из состояния героя и его статов (собирать ресурсы, есть, спать, убегать от монстров, заниматься разведкой и пр.). Цель для NN может быть разной исходя из класса героя, условно для лучника это может быть разведать как можно больше окрестностей и не умереть, для паладина – убить самого опасного монстра рискуя собой. Если прототип с основной механикой будет готов к ноябрю, то это одна из основных идей которые я хочу попробовать используя gym от OpenAI.
Выбор технологий
Движок. В моем случае, изначально у меня не было процесса где я сидел и думал какая технологическая основа подойдет для реализации. У меня был опыт с Unity и низкоуровневыми графическими интерфейсами, но я все не решался начинать делать на этом игру. В какой-то момент я наткнулся на Bevy, изучил как работает ECS и иерархия сцены и у меня понемногу начали вырисовываться идеи как можно это все использовать. Bevy мне показался довольно простым и понятным эдаким набором деталей Лего из которых можно собрать что угодно. Легковесный, гибкий, не слишком навязывающий свой подход и имеющий достаточно низкую связанность компонентов. При этом нативный и довольно производительный. Хотя производительность пока для прототипа так важна. К тому же я уже давно хотел поработать над чем-то таким на расте. Поскольку игра в 2D, то и большинство фичей больших движков мне казались не сильно нужны. Хотя в Bevy есть, насколько я могу судить, довольно грамотно спроектированный Render Graph, GLTF, PBR. У движка есть примерно 3k пользователей на Reddit и примерно такой же онлайн в Дискорде. Из спонсоров имеется Embark, вполне серьезная студия из бывших авторов серии Battlefield (как я понял из их сайта, они довольно активно используют Rust в новых проектах). Bevy можно скомпилировать под Mac, Windows, Linux, iOS и Android. Здесь можно почитать про поддержку консолей. Из плюсов, для Bevy уже написано несколько хороших плагинов для интеграции физики, инспектора сцены, UI, конечных автоматов и прочего.
Также, Bevy может компилироваться в WASM, поэтому простенькие примеры можно запускать прямо в браузере поддерживающем WebGPU или WebGL:
Графический API. Следущий переломный момент для меня наступил когда я посмотрел лекцию по WGPU. Тогда я понял что это именно те инструменты которые я искал и начал эксперименты. До этого у меня было представление что WebGPU это стандарт для веба. Оказывается это не совсем так. Несколько лет назад стандарт задумывался разработчиками браузеров именно как низкоуровневая альтернатива WebGL. Насколько я понял над WebGPU работают именно разработчики браузеров, и он никак не связан с Kronos. Изначально, библиотека WGPU создавалась для реализации стандарта WebGPU в FireFox, но позже Mozilla и Google стали поставлять свои реализации этого стандарта для нативных языков отдельно от браузера. У Google свой аналог WGPU называющийся Dawn, и в целом устроенный похожим образом, но реализованный на C++. По сути WGPU это очень тонкая низкоуровневая надстройка над графическими API вроде Vulkan, Metal и DX12 написаная на Расте с заголовками под Си. Вам дается есть очень явный доступ к графическим девайсам – очереди, пулы, буферы команд, дескрипторы, графические и вычислительные пайплайны, примитивы для синхронизации и вот это все. По сложности WGPU где-то посередине между Metal и DX12. Это почти 1-в-1 копия подхода низкоуровневых графических API, из отличий в нем упрощена работа с памятью, и требуется немного меньше кода. Главный плюс WGPU по это кроссплатформенность. В зависимости от системы (mac, pc, ios, android) можно указать разный backend – Vulkan, dx12 или metal. В расте многие библиотеки, в том числе bevy, поддерживают вывод через WGPU, поэтому их ресурсы можно переиспользовать как аттачменты в одном пайплайне без трансфера через CPU.
В WGPU пока нет фичей последних поколений графических ускорителей типа умного апкскейла, ускорения рейтрейсинга и прямой загрузки ресурсов из файловой системы в память память графического ускорителя. В качестве языка шейдеров можно использовать WGSL или GLSL которые будут транслироваться в SPRIV или MSL в зависимости от системы. Насколько я понял, главный разработчик WGPU до этого работал над графическим пайплайном в RDR2. Также автор WGPU довольно активно контрибьютил в Bevy.
Редактор мира. Следующий этап был поиск редактора мира чтобы не приходилось работать над картой через редактирование текста. Поскольку в Bevy редактор пока находится на стадии обсуждений, то пришлось искать что-то на стороне. Насколько я понял для 2D игр есть два популярных варианта – Tiled и LDTK (разработчик – студия работавшая над Dead Cells). Я выбрал последний, для моих задач его должно в основном хватать, но в целом они довольно похожи. Идея в том что вы загружаете в редактор свои тайлсеты, создаете из них карту с помощью сеток с разными слоями и затем добавляете сущности на этой карте. Для сущностей можно указывать свои кастомные свойства – примитивы (числа, строки, массивы), другие сущности, места и пути на карте и прочее. После этого карту можно импортировать в JSON файл и загрузить в свою игру. Для Раста уже написан свой парсер LDTK. Добавить парсер в ассет менеджер Bevy заняло примерно 30 минут. Распарсенный файл LDTK затем указывается как ресурс в системе которая собирает мир игры на старте. Эта система обходит ресурс LDTK, слой за слоем собирает карту из спрайтов, просчитывает данные для навигации и спавнит сущности с заданными параметрами. В целом LDTK в Bevy пока что оставляет приятные впечатления.
Для автоматизации в LDTK можно создать свои правила как которые будут выбирать нужные тайлы для точек соприкосновения разных поверхностей. Из минусов – пока что нет какой-то явной поддержки анимаций.
Язык программирования. Думаю будет не лишним упомянуть язык Rust. Язык в целом очень похож на последние итерации C++, особенно в семантике. В расте нет явной поддержки ООП, в этом он в чем по похож на Go, только вместо интерфейсов здесь типажи. Из главных отличий от других языков – borrow-checker который помогает не допускать некорректного доступа к общим ресурсам, и в основном предотвращает многие классы ошибок памяти и много-поточности. Если отбросить субъективные аспекты (которые по-моему крайне важны если вы – соло-разработчик), то Раст сопоставим с Си и Си++ по производительности (также rustc использует один бекэнд с clang – LLVM), добавляет в исполняемый файл минимум рантайма и не использует сборщик мусора. Для меня огромным плюсом также является cargo, в отличие от Си++ и Си, в Расте намного удобнее управлять зависимостями проекта. Также в отличие от Си и Си++ для раста есть только одна реализация и один компилятор под все платформы что облегчает портирование. На этом сайте собраны библиотеки на Расте которые могут быть полезны при разработки игр: arewegameyet. rs.
Собственно на этих четырех технологиях я начал разработку проекта несколько месяцев назад. Думаю на этом пока закончить первую статью. Если будет достаточный интерес к таким материалам, на следующей неделе я напишу про базовый сетап для Bevy и то как устроена загрузка мира из LDTK, ресурсы и ECS. План на следующие несколько месяцев примерно такой:
- Возможности Bevy, LDTK и загрузка ресурсов и ECS.
- 2D Пайплайн, шейдеры, отладка шейдеров, и спрайты.
- Навигация и поиск пути на карте.
- Взаимодействия сущностей через ECS, сбор ресурсов, цепочки задач.
Буду рад обратной связи. Дайте знать насколько глубоко нужно раскрывать тему. Больше или наоборот меньше технических деталей? Спасибо!
-SNG
Вторая часть здесь: