Was bewegt sich eigentlich in einem Endlosläufer?

107

Zum Beispiel bewegt sich der Spieler (in diesem Fall der Vogel oder die Kamera, welche auch immer Sie bevorzugen) vorwärts oder bewegt sich die ganze Welt rückwärts (der Vogel ändert nur die Y-Position und hat eine konstante X-Position)?

Lendrit Ibrahimi
quelle
1
Wir haben viele themenfremde Kommentare zu dieser Frage und ihren Antworten gelöscht. Wir haben auch mehrere vernünftige Diskussionen zum Chatten verschoben, in einigen Fällen wiederholt. Trotzdem haben mehrere Benutzer das Bedürfnis verspürt, die Tatsache zu ignorieren, dass Kommentare nicht für längere Diskussionen vorgesehen sind, und sind weitergegangen. Aus diesem Grund wurde diese Frage vorübergehend gesperrt.
Josh

Antworten:

146

Ich bin nicht einverstanden mit etwas Philipp Antwort ; oder zumindest, wie er es präsentierte. Es gibt den Eindruck, dass es eine bessere Idee sein könnte, die Welt um den Spieler herum zu bewegen. wenn es das genaue Gegenteil ist. Also hier ist meine eigene Antwort ...


Beide Optionen können funktionieren, aber es ist im Allgemeinen eine schlechte Idee, die Physik umzukehren, indem man die Welt um den Spieler herum bewegt, anstatt den Spieler um die Welt.


Leistungsverlust / Verschwendung:

Die Welt wird normalerweise viele Objekte haben; Viele, wenn nicht die meisten, statisch oder schlafend. Der Spieler wird ein oder relativ wenige Objekte haben. Die ganze Welt um den Spieler zu bewegen, bedeutet, alles in der Szene außer dem Spieler zu bewegen. Statische Objekte, schlafende dynamische Objekte, aktive dynamische Objekte, Lichtquellen, Schallquellen usw .; alle müssen bewegt werden.

Das ist (offensichtlich) erheblich teurer als nur das zu bewegen, was sich tatsächlich bewegt (der Spieler und vielleicht noch ein paar Sachen).


Wartbarkeit & Erweiterbarkeit:

Wenn Sie die Welt um den Spieler bewegen, wird die Welt (und alles in ihr) der Punkt sein, an dem die Dinge am aktivsten geschehen. Jeder Fehler oder jede Änderung im System bedeutet, dass sich möglicherweise alles ändert. Dies ist kein guter Weg, um Dinge zu tun; Sie möchten, dass Bugs / Änderungen so isoliert wie möglich sind, damit Sie an keiner Stelle unerwartete Verhaltensweisen feststellen, an der Sie keine Änderungen vorgenommen haben.

Es gibt auch viele andere Probleme mit diesem Ansatz. Zum Beispiel werden viele Annahmen darüber gebrochen, wie die Dinge im Motor funktionieren sollen. Sie können dynamic beispielsweise nur RigidBodyfür den Player verwenden. Da sich ein Objekt mit RigidBodynicht auf Kinematik eingestelltem Anhang beim Festlegen von Position / Drehung / Skalierung unerwartet verhält (was Sie für jedes Bild, für jedes Objekt in der Szene mit Ausnahme des Players tun würden 😨)


Die Antwort ist also, den Spieler nur dann zu bewegen!

Nun ja und nein . Wie in Philipps Antwort erwähnt, würde in einem Spieltyp mit unbegrenzten Möglichkeiten (oder in jedem Spiel mit einem großen, nahtlosen Erkundungsbereich) eine zu große Entfernung vom Ursprung zu merklichen FPPEs ( Floating-Point Precision Errors ) führen. Überlaufe den numerischen Typ und verursache entweder einen Absturz deines Spiels oder lass die Spielewelt in Rauch aufgehen ... Auf Steroiden! 😵 (weil zu diesem Zeitpunkt FPPEs das Spiel bereits auf "normalen" Riss bringen würden)


Die eigentliche Lösung:

Tu weder noch beides! Sie sollten die Welt statisch halten und den Player darum herum bewegen. Aber "re-root" sowohl den Spieler als auch die Welt, wenn der Spieler anfängt, sich zu weit von der Wurzel (Position [0, 0, 0]) der Szene zu entfernen.

Wenn Sie die relative Position der Dinge (Spieler zu der Welt um sie herum) beibehalten und diesen Vorgang in einem einzigen Frame-Update durchführen, wird der (tatsächliche) Spieler es nicht einmal bemerken!

Dazu haben Sie zwei Hauptoptionen:

  1. Bewegen Sie den Spieler an die Wurzel der Szene und verschieben Sie den Weltblock in Bezug auf den Spieler an seine neue Position.
  2. Stellen Sie sich die Welt wie ein Gitter vor. Verschieben Sie den Teil des Gitters, in dem sich der Spieler befindet, in die Wurzel, und verschieben Sie den Spieler in Bezug auf diesen Teil des Gitters an seine neue Position.

