Как создать реалистичную реку, не зная заранее всю карту?

вступление

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

Краткая информация о карте

В моей игре, когда игрок перемещается к краю текущей сгенерированной карты, на сервер загружаются новые фрагменты (маленький квадратный фрагмент карты). Если для запрошенного местоположения фрагменты не найдены, они генерируются с использованием того же начального числа, которое используется в других частях карты. В настоящее время нет ограничений по размеру карты или общему количеству сгенерированных чанков. Я использую шум Перлина для создания карты. Я рассматриваю ее как карту высот, где каждое поле имеет диапазон значений, которые оно занимает, например, мелководье начинается с -0.12инклюзивного и заканчивается 0эксклюзивным.

Я уже читал о том, как сделать реку реалистичной:

Вопрос

Как добавить реки на карту, если я не знаю, как выглядят все карты? Если я не знаю, где находятся горы, я не могу найти источник реки. И если у меня уже сгенерирована какая-то часть карты, я не могу просто добавить реку чуть позже, когда игрок сталкивается с горной цепью.

Сходства

Похожий сценарий (думаю) есть и в Майнкрафте. Там тоже карта генерируется по мере того, как игрок движется, используя семя, и есть реки, которые продолжают циркулировать, пока карта генерируется. К сожалению, я не знаю используемой там техники.

Скрины из игры

введите описание изображения здесь

введите описание изображения здесь

Загрузка чанков временно отключена, чтобы показать границы:

введите описание изображения здесь

учитывают ли новые фрагменты уже сгенерированные смежные фрагменты?
Просто проверка: если вы используете шум для создания ландшафта, тогда будут локальные минимумы. Вода будет собираться в этих минимумах, если они минимальны во всех направлениях. Вода также будет переливаться через нижнюю кромку таких минимумов. Это справедливое представление о том, как вы это делаете? Вы различаете пористую и непористую почву или между камнем и легко разрушаемой почвой?
@willk В настоящее время нет, но я мог бы сделать их доступными в процессе генерации. Хотя я немного беспокоюсь о возможных проблемах с производительностью. Когда игрок перемещается, загружается/генерируется более одного фрагмента.
Хорошо, но когда вы говорите кусок, каково разрешение внутри куска. Предположительно, между кусками должна быть некоторая градация, или вдоль линий между ними будут внезапные обрывы или обрывы. Я думаю, нам нужно больше ясности в вашем алгоритме, чтобы знать, как ответить. Это изображение из вашего алгоритма?
PS Это кусок всего изображения или это один прямоугольник внутри изображения? Можете ли вы увеличить масштаб до прямоугольников для более мелких деталей?
@chasly-reinstateMonica Да, я мог бы создать локальные озера или пруды, но я не понимаю, как потом создать из них реку. Я не делаю различий между пористым и непористым грунтом, а также между камнем и легко разрушаемой почвой. На данный момент я предполагаю, что вода может течь по любому типу почвы. Размер чанка настраивается, сейчас он установлен на 15x15 полей. Одно поле представляет собой квадрат размером 20x20 пикселей, видимый на изображении, включенном в вопрос, и да, это из моего алгоритма. Здесь нет обрывов или градаций, использование одного и того же семени делает все это хорошо последовательным. Рассматриваемое изображение загрузило около 3300 полей с 15 фрагментами.
Хорошо. Я думаю, что вижу проблему. Вы предполагаете, что уровень воды везде одинаков. Это неверно на реальной местности, если только она не является полностью пористой. С непористыми породами у вас будут бассейны, изолированные высоко в горах. Их уровень будет намного выше уровня моря. Что вам нужно найти, так это выходы из этих высших бассейнов. Они приведут к более низким водоемам и так далее вплоть до уровня моря. Это то, что дает реки. Я на правильном пути?
В продолжение @chasly сказал, что вы можете создать другую (возможно, меньшую - меньше вычислений) карту шума перлина, относящуюся к уровню воды. Затем ваш высокоуровневый генератор местности будет ссылаться на эту карту уровня воды, чтобы рассчитать соответствующий закрытый/эксклюзивный регион.
В прошлый раз, когда я пытался сгенерировать мир, я использовал метод наложения «полей» шума перлина. Как, скажем, горные/равнинные/кавернозные поля, значения которых при соблюдении некоторых условий определяли бы форму целого. У полей было свое собственное поведение, и все они взаимодействовали между собой. Горным полям будет предложено следовать по тропам, которые номинально являются прямыми или слегка извилистыми. Горные поля также имеют тенденцию управлять значениями более низких полей. Вы бы не хотели, чтобы долины образовывались там, где были горы, поэтому горные поля магнетически отталкивали и подавляли их.
Я думаю, что Minecraft теперь генерирует карту с низкой детализацией в огромных разделах. Таким образом, он может решить, что «где-то через эту область 128x128 есть река», и когда он фактически сгенерирует эту область, он решит, где именно разместить реку. Кроме того, реки Minecraft на самом деле не реки, они плоские и могут даже ходить кругами.
Если ваш мир 2D, вы почти наверняка можете позволить себе генерировать огромную сумму заранее, например, Dwarf Fortress.
Этот вопрос не имеет ничего общего с «построением мира», это часто встречающийся вопрос в игровой инженерии. Просто задайте этот вопрос на отличном сайте разработчиков игр. (Или просто погуглите сотни дискуссий об этом.)

