Comment puis-je générer des lacs et des rivières aléatoires dans mon jeu?

19

J'ai un jeu de construction de blocs 2D et j'essaie de créer des lacs et des rivières générés de manière aléatoire. J'ai étudié l'algorithme de bruit Perlin, mais je n'ai pas réussi à générer des résultats aléatoires et agréables.

J'ai essayé d'utiliser la bibliothèque de bruit python , mais elle n'a pas créé de cartes de manière très aléatoire.

Y a-t-il une fonction de départ qui me manque dans cette bibliothèque pour la rendre plus aléatoire? Quelle variable dois-je changer si je veux qu'elle soit plus aléatoire? Si possible, donnez-moi une réponse moins technique, avec moins de mathématiques et plus de termes python.

La carte est une carte en mosaïque 2D. Voici quelques exemples du caractère non aléatoire de l'autre algorithme. Le code suivant a été généré 3 fois de suite. Je randomisais les octaves et la fréquence avec quelque chose comme ça: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

C'est le code qui a produit la sortie ci-dessus:

"""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
julien
la source
Plus d'informations, s'il vous plaît. Il est impossible de répondre à cette question dans son état actuel.
Gustavo Maciel
J'en ai ajouté un peu plus, mais, que devez-vous savoir.
Julian
Vous avez ajouté de bonnes informations, mais nous en avons besoin d'un peu plus. Qu'est-ce que «pas très aléatoire»? Une capture d'écran pour nous voir quel est le résultat donné et quel est le résultat souhaité? Comment l'as-tu essayé? Avez-vous un code à nous montrer? Quel est ton contexte? 2D ou 3D? Tuilé ou polygonal? Désolé si tout cela est trop, mais j'essaie seulement d'aider. Le -1 n'était pas le mien, si vous ne donnez pas d'informations, la question deviendra impropre au site et ils le fermeront. Encore une fois, j'essaie d'aider.
Gustavo Maciel
2
+1, maintenant c'est une bonne question :) Je ne suis pas bon avec le bruit perlin et toute la génération procédurale, mais, semez-vous l'objet aléatoire? Si je ne me trompe pas, c'est random.seed()donc l'heure système qui sera utilisée comme graine. Et au lieu de octaves = random.randint(1,500000)*.000001+.5vous pouvez essayer: octaves = random.random() (il a le même résultat, vous obtiendrez un nombre compris entre 0 et 1, mais c'est beaucoup plus de possibilités que seulement 500000 nombres.)
Gustavo Maciel
Merci +1 :) :) J'ai essayé d'ajouter 1 commentaire mais je ne peux pas
Julian

Réponses:

7

Eh bien, comme il semble, vous n'amorcez pas le générateur de nombres aléatoires. En python, cela peut être fait facilement avec juste un random.seed () .

Et je peux aussi voir que vous générez un nombre compris entre 1 et 500 000 et que vous le faites entre 0 et 1. C'est une méthode fonctionnelle, mais elle est limitée à seulement 500 000 possibilités. Vous êtes mieux avec simplement l'utiliser random.random()génère déjà un nombre compris entre 0 et 1, mais avec beaucoup plus de possibilités! Si vous avez toujours besoin d'un nombre compris entre 0,5 et 1,0, comme le suggère votre code, vous pouvez simplement faire:(random.random() * 0.5) + 0.5

Votre code final devrait ressembler à ceci:

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

C'est tout!

Gustavo Maciel
la source
Je ne sais pas en quoi l'ensemencement y est pour quelque chose. Les nombres aléatoires seront toujours aléatoires si vous ne semez pas, mais répéteront. Le seul symptôme de non-ensemencement devrait être la même séquence aléatoire à chaque fois que vous exécutez le programme (en supposant que la même graine est utilisée à chaque fois).
Tim Holt
1
Si vous obtenez la même sortie trois fois de suite comme mentionné dans votre question, c'est très probablement parce que vous n'avez pas amorcé le générateur aléatoire. Amorcez-le et voyez s'il résout le problème.
ashes999
Ah, je n'avais pas vu le bit "3 fois de suite" - je lisais: "Y a-t-il une fonction de départ qui me manque dans cette bibliothèque pour la rendre plus aléatoire" Oui ensemencement pour aléatoire non répétitif :)
Tim Holt
8

Cela ne répond pas à votre question de programmation spécifique, mais considérez que la création de lacs et de rivières ne consiste pas à placer au hasard des gouttes d'eau et des bandes d'eau entre elles. Il s'agit de la hauteur du terrain - des dépressions (bassins) qui se transforment en lacs et de l'eau qui coule des endroits les plus élevés aux plus bas.

Si vous voulez un excellent exemple de création de lacs et de rivières qui ont du sens, vous pouvez consulter cet article de blog -> http://simblob.blogspot.com/2010/09/polygon-map-generation-part-1.html It's une bonne référence pour ce genre de chose si votre objectif est une hydrographie raisonnablement réaliste.

Tim Holt
la source
2

C'est très simple: si vous obtenez la même carte trois fois de suite (ou plus), c'est parce que vous n'avez pas randomisé la graine.

Qu'est-ce que ça veut dire?

Les ordinateurs sont intrinsèquement déterministes (non aléatoires), ils simulent donc le caractère aléatoire. C'est en fait répétitivement aléatoire (c'est pourquoi nous l'appelons "générateur de nombres pseudo aléatoires").

Comment cela marche-t-il?

Lorsque vous créez un nombre aléatoire, vous avez la possibilité de lui donner une "graine". L'important est que si vous utilisez toujours la même graine, vous obtiendrez toujours la même séquence de nombres aléatoires, dans le même ordre. Toujours. Cela peut être bon ou mauvais.

Dans votre cas, il semble que vous n'amorçiez pas le générateur aléatoire, et par défaut, vous obtenez la même graine - il utilise probablement un composant de votre date / heure. Par conséquent, je vous recommande de le randomiser.

Comme Gusatavo l'a mentionné dans sa réponse, vous devez appeler random.seed () . Les documents indiquent que "si X [le paramètre par défaut] est omis ou None, l'heure système actuelle est utilisée". Cela devrait être suffisant.

cendres999
la source