Рубрика развивается при поддержке

От грубых форм к естественной среде: создание уровней в Unexplored 2 — часть третья Материал редакции

Наглядный пример использования диаграммы Вороного.

В закладки
Аудио

Йорис Дорманс в блоге студии Ludomotion рассказал, как в Unexplored 2: The Wayfarer's Legacy происходит превращение грубых уровней, сгенерированных на основе тайлов, в приятные и естественные локации. Мы выбрали из текста главное.

Карты создаются с использованием обозначений разных типов тайлов (в данном примере это трава или земля) и различных декораций.

В этом случае есть несколько кустов (большие зелёные круги), скалы (чёрные круги), растения (маленькие зелёные круги), цветы (белые круги) и декоративные текстуры (серые квадраты). Существуют также специальные тайлы, которые играют важную роль в геймплее, такие как точка появления на уровне, отмеченная символом «s». Кроме того, тайлы могут быть помечены дополнительной информацией о высоте или особом подтипе.

Карты тайлов — это удобная структура данных для работы с генераторами, но такой подход может привести к тому, что стыки тайлов будут бросаться в глаза во время прохождения. Тем не менее в Unexplored 2 они выглядят вполне естественно.

Хитрость заключается в том, что отдельные тайлы сопоставляются с ячейками в диаграмме Вороного. И это можно использовать для создания форм, которые выглядят намного более естественными. Для создания подобной диаграммы Вороного плоскость случайно заполняется точками, а ячейки формируются таким образом, чтобы каждая охватывала ближайшую к себе точку. Типичная диаграмма со случайным, но равномерным распределением точек, выглядит примерно так.

Для Unexplored 2 разработчики используют разные типы распределения начальных точек, но всегда одна точка — это один тайл. Благодаря этому каждый тайл можно сопоставить с определённой ячейкой на диаграмме Вороного. Если разместить начальные точки в середине каждой ячейки, получится ровная сетка, которая выглядит точно так же, как карта тайлов.

На этом этапе генерации уровня окружение выглядит так
А так выглядит уровень, у которого половина тайлов отрендерена жёлтым цветом. Это позволяет наглядно увидеть структуру локации 

Более естественным уровень помогает сделать случайное положение каждой начальной точки. Во время их смещения такое решение позволяет убедиться, что они не выходят за пределы своего исходного тайла.

Такой вариант уже выглядит лучше, но это всё ещё не похоже на плавные и приятные линии. Чтобы добиться лучшего результата, нужно провести технику «relaxing» — стандартный способ изменения диаграммы Вороного. Но даже с использованием такого метода, результат будет получаться несколько беспорядочным.

Чтобы справиться с этим, нужно сделать так, чтобы точки перемещались по какой-то системе, а не просто случайно. Разные типы перемещения дают разные эффекты. Например, использование Шума Перлина может создавать интересные тайлмапы с естественными формами. Или можно превратить всё это в шестиугольные тайлы, переместив каждый второй ряд начальных точек влево.

Но самое интересное наступает при попытке переместить начальные точки по определённому паттерну, чтобы создать закруглённые углы. Первый шаг этого процесса уже сделан внутри генератора уровня — углы можно легко обнаружить на стыках разных типов поверхности, а крайние тайлы содержат информацию о том, как их следует деформировать.

В этом случае перепады высот также приводят к появлению углов на карте тайлов. Вот почему можно увидеть дополнительные закруглённые углы в траве в правом верхнем и левом нижнем углу, где были созданы склоны.

Игра использует эту информацию для смещения начальных точек диаграммы Вороного — каждый закруглённый угол смещает местоположение начальной точки. Кроме того, он также сдвигает начальные точки своих четырёх соседних ячеек. Всё это — кумулятивный процесс: начальные точки могут быть сдвинуты несколько раз, если они находятся рядом с несколькими углами.

Однако после обработки всего смещения начальные точки немного рандомизируются (около 10% от ширины тайла в любом направлении), а окончательное смещение ограничено 40% ширины тайла.

На этом этапе уровень уже выглядит отлично. Но есть ещё несколько действий, которые нужно сделать.

В целом форма окружения выглядит хорошо, но края всё ещё очень прямые и немного беспорядочные. Чтобы исправить это, достаточно наложить curved-ассеты по краям каждого типа поверхности. Однако реальная хитрость заключается в том, что одна кривая часто накрывает оба края и использует их углы для определения собственного направления.

