Comment pourrais-je générer une carte des étoiles?

8

Im essayant de générer une carte des étoiles.

Mon essai serait:

  1. Ayez une largeur et une hauteur pour la carte.
  2. Placez des points (étoiles) de manière aléatoire sur la zone de largeur et de hauteur.

Une approche simple, mais qui pose le problème de placer au hasard des étoiles extrêmement proches les unes des autres.

Pour résoudre ce problème, une approche consisterait à avoir une distance minimale et lors de la génération d'une étoile, vous comparez la distance de la nouvelle étoile à chaque étoile générée et si sa distance inférieure à la distance minimale, vous en générez une nouvelle, mais je ne sais pas si c'est efficace. Des conseils?

zebleckDAMM
la source
3
Il existe peut-être des moyens plus efficaces de le faire, mais pourquoi cela ne fonctionne-t-il pas pour vous? Avez-vous des problèmes avec cette implémentation? Vous optimisez prématurément?
Vaillancourt
Quel est le but de la carte des étoiles? Est-ce un arrière-plan ou plutôt un terrain de jeu?
Erik
@AlexandreVaillancourt oui je ne sais pas encore combien d'étoiles je veux générer et j'ai l'impression que c'est une manière très inefficace.
zebleckDAMM
@Erik n'est pas un arrière-plan, des stars avec
lesquelles
Et ... le ferez-vous au moment de l'exécution ou hors ligne?
Vaillancourt

Réponses:

13

Une distribution d' échantillonnage Poisson-Disk vous permettra de sélectionner des points aléatoires à une distance minimale l'un de l'autre et l'algorithme de Bridson peut résoudre efficacement le problème en O (n) - assez rapidement pour le temps réel à condition que votre nombre d'étoiles ne devienne pas trop énorme.

L'algorithme de Bridson divise la région de sortie en une grille de cellules dimensionnée par rapport à la distance minimale autorisée, de sorte qu'un seul point peut apparaître dans chaque cellule. Ensuite, lorsque vous envisagez d'ajouter un nouveau point, il vous suffit de vérifier une collection en forme de disque de cellules voisines par opposition à la liste entière de points. Par exemple, considérez l'image suivante:

entrez la description de l'image ici

Lors de la vérification pour voir si le point bleu candidat est trop proche des points existants, vous n'avez pas besoin de le comparer à chaque point existant. Au lieu de cela, vous pouvez limiter la recherche aux points dans les cellules voisines (que vous pouvez trouver rapidement en utilisant une table de recherche). Mike Bostock a une belle animation montrant l'algorithme en cours.

L'implémentation standard ne concerne qu'une distance minimale fixe entre les points. L' article d'échantillonnage du disque de Poisson d' Herman Tulleken (inclut le code source) couvre une adaptation pour faire varier la distance minimale à différentes parties de l'image; essentiellement comme un algorithme de tramage . L'utilisation du bruit perlin / bruit simplex comme indiqué dans l'article peut donner une carte des étoiles plus naturelle. Par exemple, j'ai utilisé l'image de gauche pour générer la droite:

entrez la description de l'image ici entrez la description de l'image ici

Pour ce faire, lorsque je considère un point candidat, je vérifie d'abord la valeur de l'image d'entrée, qui donne une valeur de 0 à 1. Je l'échelle ensuite à ma distance min & max souhaitée entre les points; dans ce cas, j'ai sélectionné 5 et 20 pixels. Ainsi, lorsque vous placez un point dans les régions sombres, mes étoiles peuvent être aussi proches que 5 pixels les unes des autres et lorsque vous placez des étoiles dans les régions claires, elles peuvent être éloignées jusqu'à 20 pixels.

Il convient de noter que l'accélération de Bridson ne fonctionne pas exactement avec l'échantillonnage à distance variable car les points de sortie n'utilisent pas une distance minimale uniforme. Cependant, vous pouvez toujours utiliser la grille de sortie pour réduire la recherche. Une grille plus petite entraîne une recherche plus rapide des voisins les plus proches au détriment d'une mémoire accrue pour une table de recherche plus grande.

Pikalek
la source
2
Les liens sont très sympas. Cependant, ils pourraient se perdre avec le temps. Il pourrait être encore mieux d'inclure plus de détails ici.
Trilarion
Ajout d'un peu plus d'explications et d'illustrations pour se prémunir contre cela.
Pikalek
1

Une solution très naïve mais simple serait simplement de toujours sauter la distance "minimale", puis d'ajouter un montant aléatoire en plus de cela. Cela signifie que les étoiles ne deviendront jamais trop copain et que vous obtiendrez au moins un peu de déviation.

par exemple

for (int x = 0; x < MAX_WIDTH; x+= MIN_SEPERATION_X)
{
  x += generateRandom();

  for (int y = 0; y < MAX_HEIGHT; y+= MIN_SEPERATION_Y)
  {
    y += generateRandom();

    if (x < MAX_WIDTH && y < MAX_HEIGHT)
    {
      image[x + y * width] = STAR;
    }
  }
}

(Insertion de votre fonction de génération de nombres aléatoires préférée)

Huxellberger
la source
Mais que faire si vous frappez une autre étoile là-bas? (Vos stars devraient également être dans un groupe incliné si vous faites comme ça.)
Trilarion
1
Est-il possible de frapper une autre étoile? Je suppose qu'une seule itération sur l'image entière. Les deux nombres ne changent-ils pas toujours par une séparation min. J'entends que les fusions stellaires sont assez désordonnées, donc je suis d'accord qu'il est bon de s'assurer qu'elles ne se produisent pas. Causer une supernova serait un bug très inconsidéré.
Huxellberger
Je voulais dire que la min_separation n'est pas garantie (ne peut pas être avec cet algorithme) car vous ajoutez toujours des nombres aléatoires. Assurez-vous au moins que les nombres aléatoires ne peuvent pas être supérieurs à min_separation. La distance minimale garantie est alors min_separation - max (generate_Random). Mais ce n'est pas une très mauvaise approche. +1
Trilarion
Cette approche aura tendance à produire des colonnes d'étoiles en lignes verticales nettes, car vous ne modifiez pas la coordonnée x lorsque y change. Il est peu probable que cela semble aléatoire ou naturel pour les collections denses.
DMGregory
0

Si vous connaissez la taille XYZ de votre espace de jeu, vous pouvez choisir un endroit aléatoire dans cet espace

puis faites un SphereCast pour vérifier s'il y a déjà quelque chose de trop proche.

//pseudo code

SpawnStar(){
 Vector3 spot = new vector3(random(0,world size),random(0,world size,random(0,world size)

  while(true){
  SphereCast(spot, radius)
   if(hit something){
      spot = get new random spot
    }else{
     SpawnStar();
     brake;
    }
  } 
}

Le problème avec cela est qu'il ne sera probablement pas très bon en temps réel, mais pour les pré-générés, c'est bien et assez rapide.

Josh Kirkpatrick
la source
1
Quel que soit un SphereCast, n'est-ce pas exactement la solution mentionnée dans la question et considérée comme inefficace?
Trilarion
1
Je pense que vous voulez dire OverlapSphere. SphereCast tire une sphère le long d'une ligne, ce qui lui confère une empreinte de détection en forme de capsule.
DMGregory