J'ai un système d'eau basé sur une grille 2D dans mon jeu XNA, nous avons une méthode utilisant des automates cellulaires pour simuler la chute et la propagation de l'eau.
Exemple d'eau coulant sur une pente:
Chaque tuile peut contenir une masse de 0 à 255 valeurs de liquide, stockées dans un octet. Je n'utilise pas floats
, l'ancien système d'eau que j'avais fait, mais cela a ajouté des complications et a eu un impact sur les performances.
Chaque tuile eau se met à jour avec un ensemble simple de règles:
- Si la tuile ci-dessous contient de l'espace, déplacez-vous autant que possible de la tuile actuelle vers la dernière (Flow Down)
- Si les 2 côtés ne sont pas identiques et ne sont pas nuls et que les deux sont passables, nous obtenons la somme des 3 tuiles (gauche + courant + droite) et la divisons par 3 en laissant le reste sur la tuile centrale (actuelle)
- Si la règle ci-dessus a donné un nombre de 2 comme somme, nous devons diviser les tuiles en deux côtés (1, 0, 1)
- Si la règle 2 donne 1 comme somme, choisissez un côté aléatoire dans lequel
- Si la règle 2 a échoué, nous devons vérifier si un côté est passable et l'autre non. Si c'est vrai, nous divisons la tuile actuelle en deux pour les 2 tuiles
Comment puis-je étendre cette logique pour inclure la pression? La pression fera remonter les liquides au-dessus des «coudes en U» et remplira les poches d'air.
Exemple sur la façon dont cela échoue actuellement:
L'eau doit s'écouler et s'égaliser de chaque côté du coude en U. De plus, j'ai créé des méthodes pour savoir à quelle distance se trouve un bloc d'eau et, par conséquent, la pression qu'il subit. Maintenant, je dois pouvoir prendre ces chiffres et les appliquer aux autres zones pour égaliser la pression.
Réponses:
Notez que je n'ai jamais fait cela; ce ne sont que des idées qui peuvent aider. Ou pourrait être totalement faux. Je voulais résoudre ce problème depuis Terraria, mais je ne travaille pas actuellement sur un tel jeu.
J'ai envisagé d'essayer de donner à chaque bloc d'eau de surface (tout bloc contenant de l'eau et sans bloc d'eau au-dessus) une valeur de pression initiale égale à (ou une fonction de) sa hauteur par rapport au bas du monde. La valeur de pression implicite de toute tuile infranchissable est
MAX_PRESSURE
(disons 255), et pour une tuile en plein air estMIN_PRESSURE
(0).La pression est ensuite répartie vers le haut / bas / latéralement à partir de n'importe quelle tuile avec une pression plus élevée vers des tuiles avec une pression plus faible pendant chaque tick, style d'automates cellulaires. Je devrais obtenir une simulation réelle pour savoir exactement à quoi égaliser. La pression d'un bloc doit être égale à sa pression implicite plus la "surpression" de la pression égalisée (il vous suffit donc de stocker cette surpression, pas la pression implicite).
Si une tuile de surface a une pression supérieure à sa pression implicite basée sur la hauteur et si la tuile ci-dessus a un espace libre pour l'eau, une petite partie de l'eau est déplacée vers le haut. L'eau ne coule que si les carreaux ont tous deux de la place et une pression plus faible que prévu.
Cela simule à peu près l'idée que plus le "point" de l'eau est profond, plus il a de pression, bien que les valeurs de pression représentent plus la hauteur que la pression réelle (car les tuiles plus élevées devraient avoir une "pression" plus élevée). Cela rend la pression un peu comme le
h
terme de l'équation (mais pas vraiment):Le résultat est que si la pression de l'eau est plus élevée qu'elle ne devrait l'être pour sa profondeur, elle sera poussée vers le haut. Cela devrait signifier que les niveaux d'eau dans les systèmes fermés égaliseront la pression à tous les niveaux de hauteur au fil du temps.
Je ne sais pas comment faire face ou si l'on doit même faire face aux "bulles d'air" qui seraient créées (où une tuile non superficielle aura des quantités d'eau non pleines lorsque l'eau sera poussée vers le haut). Je ne sais pas non plus comment vous pourriez éviter que les boucles de pressions d'eau soient inégales d'un côté, puis après avoir coché être inégales de l'autre côté, d'avant en arrière.
la source
J'ai créé un système similaire à celui que vous recherchez en 3D. J'ai une courte vidéo démontrant les mécanismes simples de celui-ci ici et un blog ici .
Voici un petit gif que j'ai fait des mécanismes de pression derrière un mur invisible (joué à grande vitesse):
Permettez-moi d'expliquer les données impliquées, pour donner une idée de certaines des caractéristiques du système. Dans le système actuel, chaque bloc d'eau contient les éléments suivants sur 2 octets:
Height
est la quantité d'eau dans le cube, similaire à votre pression, mais mon système n'a que 8 niveaux.Direction
est la direction du flux. Lorsque vous décidez où l'eau coulera ensuite, il est plus probable qu'elle continue dans sa direction actuelle. Il est également utilisé pour remonter rapidement un flux remontant jusqu'à son cube source en cas de besoin.IsSource
indique si ce cube est un cube source, ce qui signifie qu'il ne manque jamais d'eau. Utilisé pour la source des rivières, sources, etc. Le cube à gauche dans le gif ci-dessus est un cube source, par exemple.HasSource
indique si ce cube est connecté à un cube source. Lorsqu'ils sont connectés à une source, les cubes essaieront de puiser dans la source pour plus d'eau avant de rechercher d'autres cubes non sources "plus complets".Largest
indique à ce cube quel est le plus grand flux entre lui et son cube source. Cela signifie que si l'eau s'écoule à travers un espace étroit, cela limite le débit vers ce cube.Active
est un compteur. Lorsque ce cube a un flux actif qui le traverse, vers lui ou depuis celui-ci, l'actif est incrémenté. Sinon, actif est décrémenté de façon aléatoire. Une fois actif atteint zéro (ce qui signifie non actif), la quantité d'eau commencera à être réduite dans ce cube. Ce genre d'actes comme l'évaporation ou le trempage dans le sol. ( Si vous avez un flux, vous devriez avoir un reflux! )FlowOut
indique si ce cube est connecté à un cube qui est au bord du monde. Une fois qu'un chemin vers le bord du monde est fait, l'eau a tendance à choisir ce chemin plutôt qu'un autre.Extra
est un peu supplémentaire pour une utilisation future.Maintenant que nous connaissons les données, regardons un aperçu de haut niveau de l'algorithme. L'idée de base du système est de prioriser les flux descendants et sortants. Comme je l'explique dans la vidéo, je travaille de bas en haut. Chaque couche d'eau est traitée un niveau à la fois sur l'axe y. Les cubes pour chaque niveau sont traités au hasard, chaque cube tentera de tirer de l'eau de sa source à chaque itération.
Les cubes d'écoulement tirent l'eau de leur source en suivant leur direction d'écoulement jusqu'à ce qu'ils atteignent un cube source ou un cube d'écoulement sans parent. Le stockage de la direction du flux dans chaque cube permet de suivre le chemin vers la source aussi facilement que de parcourir une liste liée.
Le pseudo-code de l'algorithme est le suivant:
Les règles de base pour développer un flux où (classés par priorité):
Je sais, c'est un niveau assez élevé. Mais il est difficile d'entrer dans plus de détails sans se voie dans les détails.
Ce système fonctionne plutôt bien. Je peux facilement remplir des fosses d'eau qui débordent pour continuer vers l'extérieur. Je peux remplir des tunnels en U comme vous le voyez dans le gif ci-dessus. Cependant, comme je l'ai dit, le système est incomplet et je n'ai pas encore tout réglé. Je n'ai pas travaillé sur le système de flux depuis longtemps (j'ai décidé qu'il n'était pas nécessaire pour alpha et je le mettrais en attente). Cependant, les problèmes que je traitais lorsque je l'ai mis en attente où:
Piscines . Lorsque vous obtenez une grande piscine d'eau, les pointeurs de l'enfant au parent sont comme un désordre fou de n'importe quel cube aléatoire sélectionné pour couler dans n'importe quelle direction. Comme remplir une baignoire de ficelle idiote. Lorsque vous voulez vider la baignoire, devez-vous suivre le chemin de la ficelle idiote jusqu'à sa source? Ou devriez-vous simplement prendre ce qui est le plus proche? Donc, dans les situations où les cubes sont dans un grand pool, ils devraient probablement ignorer leurs flux parents et tirer de tout ce qui est au-dessus d'eux. J'ai trouvé un code de travail de base pour cela, mais je n'ai jamais eu de solution élégante dont je pourrais être satisfait.
Plusieurs parents . Un flux enfant peut facilement être alimenté par plusieurs flux parent. Mais l'enfant ayant un pointeur vers un parent seul ne le permettrait pas. Cela peut être résolu en utilisant suffisamment de bits pour permettre un bit pour chaque direction parent possible. Et probablement changer l'algorithme pour sélectionner au hasard un chemin dans le cas de plusieurs parents. Mais, je ne l'ai jamais fait pour tester et voir quels autres problèmes pourraient exposer.
la source
Je suis en quelque sorte d'accord avec Sean mais je le ferais un peu différemment:
Un bloc génère une pression égale à son propre poids (la quantité d'eau qu'il contient) et l'applique aux blocs situés en dessous et à côté. Je ne vois aucune raison pour laquelle sa position dans le monde est pertinente.
Sur chaque tique, déplacez l'eau de la haute pression à la basse pression, mais ne déplacez qu'une fraction de l'eau nécessaire pour l'égalisation. L'eau peut également être poussée vers le haut si la pression dans le bloc est trop élevée pour la pression appliquée sur le carré.
Vous obtiendrez des boucles où la pression de l'eau s'écoule trop loin dans un sens et doit ensuite être corrigée, mais comme vous ne déplacez pas toute la quantité d'eau par tick, elles seront amorties. Je pense que c'est en fait une bonne chose, car vous obtiendrez des effets de surtension lorsque les inondations dans une zone comme vous le feriez en réalité.
la source
Vous pouvez ajouter une règle qui essaie d'aller à gauche ou à droite (à travers les murs) avec les tuiles jusqu'à ce que vous trouviez un endroit libre, en commençant par les couches en bas. Si vous ne trouvez pas, la tuile reste à la position actuelle. Si vous trouvez, alors les autres règles garantiront le remplacement de la tuile déplacée (si nécessaire).
la source
pourquoi ne pouvez-vous pas définir un autre type de bloc qui agit comme une quantité de pression inamovible? Par conséquent, lorsque vous utilisez votre façon de déplacer normalement les blocs d'eau et de vérifier si elle peut monter, cela ne peut pas.
Encore mieux serait d'ajouter une autre définition à ces blocs qui permet à l'utilisateur d'entrer la quantité de pression par bloc, en augmentant la pression en fonction de la quantité de blocs d'eau qui y s'ajoutent.
la source