Помещения и карта для каждой миссии у меня в игре создаются процедурно. После того, как здания построены, генерируются ускоряющие дорожки. Этот не совсем очевидный элемент дизайна я придумал для красоты, ускорения перемещений и для дополнительных монет.
Чтобы получить с дорожки монеты, нужно проехать по ней полный круг. Не слезая. Обычно вокруг полно монстров, поэтому алгоритм такой: покрошить всех вокруг, а затем поездить по дорожкам - собрать монеты.
Так вот, планы помещений могут сгенерироваться очень разными и странными. Ускоряющие дорожки, соответственно, тоже иногда получаются очень длинными и не прямыми. На видео, например, я проехал по одной такой.
Иногда сгенерированное здание получается настолько прикольным, что хочется поиграть в нем еще раз. Однако сейчас это не возможно, т.к. на каждый запуск генерируется новое уникальное здание. Может сделать функцию сохранения в файл? Надо подумать.
Выпустил бесплатную демо-версию Coin-Op Vice на страничке в Стиме. Заходите поиграть!
Доделал процедурную генерацию карты и зданий. Каждое прохождение теперь уникально, т.к. здания получаются очень разные. Топология, кстати, тоже случайная. Первый этаж, например, может располагаться на разных берегах реки (автодороги), а соединение будет на верхних этажах. В какой-нибудь части здания может, например, построиться узко-высокая башня.
Алгоритм построения этажа достаточно простой. Создаются строители, которые могут строить комнаты и коридоры, при этом поворачивая и изменяя свои параметры.
Сложнее было согласовать действия этих строителей, чтобы здание получилось связанным - была возможность попасть в любую точку на любом этаже.
Если вам нравится стиль, то добавляйте игру в список желаемого на страничке в Стиме.
В этом гайде рассказываем, как быстро и легко сделать процедурную текстуру в Unreal Engine 5 на примере асфальта — чтобы дороги в вашей игре выглядели интересней и разнообразней.
Далее выбираем следующее: Target Platform — Desktop, Quality Preset — Maximum. Галочки на Starter Content и Raytracing не ставим.
Запустите проект. У вас откроется уровень из шаблона: чтобы убедиться, что всё работает, можете поездить на машине, нажав на зелёную кнопку Play сверху.
Так должен выглядеть проект
Загружаем карты в Unreal и добавляем в материал
Внизу Content Drawer (контент-бразуер)
Скачайте или сделайте материал. Для гайда мы возьмём его здесь.
Из всего материала нам нужны две карты: Road003_8K_Color и Road003_8K_Roughness.
Далее в Content Drawer откройте папку Track. Перетащите в Unreal обе карты из папки, куда их сохраняли.
Всё что нужно оставить от нод
Откройте материал M_Track и удалите всё, кроме основной ноды M_Track.
Перенос текстур из Content Drawer
Content Drawer — папка Track. Перетащите оттуда текстуры в окно с нодами. Пока ничего с ними не делайте.
Создание и поиск нужной ноды
Чтобы создать ноду, нажмите ПКМ на любом свободном месте, впишите её название и нажмите Enter.
Нода TextureCoordinate даёт базовые UV-координаты, с которыми вы дальше сможете работать. Нода CustomRotator позволяет поворачивать текстуры в UV-пространстве.
После подключите ноду TextureCoordinate в CustomRotator во вход UVs (V2), в Constant впишите значение 0,25 и подсоедините ко входам Rotation Center и Rotation Angle.
Выход ноды CustomRotator подключите во вход UVs к обеим нашим текстурам. Текстуру Road003_8K_Color подключите к Base Color материала M_Track.
Должно получиться так
Создаём шум для текстуры
Должно быть так — это результат всех действий в разделе
Теперь создадим и настроим шум, который сделает асфальт процедурным и добавит на него лужи.
Для этого создайте ноды World Position, Constant, Multiply и Noise. Подключите выход XYZ ноды World Position и выход Constant ко входам ноды Multiply. В дальнейшем этой константой вы сможете регулировать размер луж на текстуре.
Выход ноды Multiply подключите ко входу Position ноды Noise. На время подключите выход ноды Noise ко входу Base Color материала M_Track, чтобы видеть все изменения и настройки.
В ноде Constant установите значение 0,01.
Нода World Position даёт вектор с координатами, который в ноде Multiply умножается на значение константы — у нас оно 0,01. Это позволяет регулировать размер шума, который создаёт нода Noise.
В ноде Noise измените параметр Function на Gradient - Computational — он отвечает за тип генерации. Ещё вы можете поиграться с настройками Output Min и Output Max — они позволяют детальнее настроить внешний вид шума. Мы установили для Output Min значение -0,384, Max не изменяли.
Также в ноде Noise уберите галочку с Turbulence и поставьте галочку на Tiling.
Создайте ноду Saturate и подключите в неё ноду Noise. Нода Saturate обрезает значения, оставляя диапазон от 0 до 1.
Далее создайте ноду Power и подключите в неё Saturate. Ноду Power подключите к Base Color материала.
В параметре ноды Power установите значение 0,5 — так вы сделаете шум контрастнее. Если напишите число больше 1, шум станет более мягким и размытым и белых областей будет меньше.
Верните текстуру Color обратно во вход Base Color.
Создаём Roughness
После создания Roughness должно быть так
Карта Roughness отвечает за гладкость или шероховатость текстуры. Нам она нужна для усиления эффекта пористости асфальта.
Создайте ноду LinearInterpolate и две Constant. Нода LinearInterpolate, или же Lerp, смешивает два входа, используя вход Alpha как маску. Выход ноды LinearInterpolate подключите во вход Roughness материала.
Во вход Alpha ноды Lerp подключите ноду Power, а во входы A и B две новые Constant. В Constant A ставим значение 0, в Constant B — значение 0,06.
Создайте ещё одну ноду Lerp. В её вход Alpha подключите ноду Power, во вход А подключите ноду Lerp, которая сейчас подключена во вход Roughness материала M_Track. После этого создайте новую Constant, поставьте ей значение 1 и подключите во вход В ноды Lerp, которая подключена к Roughness.
Создайте узел на линии связи ноды Power с нодами Lerp. Узлы используют для удобства и оформления — из них можно вытаскивать неограниченное количество линий. Чтобы создать узел, два раза нажмите ЛКМ на линии связи нод в том месте, где хотите создать узел.
Создаём Normal
После создания Normal должно быть так
Карта Normal используют для создания неровностей текстуры. В нашей случае она будет дополнять Roughness.
Чтобы её сделать, создайте ещё одну ноду Lerp. В её вход Alpha подключите ноду Power, а во вход B подключите текстуру Road003_8K_Roughness.
Создайте ноду Luminosity_And_Color — она объединяет вектор и скалярное значение. На её вход Color (V3) подключите RGB-выход текстуры Road003_8K_Roughness, а на Luminosity — выход ноды Power.
Во вход A новой ноды Lerp подключите выход ноды Luminosity_And_Color. Выход последней подключите на выход Normal материала M_Track.
Создаём Metallic и Specular
После создания Metallic и Specular должно быть так
В белых областях карты Metallic будут проявляться световые свойства металла, то есть блеск и отражение, а карта Specular отвечает за «загрязнённость» текстуры: в белых областях свет будет отражаться лучше, в более тёмных — хуже из-за грязи или других визуальных недостатков. Эти карты мы используем для реалистичного отражения света на асфальте.
Для входов Metallic и Specular материала M_Track создайте две Constant со значениями 0 и 1, а также две ноды Lerp.
В первую Lerp во вход А подключите значение 1, во вход В — значение 0, в Alpha подключите выход Power.
Выход из ноды Lerp подключите ко входу A следующей ноды Lerp и ко входу Specular материала M_Track.
Во входе В поставьте значение 0,5, в альфа 0,7. Выход подключите к Metallic материала.
Сглаживаем текстуру с помощью SmoothThresold
Ноды после подключения SmoothThresold. А ещё это финальный вид карты нод — после ничего не меняем
Сглаживание избавит текстуру от лишних зернистости и стыков, а ещё сделает внешний вид более гладким и монолитным.
Создайте ноду SmoothThreshold. Её нужно подключить между нодами Saturate и Power.
Ноду Saturate подключите во вход Lerp Value ноды SmoothThreshold. Для входа Cutoff Value создайте новую Constant со значением 1, для входа Gradient создайте новую Constant со значением 0,01.
Все Constant можно перевести в Parameter. Для этого кликните по ним ПКМ и нажмите Convert to Parameter — это позволит создать Material Instance, чтобы в нём мы могли интерактивно контролировать наш материал.
Мы постарались сделать каждый город, с которого начинается еженедельный заед в нашей новой игре, по-настоящему уникальным. Оценить можно на странице совместной игры Torero и Пикабу.
Он рассказал, как создать процедурный материал с человеческими черепами и костями из катакомб, а мы перевели.
Поиск референсов
Для работы Джо вдохновлялся Парижскими катакомбами и материалами художников Арвина Виллапандо, Альберта Сото и Дэрка Эльшофа. Он хотел создать детализированную карту высот, на которой бы кости минимально накладывались друг на друга и достигалась бы их глубина и многослойность.
Джо было важно сохранить сломанный вид черепов из референсов и сделать рендер максимально реалистичным. Для этого он использовал Marmoset и Unreal Engine 5.
Располагаем черепа и кости
Возьмите готовые модели черепов или сделайте свои. Джо взял модели от Dystopia Interactive
Создайте развёртку в ZBrush и запеките на плейн
Создайте несколько костей по референсам и расположите их под разными углами для вариативности
Расположите черепа, используя ноду Tile Sampler и простую маску. Так, вы сможете контролировать расположение черепов на материале
Процедурно сломайте некоторые черепа в Substance Designer, чтобы можно было на них посмотреть изнутри
Разбейте и разбросайте кости в Substance Designer, чтобы неограниченно комбинировать повреждение и расположение костей
При разбрасывании костей слишком близко в Substance Designer может возникнуть проблема с наложением.
Наложите несколько нод Atlas Scatter с разными костями под разными углами, чтобы появилось ощущение структуры и глубины
Создаём повреждения
После добавления больших разрушений на черепа нужно добавить мелкие трещины и сделать так, чтобы они выглядели реалистично и взаимодействовали с большими трещинами:
Наложите большие трещины на черепа, которые уже разбиты
Наложите более мелкие трещины с очень низкой интенсивностью на некоторые черепа
При создании грязи важно помнить, что она должна выглядеть по-разному, взаимодействовать с костями и естественным образом образовываться вокруг них:
Добавьте большие и маленькие фигуры, чтобы материал выглядел хорошо с любого расстояния
Используйте ноду Fractal Sum Base для шума: в ней вы сможете ввести минимальные и максимальные значения
Используйте ноды Ambient Occlusion и Shadow, чтобы получить разные маски из костей
Добавьте результат на общую карту высот, чтобы создать разные ямки, соответствующие форме костей
Преимущество процедурной текстуры в том, что при изменении количества костей грязь будет подстраиваться.
Делаем цвета
Для Base Color Джо хотел создать комбинации цветов между костей так, чтобы они выглядели просто и читабельно для игрока. Он использовал ноду Color Variation художника Бена Уилсона, с помощью которой можно добиться естественных вариаций цвета, имея только несколько шумов и один цвет.
Color Variation — более точный способ создания базового цвета, поскольку добавленный цвет можно менять, а не полагаться на ноды Gradient Maps и HSL. Если у вас есть картинки референсов, вы можете взять однородные цвета с них.
Используйте ноды Dirt и Dust в конце. Нода Dust добавит реалистичности материалу, поместив пыль поверх черепов
Используйте ноду Shadows, чтобы добавить грязь под костями. Это тоже прибавит материалу реалистичности
Делаем Roughness и карту высот
Для создания Roughness возьмите карту высот и понизьте контрастность с помощью фильтра Histogram Range
Используйте эффект Colour Variation, чтобы сделать Roughness вариативнее
Добавьте эффект Flood Fill to Random Grayscale на материал, чтобы Roughness у каждой кости отличался
Используйте ноду Directional Warp на некоторых шумах, чтобы добавить дополнительные детали для Roughness. Убедитесь, что они соответствуют форме костей
Важно добавить Roughness как можно больше деталей и реалистичные вариации, которых нет на других картах:
Создайте несколько новых комбинаций шумов отдельно для Roughness
Смешайте разные получившиеся маски, например грязи и пыли, с помощью нод смешивания, чтобы улучшить карту Roughness
Скорректируйте параметры костей и камней так, чтобы они были менее грубыми и больше контрастировали с шероховатостью грязи. Это сделает материал более читабельным и улучшит финальные рендеры
При создании карты высоты важно перенести интересные визуальные формы из референсов, от маленьких деталей до больших.
Карты нормалей и Ambient Occlusion можно создать из карты высоты. Они станут базой для вашего материала
Используйте шумы и маски из карт высот, нормалей и Ambient Occlusion, чтобы создать базовый цвет и шероховатость — это ускорит рабочий процесс
Как ещё можно улучшить результат
Используйте ноды Directional Warp и маски из карты высот, чтобы детали соответствовали формам текстуры
Разделите разрушенные детали по тайлам, чтобы детали были уникальны для каждого тайла. Избегайте эффекта единого слоя трещин поверх всех тайлов
Располагайте большие трещины на сломанные черепа, а маленькие на целые — чтобы не было ощущения, что трещины располагали случайно
Помните про сторителлинг: с материалом взаимодействовали люди и на него влияло окружение
Приветствую всех на Пикабу! Разработка компьютерной игры Rekesh Gaal продолжается. Давно не делился своими рабочими моментами и сегодня хочу это исправить. Все последние две-три недели занимался разработкой системы процедурной генерации для подземных уровней. Решил это сделать, так как считаю, что это должно в перспективе сэкономить много времени, плюс "процедурка" дает идеальную точность. Реализована система на Блупринтах, в последствии возможно переделаю на С++.
Ранее собирал свой первый уровень вручную из своих же ассетов и это был хороший опыт, так как это дало представление, какая должна быть система генерации и сами ассеты в моем случае (последние практически все пришлось переделать) . Также когда планировал концепцию, были мысли сделать "процедурку" при помощи сплайнов, и у них есть свои плюсы, но в итоге решил обойтись без них.
Deep Despair 2 - когда разработчики добавляют кучу механик в сиквел игры: тут есть всё от Dungeon Crawler до симулятор ферми, от РПГ с крафтом до водного транспорта с выживанием в открытом мире. Оценки на Steam очень положительные
Deep Despair 2 — это приключенческая игра на выживание в открытом мире с процедурной генерацией и полной свободой действий. Игра является прямым продолжением и развитием первой части. Сиквел стал намного масштабнее, серьезнее, интереснее и обзавелся множеством новых механик, которые помогут вам выжить или скрасить досуг в игре. Вы вольны заниматься животноводством, производством спирта для изготовления различных напитков и коктейлей Молотова, пивоварением, приготовлением пищи, фермерством, строительством и укреплением своей базы (электричество вам в помощь!) или просто собирайте еду и отправляйтесь в путешествие через разнообразный мир, сопровождаемый дождем. Зелья помогут вам расти быстрее и сильнее, кулинария откроет для вас множество сытных блюд, а собственная ферма будет снабжать вас всеми необходимыми ресурсами. В игре вам не будет скучно, если вы любите свободу действий и умеете себя развлечь!
Подготовьте меч, заточите его на наковальне, наденьте обсидиановые доспехи, запаситесь едой с зельями и отправляйтесь в недра, чтобы добыть кристаллы магмы для создания лучшего снаряжения в игре! После этого можно отправиться на заснеженный Северный полюс и насладиться прохладой. Добро пожаловать в чудесный новый мир Deep Despair 2! Он вернулся.
Особенности
Более 500 предметов и широкий крафт с использованием самых разных приспособлений
Огромные процедурно генерируемые миры с богатой флорой и фауной
Разнообразные биомы: лес, пустыня, пляж, река, океан, болота, джунгли и даже Северный полюс
Водный транспорт для полноценных морских путешествий
4 уровня подземелий: шахты, глубокие пещеры, лавовые озера и недра
Опасные боссы с уникальной добычей
Более 10 видов брони с уникальными бонусами
Полноценная внутриигровая карта с системой маркировки
Новая боевая система, основанная на парировании и блокировании атак щитом.
Всем привет. Решил поделиться кодом для создания подземелья, который я использую в своём рогалике. Код опубликовал год назад, но добавить пояснения и комментарии для начинающих руки дошли только сейчас.
В игре есть тропический остров, на котором расположены руины, после обнаружения которых игрок спускается в подземелье состоящее из нескольких этажей (есть опция начать сразу с подземелья). Собственно с помощью кода создаётся основа для каждого этажа (но можно использовать и для создания интерьеров в наземных прямоугольных строениях). Работа алгоритма построения проста - сначала строится горизонтальная или вертикальная стена и в ней отмечается дверь (или несколько), таким образом пространство делится на две части, в каждом из которых происходит последующее разделение на две части и т.д. За основу взят метод построения правильных лабиринтов “Recursive Division”, посмотреть интерактивные примеры (в том числе и для десятка других алгоритмов) и код для ruby можно здесь: http://www.jamisbuck.org/mazes/
Чтобы в подземелье были «комнаты» и возможность нарезать круги добавлено ограничение на минимальный размер комнаты (int roomMinHorizontal, roomMinVertical) и шанс построения дополнительной двери (int extraDoorChance, minLengthForExtraDoor - минимальная длинна стены для дополнительной двери). В коде всего три метода, давайте посмотрим что они выполняют.
CreateDungeon() - главный метод, вызывается по нажатию пробела, строит подземелье и отрисовывает его на спрайте. В начале метода происходит проверка размера карты - по горизонтали и вертикали должны быть только нечётные числа. Затем идёт инициализация двумерного массива int[,] maze в котором и будет храниться карта. Далее - вызов метода разделения начальной пустой области Division(). Отрисовка полученной карты идёт с 39 по 56 строку - создается текстура и спрайт, текстуре присваивается цветовая информация (стены, пол, двери). Этот фрагмент можно использовать для отображения в игре мини-карты.
Division(int startX, int endX, int startY, int endY) - определение как надо разделить переданную область от стартовых координат (intstartX, int startY) до конечных (int endX, int endY) на две части. В методе производится проверка габаритов области и если она слишком мала то выходим из метода через return - в этом случае дальнейшие действия в этом прямоугольнике не производятся. Если нет - создаём новую область через CreateRoom().
CreateRoom(bool isHorizontal, int startX, int endX, int startY, int endY) - непосредственно построение стены и дверей в определенной «комнате». isHorizontal - область по горизонтали шире чем по вертикали, т.е. будет ли построена вертикальная или горизонтальная стена. Сделано для того, чтобы комнаты не были слишком растянуты в одном из направлений. Это определяется в предыдущем методе через if (endX - startX > endY - startY), для квадратных комнат используется рандомное расположение стены. После этого проводится стена в массиве maze[verticalWall, i] = 1 (0 - пол, 1 - стена, 2 - дверь), через int doorNumbers определяем количество дверей в ней - как минимум должна быть одна дверь (но вы можете усложнить не добавляя на этом этапе дверей и создав телепорты для несвязанных частей подземелья). Затем вызывается Division() для каждой из двух областей разделённых стеной и происходит дальнейшее деление, пока не останется неразмеченных областей, после чего продолжится выполнение метода CreateDungeon() и будет визуально отрисована карта получившегося подземелья.
Итак, какие есть плюсы и минусы данного алгоритма. Построение комнат элементарно, при этом они все связаны и при дополнительных дверях появляется нелинейность прохождения. Также игровое пространство используется по максимуму, а с получившимися прямоугольниками в дальнейшем легко работать, расставляя в них мобов и дополнительный интерьер. В то же время, простота алгоритма определяет и его недостатки - некоторая однообразность и предсказуемость - в подземелье будет как минимум одна стена идущая от края до края. Более интересных и «пещеристых» подземелий можно добиться с помощью модификации этого алгоритма под названием "Blobby" Recursive Subdivision Algorithm (в ссылке выше примеры идут сразу после Recursive Devision). Однако, для своего проекта решил остановиться на первом варианте, поскольку мне удобнее работать с прямоугольниками, а вот внутри уже них я применял другие алгоритмы для создания самых разнообразных помещений, пещерок и коридоров. Вот примеры того как таким образом можно усложнить подземелье (игрок на карте отмечен зелёным кружочком):
Здесь коридоры на самом деле тоже находятся внутри прямоугольных комнат - они просто соединяют клетки дверей граничащих комнат, а остальное пространство заливается стенами.
Пару слов о рогалике Tzakol in Exile. Разработку веду с 2021 года, планировал опубликовать в прошлом году, но притормозил и отодвинул дату до лучших времён. Сейчас периодически добавляю новый контент и то, что раньше было демоверсией постепенно повышаю до уровня lite - бесплатной версии. В ней есть два режима - с мета-прогрессией и в стиле традиционных рогаликов (доступны за исключением нескольких последний этажей и сражения с финальным боссом). Планирую добавить ещё блиц-режим, который будет представлен в lite-версии полностью. Скачать демо можно в стиме: https://store.steampowered.com/app/1764840/Tzakol_in_Exile/
Если есть вопросы по коду или по игре - пишите в комментариях, постараюсь ответить.