Ich habe in meinem XNA-Spiel ein auf einem 2D-Gitter basierendes Wassersystem. Wir haben eine Methode, die zellulare Automaten verwendet, um das Fallen und die Ausbreitung von Wasser zu simulieren.
Beispiel von Wasser, das einen Hang hinunter fließt:
Jede Kachel kann eine Masse von 0 bis 255 Flüssigkeitswerten enthalten, die in einem Byte gespeichert sind. Ich benutze nicht floats
das alte Wassersystem, das ich getan habe, aber es fügte Komplikationen hinzu und hatte einen Leistungseinbruch.
Jedes Wasserplättchen aktualisiert sich selbst mit einem einfachen Regelwerk:
- Wenn die Kachel darunter Platz hat, bewegen Sie sich so weit wie möglich von der aktuellen Kachel zur untersten (Nach unten fließen).
- Wenn die beiden Seiten nicht gleich und nicht Null sind und beide passierbar sind, erhalten wir die Summe der 3 Kacheln (links + aktuell + rechts) und teilen sie durch 3, wobei der Rest auf der mittleren (aktuellen) Kachel verbleibt
- Wenn die obige Regel eine Zahl von 2 als Summe ergibt, sollten wir die Kacheln in zwei Seiten teilen (1, 0, 1)
- Wenn Regel 2 1 als Summe ergibt, wählen Sie eine zufällige Seite, in die Sie einfließen möchten
- Wenn Regel 2 fehlschlägt, sollten wir prüfen, ob eine Seite passierbar ist und die andere nicht. Wenn dies zutrifft, teilen wir die aktuelle Kachel für die 2 Kacheln in zwei Hälften
Wie kann ich diese Logik um Druck erweitern? Durch den Druck steigen Flüssigkeiten über die "U-Bögen" und füllen die Lufteinschlüsse.
Beispiel, wie dies derzeit fehlschlägt:
Das Wasser sollte auf jeder Seite des U-Bogens fließen und sich ausgleichen. Außerdem habe ich Methoden entwickelt, um herauszufinden, wie weit ein Wasserblock entfernt ist und wie viel Druck er ausübt. Jetzt muss ich in der Lage sein, diese Zahlen zu nehmen und sie auf die anderen Bereiche anzuwenden, um den Druck auszugleichen.
Antworten:
Beachten Sie, dass ich das noch nie gemacht habe. Dies sind nur Ideen, die helfen können. Oder könnte völlig gefälscht sein. Ich wollte dieses Problem seit Terraria angehen, arbeite aber derzeit nicht an einem solchen Spiel.
Ich habe versucht, jedem Oberflächenwasserblock (jedem Block mit Wasser und ohne Wasserblock darüber) einen Anfangsdruckwert zu geben, der gleich (oder abhängig von) seiner Höhe vom Grund der Welt ist. Der implizite Druckwert einer unpassierbaren Fliese ist
MAX_PRESSURE
(z. B. 255), und für eine offene Fliese istMIN_PRESSURE
(0).Der Druck wird dann von jedem Plättchen mit höherem Druck nach oben / unten / seitwärts auf die Plättchen mit niedrigerem Druck während jedes Ticks im zellularen Automatenstil verteilt. Ich müsste eine tatsächliche Simulation erstellen, um genau herauszufinden, worauf es ankommt. Der Druck eines Blocks sollte gleich dem impliziten Druck plus dem "Überdruck" von ungefähr ausgeglichen sein (Sie müssen also nur diesen Überdruck speichern, nicht den impliziten Druck).
Wenn eine Fliese einen Druck hat, der größer ist als ihr impliziter Druck auf der Höhe, und wenn die darüber liegende Fliese freien Platz für Wasser hat, wird ein kleiner Teil des Wassers nach oben bewegt. Wasser fließt nur dann nach unten, wenn beide Fliesen Platz haben und einen geringeren Druck als erwartet haben.
Dies simuliert grob die Vorstellung, dass je tiefer der Wasser- "Punkt", desto mehr Druck vorhanden ist, obwohl die Druckwerte mehr die Höhe als den tatsächlichen Druck repräsentieren (da bei höheren Fliesen ein höherer "Druck" erwartet wird). Dies macht den Druck ein bisschen wie der
h
Ausdruck in der Gleichung (aber nicht wirklich):Das Ergebnis ist, dass wenn der Druck des Wassers höher ist, als er für seine Tiefe sein sollte, es nach oben gedrückt wird. Dies sollte bedeuten, dass der Wasserstand in geschlossenen Systemen den Druck über alle Höhenstufen hinweg im Laufe der Zeit ausgleicht.
Ich bin mir nicht sicher, wie ich damit umgehen soll oder ob ich überhaupt mit den "Luftblasen" umgehen muss, die entstehen würden (wenn eine nicht oberflächliche Fliese nicht volle Wassermengen aufweist, wenn Wasser nach oben gedrückt wird). Ich bin mir auch immer noch unsicher, wie Sie vermeiden könnten, dass Wasserdruckschleifen auf der einen Seite ungleich sind und dann nach dem Ankreuzen auf der anderen Seite ungleich sind, hin und her.
quelle
Ich habe ein System erstellt, das dem in 3D ähnelt, nach dem Sie suchen. Ich habe ein kurzes Video die einfache Mechanik davon demonstriert hier und eine Blog - Post hier .
Hier ist eine kleine Beschreibung der Druckmechanik hinter einer unsichtbaren Wand (gespielt mit hoher Geschwindigkeit):
Lassen Sie mich die Daten erläutern, um einen Eindruck von einigen Funktionen des Systems zu erhalten. In dem gegenwärtigen System enthält jeder Wasserblock das Folgende in 2 Bytes:
Height
ist die Wassermenge im Würfel, ähnlich wie Ihr Druck, aber mein System hat nur 8 Ebenen.Direction
ist die Richtung, in die der Fluss fließt. Bei der Entscheidung, wohin das Wasser als nächstes fließen soll, ist es wahrscheinlicher, dass es in die aktuelle Richtung fließt. Dies wird auch verwendet, um einen Flow bei Bedarf schnell bis zu seinem Quellcube zurückzuverfolgen.IsSource
Gibt an, ob es sich bei diesem Würfel um einen Quellwürfel handelt. Dies bedeutet, dass ihm niemals das Wasser ausgeht. Wird für die Quelle von Flüssen, Quellen usw. verwendet. Der Würfel links im GIF oben ist beispielsweise ein Quellwürfel.HasSource
Gibt an, ob dieser Cube mit einem Quellcube verbunden ist. Wenn Würfel an eine Quelle angeschlossen sind, versuchen sie, auf die Quelle zu tippen, um mehr Wasser zu erhalten, bevor sie nach anderen "volleren" Würfeln suchen, die keine Quelle sind.Largest
teilt diesem Würfel mit, welcher Fluss zwischen ihm und seinem Quellwürfel am größten ist. Das heißt, wenn Wasser durch einen engen Spalt fließt, wird der Durchfluss zu diesem Würfel begrenzt.Active
ist ein Zähler. Wenn dieser Würfel einen aktiven Fluss durchläuft, zu ihm oder von ihm, wird active inkrementiert. Ansonsten wird active zufällig dekrementiert. Sobald Aktiv Null erreicht (dh nicht aktiv), wird die Wassermenge in diesem Würfel verringert. Diese Art von Handlungen wirken wie Verdampfen oder Einweichen in den Boden. ( Wenn Sie Strömung haben, sollten Sie Ebbe haben! )FlowOut
Gibt an, ob dieser Würfel mit einem Würfel am Rand der Welt verbunden ist. Sobald ein Weg zum Rand der Welt gefunden ist, wählt das Wasser diesen Weg eher als jeden anderen.Extra
ist ein zusätzliches Bit für die zukünftige Verwendung.Nachdem wir die Daten kennen, sehen wir uns eine allgemeine Übersicht über den Algorithmus an. Die Grundidee des Systems besteht darin, das Ab- und Abfließen zu priorisieren. Wie ich im Video erkläre, arbeite ich von unten nach oben. Jede Wasserschicht wird auf der y-Achse stufenweise abgearbeitet. Die Würfel für jedes Level werden nach dem Zufallsprinzip verarbeitet. Jeder Würfel versucht bei jeder Iteration, Wasser aus seiner Quelle zu ziehen.
Strömungswürfel ziehen Wasser aus ihrer Quelle, indem sie ihrer Strömungsrichtung folgen, bis sie einen Quellwürfel oder einen Strömungswürfel ohne übergeordnetes Element erreichen. Durch das Speichern der Flussrichtung in jedem Cube wird das Verfolgen des Pfads zur Quelle so einfach wie das Durchlaufen einer verknüpften Liste.
Der Pseudocode für den Algorithmus lautet wie folgt:
Die Grundregeln zum Erweitern eines Ablaufs lauten (geordnet nach Priorität):
Ich weiß, das ist ziemlich hoch. Aber es ist schwer , mehr ins Detail zu bekommen , ohne sie Weg ins Detail.
Dieses System funktioniert ziemlich gut. Ich kann leicht Wassergruben auffüllen, die überlaufen, um nach außen zu gelangen. Ich kann U-förmige Tunnel füllen, wie Sie oben im GIF sehen. Wie gesagt, das System ist unvollständig und ich habe noch nicht alles ausgearbeitet. Ich habe lange nicht mehr am Flow-System gearbeitet (ich entschied, dass es für Alpha nicht benötigt wurde und stellte es in die Warteschleife). Die Probleme, mit denen ich mich befasste, als ich es auf Eis legte, waren jedoch:
Pools . Wenn Sie einen großen Wasserbecken bekommen, sind die Zeiger von Kind zu Eltern wie eine verrückte Sauerei, egal welcher zufällige Würfel ausgewählt wurde, um in welche Richtung zu fließen. Als würde man eine Badewanne mit einer dummen Schnur füllen. Wenn Sie die Wanne entleeren möchten, sollten Sie dem Pfad der dummen Schnur zurück zu ihrer Quelle folgen? Oder solltest du einfach nehmen, was am nächsten ist? In Situationen, in denen sich Cubes in einem großen Pool befinden, sollten sie wahrscheinlich nur die übergeordneten Flows ignorieren und von allem, was sich über ihnen befindet, ziehen. Ich hatte einen grundlegenden Arbeitscode dafür, aber nie eine elegante Lösung, mit der ich zufrieden sein konnte.
Mehrere Eltern . Ein untergeordneter Stream kann leicht von mehr als einem übergeordneten Stream gespeist werden. Aber das Kind, das einen Zeiger auf einen einzelnen Elternteil hat, würde das nicht zulassen. Dies kann behoben werden, indem genügend Bits verwendet werden, um ein Bit für jede mögliche übergeordnete Richtung zuzulassen. Und wahrscheinlich wird der Algorithmus so geändert, dass bei mehreren Elternteilen zufällig ein Pfad ausgewählt wird. Aber ich bin nie dazu gekommen, um zu testen und zu sehen, welche anderen Probleme dies aufdecken könnte.
quelle
Ich stimme Sean zu, aber ich würde es ein bisschen anders machen:
Ein Block erzeugt einen Druck in Höhe seines Eigengewichts (wie viel Wasser sich darin befindet) und legt ihn an die darunter und daneben liegenden Blöcke an. Ich sehe keinen Grund, warum seine Position in der Welt relevant ist.
Bewegen Sie bei jeder Zecke das Wasser von Hochdruck auf Niederdruck, bewegen Sie jedoch nur einen Bruchteil des zum Ausgleich benötigten Wassers. Wasser kann auch nach oben gedrückt werden, wenn der Druck im Block zu hoch ist, als dass der Druck auf das Quadrat ausgeübt werden könnte.
Sie erhalten Schleifen, in denen der Wasserdruck zu weit in eine Richtung fließt und dann korrigiert werden muss. Da Sie jedoch nicht die gesamte Wassermenge pro Tick bewegen, werden diese gedämpft. Ich denke, es ist tatsächlich eine gute Sache, da es zu Überspannungen kommt, wenn Wasser in einen Bereich strömt, wie Sie es in der Realität tun würden.
quelle
Sie können eine Regel hinzufügen, die versucht, mit den Kacheln nach links oder rechts (durch die Wände) zu gehen, bis Sie eine freie Stelle finden, beginnend mit den Ebenen auf der Unterseite. Wenn Sie nicht finden können, bleibt die Kachel an der aktuellen Position. Wenn Sie feststellen, garantieren die anderen Regeln das Ersetzen der verschobenen Kachel (falls erforderlich).
quelle
Warum können Sie keine andere Art von Block definieren, die als unbewegliche Menge an Druck wirkt? Wenn Sie also die Wasserblöcke normal bewegen und prüfen, ob sie sich nach oben bewegen lassen, kann dies nicht passieren.
Noch besser wäre es, diesen Blöcken eine weitere Definition hinzuzufügen, mit der der Benutzer die Menge des Drucks pro Block eingeben und den Druck entsprechend der Menge der hinzugefügten Wasserblöcke erhöhen kann.
quelle