Quelle est la méthode la plus simple pour générer un terrain fluide pour un jeu 2d?

23

Quelle est la méthode la plus simple pour générer un terrain fluide pour un jeu 2d comme "Moon Buggy" ou "Route 960"?

J'ai obtenu une réponse sur stackoverflow.com à propos de générer un tableau de hauteurs aléatoires et de les estomper plus tard. Oui, ça va. Mais il serait préférable de donner quelques points et d'obtenir une courbe lisse.

astropanic
la source

Réponses:

13

Une façon de réaliser ceci est la suivante:

  • Créez un point au milieu de l'écran, avec une hauteur aléatoire; vous avez maintenant deux sections, une de chaque côté de ce point
  • Pour chaque section, divisez en deux en plaçant un point au milieu de cette section, avec une hauteur aléatoire (à distance) entre ses deux voisins
  • Répétez n fois.

Ce qui se passe, c'est que les détails du décor s'affinent à chaque itération.

La façon dont vous gérez les cas limites dépend de vous: vous pouvez supposer des points à (0, hauteur / 2) et (largeur, hauteur / 2) par exemple.

J'espère que cela t'aides!

EDIT: Voici une photo que j'ai faite à titre d'illustration:

terraingen

C'est la même idée!

Tim Kelsall
la source
12

En supposant que vous vouliez un terrain réellement lisse, je suggère de prendre du recul par rapport aux réponses basées sur le bruit et de comprendre d'où elles viennent. Un signal de «bruit» est essentiellement une somme d'une infinité de sinusoïdes d'amplitudes aléatoires, l'amplitude «moyenne» à une fréquence donnée étant donnée par une fonction de la fréquence f . Vous pouvez obtenir la plupart des définitions courantes du «bruit» de cette façon. Par exemple, le mouvement brownien a un 1 / f ^ 2réponse en fréquence (c'est-à-dire que l'amplitude moyenne à une fréquence donnée est inversement proportionnelle au carré de la fréquence): cela signifie que les points proches ont une bonne corrélation entre eux, car les composantes haute fréquence du signal sont fortement amorti. En revanche, le bruit fractal classique (déplacement médian, bruit Perlin, etc.) a une réponse en fréquence 1 / f ; il y a plus de variance entre les points proches, mais toujours pas mal de corrélation. Pour aller plus loin, le bruit blanc a une réponse en fréquence constante - il n'y a aucune corrélation entre les points.

À quoi cela sert-il? Eh bien, vous pouvez obtenir un signal lisse qui a toujours un aspect un peu bruyant en additionnant simplement une poignée de sinusoïdes mais en vous assurant qu'elles ont une amplitude appropriée à toutes les fréquences données. Vous voulez que les fréquences soient `` aléatoires '' afin qu'aucune d'entre elles n'ait un multiple commun (sinon vous obtiendrez une composante périodique à la forme globale de vos collines), donc je suggère quelque chose comme la procédure suivante (complète avec exemple de travail):

  1. Choisissez 4 nombres (réels) au hasard dans la plage [1..10] - ce seront les fréquences de vos ondes sinusoïdales. J'ai `` lancé les dés '' sur random.org et j'ai obtenu: f 0 = 1,75, f 1 = 2,96, f 2 = 6,23 et f 3 = 8,07. Le nombre 4 n'a rien de magique (vous pouvez en utiliser plus, mais en utiliser moins va commencer à rendre les ondes sinusoïdales individuelles plus évidentes) ou la plage de 1 à 10 ici (c'est juste un moyen de vous assurer que votre plus haut et votre plus bas les fréquences ne sont pas trop éloignées). Il peut être judicieux de choisir une fréquence dans la plage [1..2] et le reste dans la plage [2..10] juste pour avoir une sinusoïde «dominante» connue.
  2. Pour chacun de ces quatre (ou plusieurs) mais les fréquences f i , pour choisir une amplitude d' un i quelque part dans la plage comprise entre -C / f i et C / f i pour une constante C . La valeur que vous choisissez ici contrôle l'amplitude globale de votre onde - pour plus de commodité, j'ai choisi C = 1. Ensuite, j'avais besoin de nombres aléatoires dans la plage [-1 / 1,75 (= -0,571) .. 1 / 1,75 (= 0,571) ], et de même dans les fourchettes [-0,338 .. 0,338], [-0,161 .. 0,161] et [-0,124 .. 0,124]. En lançant à nouveau les dés quatre fois, j'ai obtenu un 0 = -0,143, un 1 = -0,180, un 2 = -0,012 eta 3 = 0,088. (Notez que ce n'est probablement pas tout à fait la meilleure façon de faire cette étape - puisque la valeur maximale possible de la fonction est la somme des amplitudes abs ( a 0 ) + abs ( a 1 ) + abs ( a 2 ) + abs ( un 3 ), il serait plus logique de diviser chacun de vos quatre a i valeurs par cette somme une fois que vous les avez généré, puis multiplier chacun par C de sorte que vous pouvez être sûr que le maximum précise la fonction peut atteindre est C .)
  3. Choisissez quatre «décalages» o i , chacun dans la plage [0..2π] (0..6.28) - ceux-ci ajusteront les points de départ de vos vagues afin qu'elles ne commencent pas toutes à 0. Je suis o 0 = 1,73, o 1 = 4,98, o 2 = 3,17 et o 3 = 4,63.
  4. 'Tracer' la fonction f (x) = a 0 sin ( f 0 (kx + o 0 ) ) + a 1 sin ( f 0 (kx + o 1 ) ) + a 2 sin ( f 0 (kx + o 0 ) ) + a 3 sin ( f 0 (kx + o 0 ) ) - ici k est une autre constante, celle qui contrôle le «stretch» ​​horizontal de vos fonctions. Vous devrez comprendre ce que c'est pour votre propre application; pour plus de commodité, je viens de choisir k= 1, et donc ma fonction globale est f (x) = -0,143 sin (1,75 ( x + 1,73)) - 0,180 sin (2,96 ( x +4,98)) - 0,012 sin (6,23 ( x +3,17)) + 0,088 sin (8,07 ( x +4,63)).