Hier ist ein Beispiel für diesen Prozess in Aktion


Aber wie weit ist zu weit?

Wenn Sie sich den Quellcode von Unity ansehen, verwenden sie 1e-5( 0.00001) als Grundlage für die Berücksichtigung von zwei Fließkommawerten, die innerhalb von Vector2und "gleich" sind Vector3(die Datentypen, die für die Positionen, [Euler-] Rotationen und Skalierungen von Objekten verantwortlich sind). Da der Gleitkomma-Präzisionsverlust in beide Richtungen von Null entfernt auftritt, kann davon ausgegangen werden, dass alles, was unter 1e+5( 100000) von der Szenenwurzel / -ursprung entfernt ist, sicher funktioniert.

Aber! Schon seit...

  1. Es ist sinnvoller, ein System zu erstellen, das diese Neuwurzelungsprozesse automatisch abwickelt.
  2. Was auch immer Ihr Spiel ist, es ist nicht erforderlich, dass ein zusammenhängender "Abschnitt" der Welt 100000 Einheiten (Meter [?]) Breit ist.

... dann ist es wahrscheinlich eine gute Idee, viel früher / öfter als die 100000-Einheiten-Marke neu zu wurzeln. Das Beispielvideo, das ich zur Verfügung gestellt habe, scheint dies zum Beispiel alle 1000 Einheiten zu tun.

XenoRo
quelle
2
Kommentare sind nicht für eine längere Diskussion gedacht. Diese Unterhaltung wurde in den Chat verschoben . Bitte benutze diesen Chat, anstatt hier weitere Kommentare zu posten.
Alexandre Vaillancourt
> Das ist (offensichtlich) erheblich teurer als nur das zu bewegen, was sich tatsächlich bewegt . Beim Rendern müssen Sie ohnehin bei allen Objekten eine Matrizenmultiplikation mit der Kameramatrix durchführen, da eine Fixierung der Kamera auf die Identität auf diese Weise weniger kostspielig wäre .
Matsemann
In diesem Moment wird aus der Spieleentwicklung die Entwicklung der Einheit ...
LJ ᛃ
@Matsemann - Wenn Sie zum Chatten gegangen wären, hätten Sie bemerkt, dass dies kein neuer Punkt ist. Rendern Sie, wie bereits erläutert, die Szene NOT-EQUALS. Sie sind verschiedene und fast völlig unabhängige Subjekte und Pipelines. Eine Umkehrung des Bezugsrahmens bei der Positionierung von Objekten in der Szene bedeutet, dass Sie an beiden Enden einen schwereren Prozess haben als nur beim Rendern. --- Auch wenn die Leistung war gleich gehandelt , wie Sie argumentieren, alle anderen Probleme mit der Umkehrung wäre noch ungelöst bleiben, diesen Ansatz macht noch schlechter als die einer Wieder Verwurzelung.
XenoRo
@LJ ᛃ Die Frage wurde speziell zu Unity gestellt (siehe OPs Tags vor D. Everhards [IMHO Defacing] -Änderungen), und daher wurde die Antwort darauf zugeschnitten . --- Aber hier ist das Beste: Sei es Unity, Unreal, CryEngine, Source usw. Die besten und / oder beliebtesten Motoren funktionieren auf diese Weise (und das aus einem bestimmten Grund), daher lautet die Antwort nicht nur Im Allgemeinen vollkommen gültig , aber die vorgebrachten Punkte sind immer noch auf dem Höhepunkt der Genauigkeit . Wenn Sie den Bezugsrahmen der Physik umkehren, können Sie im Allgemeinen Probleme erwarten, insbesondere bei dynamischen Objekten.
XenoRo
89

Beide Optionen funktionieren.

Aber wenn Sie wollen, dass der Endlosläufer wirklich endlos ist, müssen Sie den Spieler stationär halten und die Welt bewegen. Andernfalls stoßen Sie möglicherweise an die Grenzen der Variablen, mit denen Sie die X-Position speichern. Eine Ganzzahl würde irgendwann überlaufen und eine Gleitkommavariable würde immer ungenauer werden, was das Gameplay nach einer Weile unangenehm machen würde. Sie können dieses Problem jedoch vermeiden, indem Sie einen Typ verwenden, der groß genug ist, damit niemand innerhalb der denkbaren Zeitspanne in einer Sitzung auf diese Probleme stößt (wenn ein Player 1000 Pixel pro Sekunde verschiebt, läuft nach 49 Tagen eine 32-Bit-Ganzzahl über).

Tun Sie also, was Ihnen konzeptionell intuitiver erscheint.

