Как я могу генерировать случайные озера и реки в моей игре?

19

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

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

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

Карта является двумерной мозаичной картой. Вот несколько примеров неслучайности другого алгоритма. Следующий код был выведен 3 раза подряд. Я рандомизировал октаву и частоту примерно так:freq = 16.0 * random.randint(1, 500000) * 0.000001 + 0.5

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1
1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1
1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1
1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1
1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1
1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1

Это код, который произвел вывод выше:

"""Writes a 256x256 grayscale simplex noise texture file in pgm format
(see http://netpbm.sourceforge.net/doc/pgm.html)
"""
# $Id: 2dtexture.py 21 2008-05-21 07:52:29Z casey.duncan $

import sys
from noise import pnoise2
import random
octaves = random.randint(1, 500000) * 0.000001 + 0.5
freq = 16.0 * octaves
for y in range(30):
    for x in range(40):
        n = int(pnoise2(x/freq, y / freq, 1)*10+3)
        if n>=1:
            n=1
        else:
            n=0
        print n,
    print
юлианский
источник
Больше информации, пожалуйста. На этот вопрос нельзя ответить в его текущем состоянии.
Густаво Масиэль
Я добавил немного больше, но, что вам нужно знать.
Джулиан
Вы добавили хорошую информацию, но нам нужно немного больше. Что такое "не очень случайно"? Любой снимок экрана для нас, чтобы увидеть, каков был данный результат, и каков желаемый результат? Как ты это попробовал? Любой код для вас, чтобы показать нам? Каков твой контекст? 2D или 3D? Плиточный или многоугольный? Извините, если все это слишком много, но я только пытаюсь помочь. -1 не мое, если вы не предоставите информацию, вопрос станет непригодным для сайта, и они закроют его. Итак, еще раз, я пытаюсь помочь.
Густаво Масиэль
2
+1, теперь это хороший вопрос :) Я плохо разбираюсь в перлин-шуме и всей процедурной генерации, но вы засеваете случайный объект? Если я не ошибаюсь, random.seed()так что системное время будет использоваться в качестве начального числа. И вместо этого octaves = random.randint(1,500000)*.000001+.5вы можете попробовать: octaves = random.random() (у него тот же результат, вы получите число от 0 до 1, но его гораздо больше возможностей, чем просто 500000 чисел.)
Густаво Масиэль
Спасибо +1 :) :) Пытался добавить 1 комментарий, но я не могу
Julian

Ответы:

7

Ну, кажется, вы не заполняете генератор случайных чисел. В python это легко сделать с помощью random.seed () .

И я также вижу, что вы генерируете число от 1 до 500000 и делаете его между 0 и 1. Это функциональный метод, но он ограничен до 500000 возможностей. Вы лучше, просто используя random.random()его уже генерирует число от 0 до 1, но с гораздо большими возможностями! Если вам все еще нужно число от 0,5 до 1,0, как предполагает ваш код, вы можете просто сделать:(random.random() * 0.5) + 0.5

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

import sys
from noise import pnoise2
import random
random.seed()
octaves = random.random()
# octaves = (random.random() * 0.5) + 0.5
freq = 16.0 * octaves
for y in range(30):
    for x in range(40):
        n = int(pnoise2(x/freq, y / freq, 1)*10+3)
        if n>=1:
            n=1
        else:
            n=0
        print n,
    print

Это все!

Густаво Масиэль
источник
Мне не ясно, как посев имеет какое-либо отношение к этому. Случайные числа все равно будут случайными, если вы не начнете, но будут повторяться. Единственный признак отказа в посеве - это одна и та же случайная последовательность при каждом запуске программы (при условии, что каждый раз используется одно и то же семя).
Тим Холт
1
Если вы получаете один и тот же результат три раза подряд, как упоминалось в вашем вопросе, это очень вероятно, потому что вы не сеяли генератор случайных чисел. Посмотрите это и посмотрите, решит ли это проблему.
ashes999
Ах, я не видел бит «3 раза подряд» - читал: «Есть ли в этой библиотеке какая-то начальная функция, которую я пропускаю, чтобы сделать ее более случайной». Да, посев для неповторяющейся случайности :)
Тим Холт
8

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

Если вы хотите получить отличный пример создания озер и рек, которые имеют смысл, вы можете проверить это сообщение в блоге -> http://simblob.blogspot.com/2010/09/polygon-map-generation-part-1.html Это хороший ориентир для такого рода вещей, если ваша цель - реалистичная гидрография.

Тим Холт
источник
2

Это очень просто: если вы получаете одну и ту же карту три раза подряд (или больше), это потому, что вы не рандомизировали начальное число.

Что это значит?

Компьютеры по своей природе являются детерминированными (неслучайными), поэтому они симулируют случайность. На самом деле это случайное повторение (поэтому мы называем это «генератором псевдослучайных чисел»).

Как это работает?

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

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

Как Гусатаво упомянул в своем ответе, вам нужно вызвать random.seed () . В документе указано, что «если X [параметр по умолчанию] опущен или Noneиспользуется текущее системное время». Этого должно быть достаточно.

ashes999
источник