Voici le résultat de mon exemple, comme tracé dans Wolfram Alpha - notez qu'il fixe la taille de ses graphiques à des fins d'affichage, mais que vous devriez avoir beaucoup de contrôle sur l'étirement horizontal et vertical du résultat via les constantes que j'ai mentionnées ci-dessus :

Sinusoïde aléatoire simple

Steven Stadnicki
la source
10

L' algorithme de déplacement à mi-chemin peut générer un beau terrain 2D.

exemple de terrain

Il y a une différence subtile entre le déplacement à mi-chemin et ce que suggère @tykel. L'algorithme de Tykel subdivise l'horizon et choisit une nouvelle hauteur. Cela crée un terrain où les pics sont uniformément espacés. Les humains sont excellents pour choisir les régularités, donc le terrain généré semble généré, pas naturel.

La puissance du point médian vient de choisir le point médian puis de se déplacer le long de la normale de cette ligne. Cela fait varier les pics de haut en bas ainsi que d'un côté à l'autre. Le terrain résultant est fractal et les humains perçoivent les fractales comme naturelles.

Un déplacement aléatoire de la hauteur peut entraîner une descente du terrain si vous ajoutez quelques paramètres supplémentaires (déplacement horizontal, pente maximale, etc.). Cela met en évidence une autre des forces du MPD; il est très simple à régler. Deux paramètres, bosses et niveau de détail.

deft_code
la source
7

Vous pouvez utiliser des fonctions de bruit pour générer des hauteurs aléatoires. Le plus simple d'entre eux est le bruit de valeur, qui fonctionne exactement comme votre description: vous générez des hauteurs entières aléatoires, puis interpolez les hauteurs entre elles. La méthode d'interpolation la plus utilisée est le mappage de la courbe en S cubique:

Supposons que vous ayez une hauteur h0au point x0et une hauteur h1au point x1. Ensuite, pour obtenir la hauteur en tout point x( x0<=x<=x1), vous utilisez

t = (x-x0)/(x1-x0); // map to [0,1] range
t = t*t*(3 - 2*t); // map to cubic S-shaped curve
h = h0+t*h1;

Les hauteurs ainsi obtenues seront lisses, aléatoires, mais pas vraiment intéressantes. Pour améliorer votre terrain, vous pouvez utiliser le bruit fractal . Cela fonctionne comme ceci: supposons que vous avez généré une fonction h(x)qui renvoie la hauteur à une coordonnée donnée (en utilisant la méthode ci-dessus). Cette fonction a une fréquence, déterminée par la fréquence des hauteurs entières d'origine. Pour en faire une fractale, vous combinez des fonctions avec plusieurs fréquences:

fbm(x)=h(x) + 0.5*h(2*x) + 0.25*h(4*x) + 0.125*h(8*x);

Dans cet exemple, je combine quatre fréquences - originale, double, 4 fois et 8 fois originale, avec des fréquences plus élevées étant donné moins de poids. Théoriquement, les fractales vont jusqu'à l'infini, mais en pratique, seuls quelques termes sont requis. Le fbmdans la formule représente le mouvement brownien fractionnaire - c'est le nom de cette fonction.

Il s'agit d'une technique puissante. Vous pouvez jouer avec un multiplicateur de fréquence, avec des poids de fréquences différentes, ou ajouter des fonctions pour déformer le bruit. Par exemple, pour obtenir une sensation plus "striée", h(x)peut être changé en 1-abs(h(x))(en supposant -1<=h(x)<=1)

Cependant, bien que tout cela soit agréable, cette technique a de sérieuses limites. Avec une approche basée sur la "hauteur", vous ne pouvez jamais avoir de "surplombs" de terrain. Et je les imagine comme une fonctionnalité très agréable à avoir dans un jeu de type "Moon Buggy".

Ajouter de beaux surplombs est une tâche difficile. Une chose à laquelle je peux penser - vous pouvez commencer par une "ligne de hauteur" fractale et la "tesseller" en une série de splines ou de courbes de Bézier. Ensuite, la ligne de terrain sera définie par plusieurs "points clés". Appliquez un peu de gigue à ces points clés - cela entraînera une déformation aléatoire du terrain, formant probablement des formes intéressantes. Cependant, les auto-intersections du terrain peuvent devenir un problème avec cette approche, en particulier avec des quantités de gigue élevées.

Ça ne fait rien
la source
4

Il existe deux méthodes populaires pour générer des cartes de hauteur de terrain.

Certaines réponses données ici sont déjà basées sur l'algorithme Diamond-square, mais connaître le nom facilite la recherche d'informations. Le bruit Perlin a également d'autres utilisations, il est donc bon de le vérifier de toute façon.

msell
la source
L'OP parle de paysages 2D de style mario, mais ce sont quand même de bons liens.
tenpn
1

Mon idée serait de créer une fonction de bruit lissé. D'abord avec une méthode intNoise (int) qui retourne un int "aléatoire", mais qui dépend de l'entrée. Si vous utilisez deux fois la même entrée, le résultat sera le même.

Utilisez ensuite une méthode de lissage pour créer un floatNoise (float) qui utilise les deux entiers autour de l'entrée pour créer une valeur aléatoire.

Utilisez ensuite la position X comme entrée et le Y comme sortie. Le résultat sera une courbe lissée mais avec une hauteur aléatoire.

XGouchet
la source