В декабрьских новостях о Ураган Флоренция часто упоминались Внешние банки - ряд барьерных островов на побережье Северной Каролины:
Барьерные острова — это плоские или глыбистые участки песка, образованные волнами и прибоем параллельно материковому побережью.
Зачастую они имеют вид длинных цепей, которые могут простираться на многие десятки миль.
Барьерные острова обычно разделены небольшими приливными каналами и могут образовывать лагуны между островами и материком.
В соответствии с Википедия Барьерные острова могут занимать до 15% береговой линии, поэтому вы ожидаете увидеть их на большинстве фэнтезийных карт, но на самом деле они довольно редки.
А из-за природы шума они почти никогда не встречаются на процедурно сгенерированных картах, использующих шум для создания ландшафта.
Чтобы понять, почему это так, давайте взглянем на ванильную карту острова:
По сути, это круг, искаженный небольшим количеством низкочастотного шума, добавленного для разрушения круглой формы.
Давайте теперь попробуем использовать шум, чтобы разбить берег и сформировать прибрежные острова.
Вот тот же остров с добавленным низкочастотным шумом:
Он имеет заливы и мысы.
Элементы ландшафта довольно большие, потому что я использовал низкочастотный шум, который медленно меняется.
Однако шум недостаточно силен, чтобы создавать острова.
Давайте сделаем это немного сильнее:
Теперь мы создали несколько островов, но по сути это круглые пятна, которые не обязательно тянутся вдоль побережья.
Можно добавить высокочастотный шум:
Это может дать нам очень неровные береговые линии и небольшие острова вдоль побережья, но ничего похожего на барьерный остров.
Единственная причина этого заключается в том, что шум не является согласованным по координатам x и y, поэтому, хотя в целом шум не является случайным, формы, которые он создает, следующие:
Для некоторых вещей это хорошо, но для создания конкретной формы, например острова вдоль побережья, не подходит.
Как и в других случаях, когда мне нужно было создать определенную форму или область, мне нужно было создать маску нужной формы, а затем использовать шум внутри маски.
(Вы также можете использовать шум, чтобы исказить маску, придав ей более естественную форму.
) Барьерные острова — это, по сути, длинные и тонкие области, смещенные от побережья.
Итак, давайте создадим маску такой формы.
Начнем с определения части побережья, на которой будет расположен барьерный остров.
Это можно сделать, выбрав случайную точку на побережье и вторую точку ниже, которые отмечены на рисунке красной линией в правом верхнем углу:
Чтобы начать создавать барьерный остров, я могу просто провести прямую линию между этими двумя точками и спроецировать ее немного наружу, в воду.
Это даст мне очень прямой и неестественно выглядящий остров, но я могу исказить его форму, чтобы скрыть это.
Настоящая проблема в том, что остров не следует за береговой линией.
Вероятно, это будет хорошо смотреться на большинстве прямых участков береговой линии, но будет выглядеть странно на извилистых береговых линиях.
Лучше повторить береговую линию и сделать ее основой формы острова.
Для этого мне нужно создать копию береговой линии, а затем спроецировать ее в океан перпендикулярно береговой линии.
У меня уже есть процедура расчета перпендикуляров (нормалей) к полилиниям с момента реализации.
рукописные линии , а мои береговые линии всегда идут в одном направлении, так что это довольно просто:
Или Кажется простой.
Давайте посмотрим, что произойдет, если я спроецирую береговую линию немного дальше наружу (чтобы создать другую сторону маски острова) на менее гладкой части береговой линии:
Два отрезка проецируемой линии пересекаются друг с другом и создают на многоугольнике устрашающую «восьмерку».
Это так называемый задача о параллельной кривой .
Мы не можем просто отодвинуть банку на некоторое расстояние, нам также нужно решить проблемы, вызванные острыми внутренними и внешними углами.
Я искал код Javascript для решения этой проблемы, но нашел единственный пример ( отсюда ) потрясающе падал даже на довольно простых сэмплах.
Поэтому я написал свой собственный.
В общем, решение состоит в том, чтобы сместить каждую точку по нормали, а затем проверить, создает ли новая точка сегмент линии, пересекающий любую из существующих линий.
Если да, то обрезаем петлю и вставляем новый отрезок, состоящий из точки пересечения и новой точки.
В тестовых случаях, которые я тестировал, эта система вполне соответствовала моим требованиям.
Итак, теперь я могу создавать простые маски (без циклов) для островов:
Он слишком однородный, поэтому исказлю контуры:
В некоторых местах контуры могут касаться берега, но это нормально и часто встречается на барьерных островах.
Следующий шаг — заполнить контур сушей, но прежде чем я это сделаю, я хочу сделать острова длиннее и добавить некоторую логику, чтобы избежать перекрытия островов в случае, если на одной береговой линии есть несколько барьерных островов.
Теперь попробуем добавить сушу.
Для этого я подниму высоту любого участка суши (который представляет собой треугольники Делоне) над уровнем моря:
Здесь стоит отметить несколько аспектов.
Во-первых, в левом верхнем углу есть довольно удачный барьерный остров.
Однако остров, похоже, плохо заполняет полигон.
Многие сухопутные треугольники «включены» из-за наличия их центров внутри многоугольника.
Это добавляет случайности форме острова.
Во-вторых, можно заметить, что два других острова находились настолько близко к берегу, что просто слились с ним.
Поскольку я хочу создать здесь острова, я не хочу, чтобы это происходило слишком часто, поэтому я настрою генерацию так, чтобы между береговой линией и островом было больше водного зазора.
(Я добавлю проверку позже, чтобы этого не произошло.
)
Одна из приятных особенностей неправильных треугольников, из которых состоит суша, заключается в том, что они естественным образом создают приливные каналы, типичные для барьерных островов.
Плохо то, что они обычно создают островные пятна, похожие на искаженные жемчужины на нитке.
Они мало похожи на барьерные острова, а если взять много отдельных треугольников, то они выглядят очень неестественно.
Если я увеличу ширину островов, оба эффекта исчезнут, и в итоге я получу более естественные острова, но без приливных каналов:
Но мне хотелось бы научиться создавать очень узкие острова.
Другой подход — (значительно) увеличить количество локаций в мире для повышения разрешения:
Это может дать нам впечатляюще тонкие и детализированные острова, но значительно увеличивает время и память, необходимые для создания карты.
При использовании обоих этих методов существует большая вероятность того, что некоторые части острова будут очень неровными:
Это происходит потому, что контур пересекает две стороны (а иногда и все три стороны) лежащих в основе треугольников Делоне.
Это неотъемлемая проблема использования триангуляции Делоне при создании карт, но по какой-то причине она редко обсуждается! Это случается не очень часто на береговых линиях в моей игре, потому что я намеренно добавил этап сглаживания, чтобы уменьшить вероятность этого, но этот этап имеет тенденцию разрушать узкие острова.
Потенциальное решение — создать немного более широкие острова и использовать сглаживание — при правильной настройке это может привести к созданию более тонких островов без большого количества треугольных артефактов:
Однако при таком подходе по-прежнему существуют пределы того, насколько узкими могут быть острова.
Это также означает, что мы никогда не получим по-настоящему фрактальных береговых линий.
Иногда алгоритм сглаживания приводит к разделению длинного барьерного острова на несколько более мелких (как в левом нижнем углу изображения выше), но было бы неплохо иметь возможность принудительно это сделать:
Остается только дать островам названия и нанести их на карту.
Единственная тонкость здесь в том, что я не хочу называть все острова в цепочке барьерных островов.
В реальных цепочках барьерных островов отдельные острова часто имеют названия, что приводит к хаосу на карте:
Поэтому при создании барьерного острова я учитываю всю дугу и присваиваю ей одно имя, даже если результирующая генерация разбивает дугу на несколько островов:
Обычно барьерные острова называют «Берегами» или «Барами», поэтому эти слова встречаются в вариантах названий.
Этот пример показывает потенциальную проблему с барьерными островами:
Здесь внутри залива был создан барьерный остров.
Это нелогично (а также приводит к дублированию названий).
Чтобы избежать этого, я могу использовать свой логика распознавания отсеков , и пропустите эти участки береговой линии.
Этот метод, вероятно, не является надежным, но он хорошо работает для этой карты:
Теги: #Разработка игр #Игровой дизайн #Работа с векторной графикой #острова #географические карты #процедурная генерация карт #процедурная генерация #процедурная генерация
-
Ios. Методы Программирования
19 Oct, 24 -
Geek Picnic — Пленэр Для Айтишников
19 Oct, 24 -
Классификация Ит-Пользователей По Версии Pew
19 Oct, 24 -
Несколько Слов Об Icq
19 Oct, 24 -
Ответы На Хабр Из Сколково
19 Oct, 24