Philipp
quelle
Kommentare sind nicht für eine längere Diskussion gedacht. Diese Unterhaltung wurde in den Chat verschoben .
Josh
1
Ich denke nicht, dass das irgendetwas löst. Anstatt die Position des Spielers (und der Kamera) beizubehalten, behalten Sie die Bildlaufposition der Welt bei - wie ist das anders?
Agent_L
1
@Agent_L Im Allgemeinen werden Welten stückweise generiert, und jedes Stück hat seine X / Y-Position. Wenn die Figur genügend hinter dem Spieler zurückbleibt (z. B. außerhalb des Bildschirms), wird sie gelöscht, und sie werden nur eine bestimmte Menge im Voraus generiert, sodass sie immer in einem relativ kleinen Bereich liegen - ein Spiel, das ich gemacht habe, hatte nie eine größere Koordinate als ~ 1000 oder kleiner als 0, obwohl ich aus diesem Grund ein unendlicher, zufällig generierter Läufer bin - Ich habe die Position des Spielers in jedem Block und den Index jedes Blocks in der Sequenz verfolgt.
Nic Hartley
Ich kaufe das Konzept "variabler Überlauf" nicht. Wenn sich der Spieler nicht bewegt, wird der "Hintergrund" um den gleichen Betrag negativ verschoben, den der Spieler bei einer Bewegung hätte. In beiden Fällen würde genau dasselbe Problem auftreten (in entgegengesetzte Richtungen), und beide erfordern eine spezielle Behandlung an den Grenzen des Überlaufs.
Spender
2
Bei 1000 Pixeln pro Sekunde würde es über 586 Millionen Jahre dauern, um eine 64-Bit-Ganzzahl zu überschreiten. Dies ist nur dann wirklich ein Problem, wenn Sie wirklich kleine Typen wie 16-Bit-Ganzzahlen verwenden.
Lyndon White
38

Aufbauend auf der Antwort von XenoRo könnte man anstelle der beschriebenen Methode zum erneuten Verwurzeln Folgendes tun:

Erstellen Sie einen kreisförmigen Puffer aus Teilen Ihrer generierten unendlichen Karte, durch den sich Ihr Charakter mit einer mit Modulo-Arithmetik aktualisierten Position bewegt (sodass Sie nur um den kreisförmigen Puffer herumlaufen). Ersetzen Sie Teile Ihres Puffers, sobald Ihr Charakter den Block verlässt. Die Spieler-Update-Gleichung würde ungefähr so ​​lauten:

player.position = (player.position + player.velocity) % worldBuffer.width;

Hier ist ein Bildbeispiel von dem, wovon ich spreche:

Bildbeschreibung hier eingeben

Hier ist ein Beispiel dafür, was beim Umschließen am Ende passiert.

Bildbeschreibung hier eingeben

Mit dieser Methode laufen Sie nicht in Präzision Fehler immer, aber Sie können einen sehr großen Puffer machen brauchen , wenn Sie beabsichtigen , dies mit sehr weiten Blick Abstand in 3d zu tun (wie Sie noch in der Lage sein müssen sehen vor sich ). Wenn es ein flatterhafter Vogel ist, wird Ihr Block wahrscheinlich nur so groß sein, wie es sein muss, um eine einzelne Szene für einen einzelnen Bildschirm aufzunehmen, und Ihr Puffer kann sehr klein sein.

Beachten Sie, dass Sie mit ANY prng anfangen, sich wiederholende Ergebnisse zu erhalten, und die maximale Anzahl nicht wiederholender Sequenzen einer PRNG-Generation in der Regel geringer ist als die Länge von pow (2, Anzahl der intern verwendeten Bits), mit merzenne twister ist dies nicht der Fall Ein großes Problem, da 2,5 KB interner Status verwendet werden. Wenn Sie jedoch die winzige Variante verwenden, haben Sie 2 ^ 127-1 maximale Iterationen vor der Wiederholung (oder noch schlimmer). Dies ist jedoch immer noch eine astronomisch große Zahl . Sie können Probleme mit Wiederholungsperioden auch dann beheben, wenn Ihr PRNG über gute Lawinenmischfunktionen für die Saat (wenn Sie implizit mehr Status hinzufügen) wiederholt eine kurze Periode aufweist .

opa
quelle
Kommentare sind nicht für eine längere Diskussion gedacht. Diese Unterhaltung wurde in den Chat verschoben .
Josh
15

Wie bereits gefragt und akzeptiert, hängt es wirklich vom Umfang und Stil Ihres Spiels ab, aber da es nicht erwähnt wurde: FlappyBird bewegt das Hindernis über den Bildschirm und nicht den Spieler über die Welt.

Ein Spawner instanziiert Objekte außerhalb des Bildschirms mit einer festgelegten Geschwindigkeit in der Vector2.leftRichtung.

Stephan
quelle
3
Das funktioniert bei FlappyBird, weil es ein sehr einfaches Spiel ist. Wie in meiner Antwort erwähnt, wäre die gleiche Technik bei komplexeren Objekten (mit mehr Weltobjekten / Details) wie dem Subway Surfer sehr problematisch , obwohl dies immer noch möglich ist .
XenoRo
15
Ich stimme zu, und Ihre Antwort ist sehr gründlich. Ich habe nur niemanden gesehen, der erwähnt hat, welche Methode das Flattern von Vögeln tatsächlich verwendet, also dachte ich, ich würde es hinzufügen.
Stephan