Ответы (4)

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

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

ЛОД и физика:

Вы можете суб- и супер-сэмплировать перлиновый шум для создания карт с несколькими разрешениями. Если ваши тайлы составляют 1 тайл на 1 метр, вы можете создать всю карту на более управляемом уровне, скажем, 1 тайл на 1 км, рассчитать реалистичные точки родника и бурный путь реки, а затем разделить, например, 1 тайл на 100 м - на этом уровне вы знаете, где река течет с точностью до 10 тайлов, определите, где река течет по этому пути, а затем рекурсивно, где река течет через эти меньшие тайлы, и т. д., пока вы не достигнете полного уровня детализации.

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

LOD и 1D перлин

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

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

Притворяться

Есть 2 стиля рек. Один идет «в гору», другой идет «в горку». Создайте плитки, чтобы показать реку, вытекающую из источника и превращающуюся в полноценную реку, и одну, показывающую, как полная река впадает в небольшой подземный объект.

Если значение шума перлина для прибрежной зоны является очень точным значением, то оно порождает реку «в гору». Это перемещается к самой высокой краевой точке плитки, которая не граничит с исследуемой плиткой, которая затем, когда загружается следующая плитка, переходит к следующей высшей точке. Если он обнаружит, что достиг локального максимума (более высокой точки нет) или все соседние тайлы уже исследованы, вернитесь примерно к середине, поместите тайл, на котором изображена река, выходящая из пещеры, родник или что-то еще под землей, так что пользователь не видит реку, начинающуюся с вершины небольшого холма.

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

Обычно этого достаточно для 2D-игры, основанной на тайлах.

2 (или более) перлиновых канала

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

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

Если вы запустите его дважды - я бы предложил влажность и высоту. Если вы запустите его 3 раза, я бы предложил размер элемента (песок / камень, лед / снег или пустырь -> луга -> кусты -> деревья), влажность (пустыня -> плодородная -> река -> болото) и высота над уровнем моря (вода -> равнины -> холмы -> горы). 4 раза, возможно, будет включать и температуру.

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

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

Как добавить реки на карту, если я не знаю, как выглядят все карты? Если я не знаю, где находятся горы, я не могу найти источник реки. И если у меня уже сгенерирована какая-то часть карты, я не могу просто добавить реку чуть позже, когда игрок сталкивается с горной цепью.

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

  1. Невидимо расширяйте ландшафт вокруг минимума, пока не найдете периметр этого минимума в еще не исследованном фрагменте. Вам не нужно заполнять весь новый кусок, потому что к тому времени вы уже знаете, куда будет стекать пул. Это будет либо назад в текущий фрагмент, либо куда-то, пока еще незавершенный, в еще не исследованном фрагменте. Другими словами, вы должны выйти за пределы того, что видно/было исследовано. Вы можете назвать это программированием на всякий случай .

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

Обратите внимание, что использование локальных минимумов таким образом (при условии непроницаемой местности) позволит сделать зерно настолько мелким, насколько вы пожелаете. Это может даже позволить вам показать родники и другие небольшие источники реки.

Несколько лет назад я написал алгоритм для ролевой игры, который работал аналогичным образом.
Думай в "Сапере". Когда вы обнаружите горный квадрат, есть вероятность, что там будет вода. Но этот квадрат влияет на вероятность того, что кусок рядом с ним будет горой. Которые влияют на внешний вид воды. Для каждой карты вы можете установить источники воды. Карта запускается из диапазона 0-100 выбирается номер. Это количество источников воды. Чем больше на карте не затенено, тем выше вероятность того, что появится вода.

Теперь, чтобы помочь вам, природа пришла с этой отличной вещью, что ручейки появляются, а затем просачиваются в трещину и исчезают. Сегодня, с помощью современных технологий, мы можем проследить, откуда он возвращается, но на этапе «открытия» один источник может отображаться как 3 или 4 разных ручья. ТАК, что они не должны быть одной непрерывной линией от обнаруженного источника до «куда-то». Это может закончиться после 4 или 5 чанков.

Таким образом, вы можете просто закончить сгенерированные водой куски, когда игрок встретит уже обнаруженный «сухой» кусок.
ИЛИ

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

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

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

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

Предполагая, что ваш алгоритм иногда генерирует горы, если горы/долины создаются в пределах n единиц от «конца» реки и под любым углом меньше, чем +/-45 градусов касательной к реке, то сгенерируйте речной путь из этого указать на горную долину и поместить там ледник.

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

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

Возможно, вам даже удастся позволить ему соединиться с несколькими горами/долинами, если есть несколько потенциальных мест, и это даст вам притоки, впадающие в главную реку, ведущую к морю.

Это, конечно, основано на схеме генерации карты, состоящей из двух частей, где генерируются большинство объектов карты, а реки «рисуются» поверх них. Например, это сработает для Minecraft, который, как мне кажется, так и делает. Если бы ваша игра была более сложной и использовала высоту для определения путей рек, это было бы нежизнеспособно.