Je fais un jeu avec un monde généré de manière procédurale créé au début du jeu, composé de plusieurs zones représentées par des grilles (disons, 8x8, 9x6, les tailles seraient idéalement arbitraires). Ces zones sont censées être connectées les unes aux autres via une liste de dépendances.
Une connexion existe lorsqu'au moins 3 espaces de cette grille sont exposés entre ces deux zones. Dans la cellule centrale de cette zone de connexion à 3 espaces se trouve la porte entre les zones:
J'ai essayé de trouver un moyen de les connecter, mais cela devient de plus en plus complexe au fur et à mesure que vous devez prendre en compte plusieurs domaines.
J'ai essayé du prototypage papier et bien que ce soit un processus très simple pour le faire visuellement, je n'ai pas trouvé un bon ensemble d'expressions mathématiques qui me permettent de placer des pièces avec la même efficacité par code.
Voici un exemple "simple" avec lequel je me bats en ce moment:
- La zone «a» doit être connectée à «b» et «c»
- La zone «b» doit être connectée à «a» et «d»
- La zone «c» doit être connectée à «a» et «d»
- La zone «d» doit être connectée à «b» et «c»
Considérez, pour simplifier, nous plaçons les chambres par leur ordre d'apparition sur la liste (j'en ai essayé d'autres). J'approche donc cela comme votre algorithme de génération de donjons procédural standard.
Nous plaçons 'a' n'importe où sur le tableau, car c'est le premier domaine. Ensuite, nous choisissons un mur au hasard et, comme rien n'est connecté à ce mur, nous pouvons y placer «b»:
Maintenant, nous devons placer «c», mais «a» est déjà sur le plateau et a un mur occupé, nous décidons donc de le placer sur un autre mur. Mais tous les emplacements ne feront pas l'affaire, car «d» arrive et il doit également être connecté à «b» et «c»:
J'ai essayé une limitation possible que 2 chambres qui ont le même ensemble de dépendances ne peuvent pas être sur des murs opposés, mais même cela ne garantit pas le succès:
Et dans d'autres cas, lorsque les zones ont des tailles différentes, le fait d'être sur des murs opposés peut fonctionner:
De plus, ne pas considérer un mur utilisé est une hypothèse erronée car elle exclut les solutions valides:
J'ai essayé de chercher des recherches sur d'autres algorithmes de génération procédurale ou similaires, tels que les algorithmes d'optimisation de rectangle et de mise en page graphique, mais généralement ces algorithmes ne prennent pas en compte toutes les contraintes de ce problème et sont difficiles à mélanger.
J'ai pensé à un tas d'approches, y compris le placement d'une zone et la marche arrière jusqu'à ce qu'un placement approprié soit trouvé, mais elles semblent très dépendantes des essais et des erreurs et coûteuses en termes de calcul. Mais, compte tenu des recherches approfondies sur les deux derniers problèmes que j'ai mentionnés, ce pourrait être la seule / meilleure solution?
Je voulais juste voir si quelqu'un avait eu des problèmes similaires dans le passé ou s'il était prêt à m'aider à comprendre cela et à me donner quelques conseils sur la façon de commencer avec l'algorithme. Ou, à défaut, je devrai envisager de desserrer les contraintes que j'ai définies.
la source
Réponses:
C'est un problème sympa. Je crois que cela peut être résolu en utilisant la planification d'actions dans l'espace de placement des chambres.
Définissez l' état du monde comme suit:
Définissez une contrainte comme:
Où "adjacent" est comme vous l'avez décrit (partageant au moins 3 voisins)
Une contrainte serait invalidée chaque fois que les deux pièces ne sont pas adjacentes et que les deux pièces existent.
Définissez un État pour être valide lorsque:
Définissez une action comme l'emplacement d'une pièce, compte tenu d'un état actuel. L' action est valide chaque fois que l'état résultant de l'action est valide. Par conséquent, nous pouvons générer une liste d'actions pour chaque état:
Maintenant, ce qui vous reste est un graphique , où les États sont des nœuds et les Actions sont des liens. Le but est de trouver un État qui soit à la fois valide, et toutes les chambres ont été placées. Nous pouvons trouver un emplacement valide en recherchant dans le graphique de manière arbitraire, peut-être en utilisant une recherche en profondeur d'abord. La recherche ressemblera à ceci:
Maintenant, la qualité du donjon généré dépendra de l'ordre dans lequel les salles et les actions sont prises en compte. Vous pouvez obtenir des résultats intéressants et différents probablement en permutant simplement au hasard les actions que vous prenez à chaque étape, faisant ainsi une marche aléatoire dans le graphique état-action. L'efficacité de la recherche dépendra grandement de la rapidité avec laquelle vous pouvez rejeter les états non valides. Il peut être utile de générer des états valides à partir des contraintes chaque fois que vous souhaitez rechercher des actions valides.
la source
Vos priorités de génération sont en conflit. Lors de la génération de niveaux, votre premier objectif doit être un réseau de points connectés planaires (sans chevauchement) , quelle que soit l'échelle. Ensuite, créez des pièces à partir des points de ce site Web. La création de formes de pièce en premier est généralement une erreur. Créez d'abord la connectivité, puis voyez quelles formes de salle peuvent être adaptées à cela.
Algorithme général
Créez une grille de plancher quantifiée de taille suffisante pour prendre en charge votre niveau, à l'aide d'un tableau ou d'une image 2D.
Dispersez des points au hasard sur cet espace vide. Vous pouvez utiliser une simple vérification aléatoire sur chaque tuile pour voir si elle obtient un point, ou utiliser la distribution standard / gaussienne pour disperser les points. Attribuez une couleur / valeur numérique unique à chaque point. Ce sont des identifiants. (PS Si après cette étape, vous sentez que vous avez besoin d'agrandir votre espace, faites-le.)
Pour chacun de ces points générés, en séquence, augmentez progressivement un cercle de limites ou un rectangle de limites en une seule étape (généralement un taux de 0,5 à 1,0 cellules / pixels par étape) dans
x
ety
. Vous pouvez soit faire pousser toutes les bornes en parallèle, toutes en commençant à partir de la taille zéro au même stade, soit vous pouvez commencer à les faire pousser à des moments et à des rythmes différents, ce qui donne un biais à la taille de celles qui commencent plus tôt (imaginez que les semis poussent, où certains commencer tard). Par «grandir», je veux dire remplir les limites nouvellement incrémentées avec la couleur / ID unique au point de départ pour ces limites. Une métaphore pour cela serait de tenir des marqueurs contre le dos d'un morceau de papier et de regarder des taches d'encre de différentes couleurs pousser jusqu'à ce qu'elles se rencontrent.À un moment donné, les limites d'un point et d'un autre vont entrer en collision, pendant l'étape de croissance. C'est le point auquel vous devez arrêter de repousser les limites de ces deux points - au moins dans le sens uniforme décrit à l'étape 3.
Une fois que vous avez repoussé les limites de tous les points autant que possible et arrêté tous les processus de croissance, vous aurez une carte qui devrait être largement, mais pas entièrement remplie. Vous voudrez peut-être maintenant emballer ces espaces vides, que je suppose être blancs, comme si vous coloriez une feuille de papier.
Remplissage d'espace post-traitement
Diverses techniques peuvent être utilisées pour remplir les espaces vides / blancs qui restent, selon l'étape 5:
Perturbation
Comme dernière étape pour rendre les choses plus organiques, vous pouvez faire une perturbation des bords à divers degrés, sur les cellules des bords des zones. Assurez-vous simplement de ne pas bloquer les itinéraires de déplacement cruciaux.
Théorie, pour l'intérêt
Ceci est similaire à l'approche adoptée dans Diagrammes de Voronoï / Triangulation de Delaunay , sauf que dans ce qui précède, vous ne créez pas explicitement d'arêtes - au lieu de cela, lorsque les zones de délimitation entrent en collision, la croissance cesse. Vous remarquerez que les diagrammes de Voronoi remplissent l'espace; c'est parce qu'ils ne cessent pas la croissance simplement au toucher, mais plutôt sur un certain degré nominal de chevauchement. Vous pouvez essayer similaire.
la source