Далее применяются 3D-ассеты, чтобы добавить скалам дополнительную текстуру.

И, наконец, другие ассеты заполняют локацию. Их размещение определяется информацией об уровне, которая была сгенерирована ранее. Для размещения ассетов используется единственное правило — меньшие ассеты располагаются вокруг более крупных, создавая естественные и приятные переходы.

В игре применяются и другие способы смещения точек. Например, рядом с искусственными сооружениями важно добиться того, чтобы края были более прямыми.

Разработчики могут легко достичь этого эффекта — достаточно просто ввести другое правило смещения, которое гарантирует, что тайлы с искусственными конструкциями не смещаются. Генератор использует меньшие квадраты, чтобы пометить эти тайлы, поэтому с ними ничего не происходит.

{ "author_name": "Владимир Семыкин", "author_type": "editor", "tags": ["\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f","\u0430\u0440\u0442"], "comments": 3, "likes": 71, "favorites": 155, "is_advertisement": false, "subsite_label": "gamedev", "id": 62639, "is_wide": false, "is_ugc": false, "date": "Tue, 13 Aug 2019 13:01:06 +0300", "is_special": false }
0
{ "id": 62639, "author_id": 94357, "diff_limit": 1000, "urls": {"diff":"\/comments\/62639\/get","add":"\/comments\/62639\/add","edit":"\/comments\/edit","remove":"\/admin\/comments\/remove","pin":"\/admin\/comments\/pin","get4edit":"\/comments\/get4edit","complain":"\/comments\/complain","load_more":"\/comments\/loading\/62639"}, "attach_limit": 2, "max_comment_text_length": 5000, "subsite_id": 64954, "last_count_and_date": null }
3 комментария
Популярные
По порядку
4

Выглядит круто, но - справедливости ради - вот такие моменты довольно неестественны

Ответить
0

Нужно добавить ещё один слой обработки

Ответить
1

У вас два абзаца оригинала (про Вороного и про размещение точек по ясейкам) слиты в один. Из-за этого вышел ляп, когда читается, что регулярная сетка получится, если расставить точки по центру ячеек Вороного, тогда как речь идет о ячейках регулярной сетки.

Ответить

Прямой эфир

[ { "id": 1, "label": "100%×150_Branding_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox_method": "createAdaptive", "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "ezfl" } } }, { "id": 2, "label": "1200х400", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "ezfn" } } }, { "id": 3, "label": "240х200 _ТГБ_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fizc" } } }, { "id": 4, "label": "Article Branding", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "cfovz", "p2": "glug" } } }, { "id": 5, "label": "300x500_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "ezfk" } } }, { "id": 6, "label": "1180х250_Interpool_баннер над комментариями_Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "clmf", "p2": "ffyh" } } }, { "id": 7, "label": "Article Footer 100%_desktop_mobile", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fjxb" } } }, { "id": 8, "label": "Fullscreen Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fjoh" } } }, { "id": 9, "label": "Fullscreen Mobile", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fjog" } } }, { "id": 10, "disable": true, "label": "Native Partner Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyb" } } }, { "id": 11, "disable": true, "label": "Native Partner Mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyc" } } }, { "id": 12, "label": "Кнопка в шапке", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fdhx" } } }, { "id": 13, "label": "DM InPage Video PartnerCode", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox_method": "createAdaptive", "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "clmf", "p2": "flvn" } } }, { "id": 14, "label": "Yandex context video banner", "provider": "yandex", "yandex": { "block_id": "VI-250597-0", "render_to": "inpage_VI-250597-0-1134314964", "adfox_url": "//ads.adfox.ru/228129/getCode?pp=h&ps=clmf&p2=fpjw&puid1=&puid2=&puid3=&puid4=&puid8=&puid9=&puid10=&puid21=&puid22=&puid31=&puid32=&puid33=&fmt=1&dl={REFERER}&pr=" } }, { "id": 15, "label": "Баннер в ленте на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byudo", "p2": "ftjf" } } }, { "id": 17, "label": "Stratum Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fzvb" } } }, { "id": 18, "label": "Stratum Mobile", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fzvc" } } } ]