Jak mogę generować losowe jeziora i rzeki w mojej grze?

19

Mam grę polegającą na budowaniu bloków 2D i próbuję tworzyć losowo generowane jeziora i rzeki. Przyjrzałem się algorytmowi szumu Perlina, ale nie udało mi się uzyskać losowych i dobrych wyników.

Próbowałem użyć biblioteki szumów Pythona , ale nie tworzyłem map losowo.

Czy jest jakaś funkcja nasion, której brakuje w tej bibliotece, aby uczynić ją bardziej losową? Jaką zmienną mam zmienić, jeśli chcę, aby była bardziej losowa? Jeśli to możliwe, daj mi mniej techniczną odpowiedź, mniej matematyki i więcej terminów python.

Mapa jest kafelkową mapą 2D. Oto kilka przykładów nielosowości drugiego algorytmu. Poniższy kod został wyprowadzony 3 razy z rzędu. Randomizowałem oktawy i częstotliwość za pomocą czegoś takiego: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

To jest kod, który wytworzył wynik powyżej:

"""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
juliański
źródło
Proszę o więcej informacji. Na to pytanie nie można odpowiedzieć w obecnym stanie.
Gustavo Maciel
Dodałem trochę więcej, ale co musisz wiedzieć.
Julian
Dodałeś dobre informacje, ale potrzebujemy trochę więcej. Co to jest „niezbyt losowo”? Każdy zrzut ekranu, aby zobaczyć, jaki jest podany wynik i jaki jest pożądany wynik? Jak tego próbowałeś? Jakiś kod, który możesz nam pokazać? Jaki jest twój kontekst? 2D czy 3D? Kafelkowy czy wielokątny? Przepraszam, jeśli to wszystko za dużo, ale staram się tylko pomóc. -1 nie było moje, jeśli nie podasz informacji, pytanie stanie się nieodpowiednie dla strony i zamkną ją. Więc znowu próbuję pomóc.
Gustavo Maciel
2
+1, teraz jest dobre pytanie :) Nie jestem dobry z hałasem Perlina i generowaniem procedur, ale czy obsiewacie losowy obiekt? Jeśli się nie mylę, jego random.seed()czas systemowy zostanie wykorzystany jako ziarno. I zamiast tego octaves = random.randint(1,500000)*.000001+.5możesz spróbować: octaves = random.random() (ma ten sam wynik, otrzymasz liczbę od 0 do 1, ale ma znacznie więcej możliwości niż tylko 500000 liczb.)
Gustavo Maciel
Dzięki +1 :) :) Próbowałem dodać 1 komentarz, ale nie mogę
Julian

Odpowiedzi:

7

Cóż, jak się wydaje, nie obsadzasz generatora liczb losowych. W Pythonie można to łatwo zrobić za pomocą random.seed () .

Widzę też, że generujesz liczbę od 1 do 500000 i ustawiasz ją między 0 a 1. Jest to metoda funkcjonalna, ale jest ograniczona do zaledwie 500000 możliwości. Lepiej jest, gdy tylko random.random()go użyjesz , już generuje liczbę od 0 do 1, ale z dużo większą ilością możliwości! Jeśli nadal potrzebujesz liczby od 0,5 do 1,0, jak sugeruje Twój kod, możesz po prostu:(random.random() * 0.5) + 0.5

Twój końcowy kod powinien wyglądać następująco:

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

To wszystko!

Gustavo Maciel
źródło
Nie jestem pewien, czy siew ma coś z tym wspólnego. Liczby losowe nadal będą losowe, jeśli nie zaczniesz, ale będą się powtarzać. Jedynym objawem braku wysiewu powinna być ta sama losowa sekwencja przy każdym uruchomieniu programu (zakładając, że za każdym razem używane jest to samo ziarno).
Tim Holt
1
Jeśli otrzymujesz tę samą moc trzy razy z rzędu, jak wspomniano w pytaniu, jest to bardzo prawdopodobne, ponieważ nie uruchomiłeś generatora losowego. Zaszczep go i sprawdź, czy to rozwiąże problem.
prochy999
Ach, nie widziałem bitu „3 razy z rzędu” - czytałem: „Czy jest jakaś funkcja nasion, której mi brakuje w tej bibliotece, aby uczynić ją bardziej losową”. Tak, seedowanie za nie powtarzającą się przypadkowość :)
Tim Holt
8

To nie odpowiada na konkretne pytanie dotyczące programowania, ale weź pod uwagę, że tworzenie jezior i rzek nie polega na przypadkowym umieszczaniu kropel wody i pasków wody między nimi. Chodzi o wysokość terenu - o zagłębienia (baseny), które zamieniają się w jeziora i wodę, która przepływa z miejsc wyższych do niższych.

Jeśli chcesz świetny przykład tworzenia jezior i rzek, które mają sens, możesz sprawdzić ten post na blogu -> http://simblob.blogspot.com/2010/09/polygon-map-generation-part-1.html To dobre odniesienie do tego rodzaju rzeczy, jeśli twoim celem jest stosunkowo realistyczna hydrografia.

Tim Holt
źródło
2

To bardzo proste: jeśli otrzymujesz tę samą mapę trzy razy z rzędu (lub więcej), dzieje się tak dlatego, że nie losowałeś nasion.

Co to znaczy?

Komputery są z natury deterministyczne (nieprzypadkowe), więc symulują losowość. W rzeczywistości jest powtarzalnie losowy (dlatego nazywamy go „generatorem liczb pseudolosowych”).

Jak to działa?

Kiedy tworzysz liczbę losową, masz możliwość nadania jej „ziarna”. Ważne jest to, że jeśli zawsze używasz tego samego ziarna, zawsze otrzymasz tę samą sekwencję liczb losowych, w tej samej kolejności. Zawsze. To może być dobre albo złe.

W twoim przypadku wygląda na to, że nie uruchamiasz generatora losowego i domyślnie otrzymujesz to samo ziarno - prawdopodobnie używa jakiegoś składnika twojej daty / godziny. Dlatego zalecam losowanie.

Jak Gusatavo wspomniał w swojej odpowiedzi, musisz wywołać random.seed () . Dokumenty stwierdzają, że „jeśli X [parametr domyślny] zostanie pominięty lub Noneużyty zostanie bieżący czas systemowy.” To powinno wystarczyć.

ashes999
źródło