Генерация Барьерных Островов

В декабрьских новостях о Ураган Флоренция часто упоминались Внешние банки - ряд барьерных островов на побережье Северной Каролины:

Генерация барьерных островов

Барьерные острова — это плоские или глыбистые участки песка, образованные волнами и прибоем параллельно материковому побережью.

Зачастую они имеют вид длинных цепей, которые могут простираться на многие десятки миль.

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

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

А из-за природы шума они почти никогда не встречаются на процедурно сгенерированных картах, использующих шум для создания ландшафта.

Чтобы понять, почему это так, давайте взглянем на ванильную карту острова:

Генерация барьерных островов

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

Давайте теперь попробуем использовать шум, чтобы разбить берег и сформировать прибрежные острова.

Вот тот же остров с добавленным низкочастотным шумом:

Генерация барьерных островов

Он имеет заливы и мысы.

Элементы ландшафта довольно большие, потому что я использовал низкочастотный шум, который медленно меняется.

Однако шум недостаточно силен, чтобы создавать острова.

Давайте сделаем это немного сильнее:

Генерация барьерных островов

Теперь мы создали несколько островов, но по сути это круглые пятна, которые не обязательно тянутся вдоль побережья.

Можно добавить высокочастотный шум:

Генерация барьерных островов

Это может дать нам очень неровные береговые линии и небольшие острова вдоль побережья, но ничего похожего на барьерный остров.

Единственная причина этого заключается в том, что шум не является согласованным по координатам x и y, поэтому, хотя в целом шум не является случайным, формы, которые он создает, следующие:

Генерация барьерных островов

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

(Вы также можете использовать шум, чтобы исказить маску, придав ей более естественную форму.

) Барьерные острова — это, по сути, длинные и тонкие области, смещенные от побережья.

Итак, давайте создадим маску такой формы.

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

Это можно сделать, выбрав случайную точку на побережье и вторую точку ниже, которые отмечены на рисунке красной линией в правом верхнем углу:

Генерация барьерных островов

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

Это даст мне очень прямой и неестественно выглядящий остров, но я могу исказить его форму, чтобы скрыть это.

Настоящая проблема в том, что остров не следует за береговой линией.

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

Лучше повторить береговую линию и сделать ее основой формы острова.

Для этого мне нужно создать копию береговой линии, а затем спроецировать ее в океан перпендикулярно береговой линии.

У меня уже есть процедура расчета перпендикуляров (нормалей) к полилиниям с момента реализации.

рукописные линии , а мои береговые линии всегда идут в одном направлении, так что это довольно просто:

Генерация барьерных островов

Или Кажется простой.

Давайте посмотрим, что произойдет, если я спроецирую береговую линию немного дальше наружу (чтобы создать другую сторону маски острова) на менее гладкой части береговой линии:

Генерация барьерных островов

Два отрезка проецируемой линии пересекаются друг с другом и создают на многоугольнике устрашающую «восьмерку».

Это так называемый задача о параллельной кривой .

Мы не можем просто отодвинуть банку на некоторое расстояние, нам также нужно решить проблемы, вызванные острыми внутренними и внешними углами.

Я искал код Javascript для решения этой проблемы, но нашел единственный пример ( отсюда ) потрясающе падал даже на довольно простых сэмплах.

Поэтому я написал свой собственный.

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

Если да, то обрезаем петлю и вставляем новый отрезок, состоящий из точки пересечения и новой точки.

В тестовых случаях, которые я тестировал, эта система вполне соответствовала моим требованиям.

Итак, теперь я могу создавать простые маски (без циклов) для островов:

Генерация барьерных островов

Он слишком однородный, поэтому исказлю контуры:

Генерация барьерных островов

В некоторых местах контуры могут касаться берега, но это нормально и часто встречается на барьерных островах.

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



Генерация барьерных островов

Теперь попробуем добавить сушу.

Для этого я подниму высоту любого участка суши (который представляет собой треугольники Делоне) над уровнем моря:

Генерация барьерных островов

Здесь стоит отметить несколько аспектов.

Во-первых, в левом верхнем углу есть довольно удачный барьерный остров.

Однако остров, похоже, плохо заполняет полигон.

Многие сухопутные треугольники «включены» из-за наличия их центров внутри многоугольника.

Это добавляет случайности форме острова.

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

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

(Я добавлю проверку позже, чтобы этого не произошло.

)

Генерация барьерных островов

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

Плохо то, что они обычно создают островные пятна, похожие на искаженные жемчужины на нитке.

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

Если я увеличу ширину островов, оба эффекта исчезнут, и в итоге я получу более естественные острова, но без приливных каналов:

Генерация барьерных островов

Но мне хотелось бы научиться создавать очень узкие острова.

Другой подход — (значительно) увеличить количество локаций в мире для повышения разрешения:

Генерация барьерных островов

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

При использовании обоих этих методов существует большая вероятность того, что некоторые части острова будут очень неровными:

Генерация барьерных островов

Это происходит потому, что контур пересекает две стороны (а иногда и все три стороны) лежащих в основе треугольников Делоне.

Это неотъемлемая проблема использования триангуляции Делоне при создании карт, но по какой-то причине она редко обсуждается! Это случается не очень часто на береговых линиях в моей игре, потому что я намеренно добавил этап сглаживания, чтобы уменьшить вероятность этого, но этот этап имеет тенденцию разрушать узкие острова.

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

Генерация барьерных островов

Однако при таком подходе по-прежнему существуют пределы того, насколько узкими могут быть острова.

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

Иногда алгоритм сглаживания приводит к разделению длинного барьерного острова на несколько более мелких (как в левом нижнем углу изображения выше), но было бы неплохо иметь возможность принудительно это сделать:

Генерация барьерных островов

Остается только дать островам названия и нанести их на карту.

Единственная тонкость здесь в том, что я не хочу называть все острова в цепочке барьерных островов.

В реальных цепочках барьерных островов отдельные острова часто имеют названия, что приводит к хаосу на карте:

Генерация барьерных островов

Поэтому при создании барьерного острова я учитываю всю дугу и присваиваю ей одно имя, даже если результирующая генерация разбивает дугу на несколько островов:

Генерация барьерных островов

Обычно барьерные острова называют «Берегами» или «Барами», поэтому эти слова встречаются в вариантах названий.

Этот пример показывает потенциальную проблему с барьерными островами:

Генерация барьерных островов

Здесь внутри залива был создан барьерный остров.

Это нелогично (а также приводит к дублированию названий).

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

Этот метод, вероятно, не является надежным, но он хорошо работает для этой карты:

Генерация барьерных островов

Теги: #Разработка игр #Игровой дизайн #Работа с векторной графикой #острова #географические карты #процедурная генерация карт #процедурная генерация #процедурная генерация

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.