Wie funktioniert die Wiederholung in einem Spiel?


145

Ich war ein bisschen neugierig, wie die Wiederholung in einem Spiel implementiert werden könnte.

Anfangs dachte ich, dass es nur eine Befehlsliste für jeden Spieler / jede Aktion geben würde, die / der im Spiel ausgeführt wurde. Dann wird das Spiel erneut abgespielt und die Engine wird wie gewohnt gerendert. Allerdings habe ich bei Replays in FPS sehe / RTS - Spiele, und bei sorgfältiger Prüfung auch Dinge wie die Partikel und grafische / hörbare Störungen sind konsistent (und diese Störungen sind in der Regel in Einklang).

Wie passiert das? In Spielen mit festem Kamerawinkel schreibe ich zwar möglicherweise jedes Bild der gesamten Szene in einen Stream, der gespeichert wird, und spielt den Stream dann einfach wieder ab, aber das scheint nicht genug für Spiele zu sein, bei denen Sie die Kamera anhalten und bewegen können um. Sie müssten zu jedem Zeitpunkt die Positionen von allem in der Szene speichern (Nein?). Für Dinge wie Partikel sind also viele Daten zu pushen, was die Leistung des Spiels während des Spielens erheblich zu beeinträchtigen scheint.


10
Original Star Craft Replays waren in der Tat NICHT konsistent. Sie könnten das gleiche Spiel zweimal sehen und einige ziemlich unterschiedliche Ergebnisse sehen.
Andres

1
@Andres: Interessant, ich hatte es nicht bemerkt. Insbesondere für das RTS-Genre dachte ich an Company Of Heroes.
Steven Evers

4
Um zu klären, was SnOrfus meiner Meinung nach fragt: Bei einigen Spielen (Uncharted 2, Halo 3, sogar Battlefield 2) können Sie ein Spiel in seiner Gesamtheit aufzeichnen. Nachdem das Spiel beendet ist, können Sie es mit einer festgelegten Geschwindigkeit wiedergeben und während der Aktion durch das Level fliegen und es von jeder Position auf der Karte aus anzeigen. Ich gehe also davon aus, dass es darum geht, die Bewegungen aller Player / Objekte aufzuzeichnen, und nicht um Videopuffer.
Sean

1
@ Sean O'Hollaren: Ja, das ist richtig.
Steven Evers

1
Dann werde ich auch für die Autorennen hinzufügen, bei denen Wiederholungen fast Standard sind. Ich bin mir ziemlich sicher, dass der Standort der Modelle aufgezeichnet wird und dann alles einfach durch den Motor läuft.
d -_- b

Antworten:


61

Ich denke, Ihr erster Gedanke war richtig. Um eine Wiederholung zu erstellen, speichern Sie alle vom Benutzer empfangenen Eingaben (zusammen mit der Frame-Nummer, bei der sie empfangen wurden) zusammen mit den anfänglichen Startwerten aller Zufallszahlengeneratoren. Um das Spiel erneut abzuspielen, setzen Sie Ihre PRNGs mithilfe der gespeicherten Seeds zurück und geben der Spiel-Engine dieselbe Eingabesequenz (synchronisiert mit den Frame-Nummern). Da viele Spiele den Spielstatus basierend auf der Zeit aktualisieren, die zwischen den Frames vergeht, müssen Sie möglicherweise auch die Länge jedes Frames speichern.


Bildnummern sind möglicherweise keine gute Referenz, da die Wiedergabe möglicherweise mit einer anderen Bildrate als das Live-Spiel ausgeführt wird.
Ben S

5
@ Ben: Die Framerate macht keinen Unterschied, da die Frame-Nummern immer noch gleich sind. Dies ist die richtige Antwort.
BlueRaja - Danny Pflughoeft

14
Grafische Frames und Engine-Frames (oder Iterationen) sind nicht unbedingt gleich. In vielen älteren Spielen wurde die Engine in einer Master-Schleife mit der gleichen Geschwindigkeit wie die Grafik aktualisiert. Bei modernen Engines können die Grafiken häufig so schnell aktualisiert werden, wie es die GPU zulässt, wobei die Engine auf dem Niveau tickt, das für eine gute, konsistente Auflösung der Spieldynamik erforderlich ist (häufig eine Physik-Engine).
Dan Bryant

3
@iamgopal: Wenn Sie den Status des Pseudozufallszahlengenerators kennen, ist dieses Problem bereits gelöst. Eine andere Methode kann darin bestehen, Zufallszahlen als eine andere Form der Eingabe zu behandeln und diese neben Tastendrücken und dergleichen zu speichern.
Kylotan

1
Ich möchte darauf hinweisen, dass dieser Ansatz erfordert, dass Ihre Spiel-Engine deterministisch ist und mit einem festen Zeitschritt arbeitet. Ich glaube, alle RTS-Spiele von Blizzard wurden auf diese Weise entwickelt. Nicht deterministische Spiele würden zusätzliche Synchronisationsdaten enthalten, um auf lange Sicht Konsistenz zu gewährleisten.
John Leidegren

28

Starcraft und Starcraft: Brood War hatten eine Wiederholungsfunktion. Nach Abschluss eines Spiels können Sie die Wiederholung speichern, um sie später anzuzeigen. Während der Wiedergabe können Sie durch die Karte scrollen und auf Einheiten und Gebäude klicken, ohne deren Verhalten zu ändern.

Ich erinnere mich, dass ich einmal eine Wiederholung eines Spiels gesehen habe, das im ursprünglichen Spiel gespielt wurde, aber die Wiederholung wurde in Brood War angesehen. Für Unbekannte enthält Brood War alle ursprünglichen Einheiten und Gebäude sowie eine Vielzahl neuer. Im ursprünglichen Spiel hatte der Spieler den Computer besiegt, indem er Einheiten erstellt hatte, die der Computer nicht leicht kontern konnte. Als ich die Wiederholung in Brood War spielte, hatte der Computer Zugriff auf verschiedene Einheiten, die er erstellt und verwendet hat, um den Spieler zu besiegen. Die exakt gleiche Wiederholungsdatei führte also zu einem anderen Gewinner, je nachdem, welche Version von Starcraft die Datei abspielte.

Ich fand das Konzept immer faszinierend. Es scheint, dass die Wiedergabefunktion funktioniert, indem alle Eingaben des Players aufgezeichnet wurden, und angenommen wurde, dass der Computer jedes Mal genau auf diese Reize reagiert. Wenn die Spielereingaben in den ursprünglichen Starcraft-Replayer eingegeben wurden, lief das Spiel genau so ab wie im ursprünglichen Match. Als genau dieselbe Eingabe in den Brood War-Replayer eingespeist wurde, reagierte der Computer anders, schuf stärkere Einheiten und gewann das Spiel.

Denken Sie daran, wenn Sie eine Wiederholungs-Engine schreiben.


6
+1: Sehr interessant. Davon hatte ich noch nie gehört. Bietet einen guten Einblick in die Entwicklung.
Steven Evers

18

Es gibt zwei Hauptmethoden:

  1. Speichern von Ereignissen (z. B. Spieler- / Ai-Aktionen) - genau wie Sie sagen.
  2. Speicherstatus (vollständiger Spielstatus, z. B. Positionen von Objekten, in aufeinanderfolgenden Momenten).

Es hängt davon ab, was Sie tun möchten. Manchmal ist das Speichern von Ereignissen besser, da dies normalerweise viel weniger Speicher benötigt. Auf der anderen Seite ist es besser, Status zu speichern, wenn Sie Wiederholungen bereitstellen möchten, die mit unterschiedlichen Geschwindigkeiten und von unterschiedlichen Startpunkten aus abgespielt werden können. Beim Speichern von Status können Sie auch entscheiden, ob Sie sie nach jedem Ereignis oder nur 12 oder 25 Mal pro Sekunde speichern möchten. Dies kann die Größe Ihrer Wiedergabe verringern und das Zurückspulen / Vorspulen erleichtern.

Beachten Sie, dass "Zustand" nicht grafischen Zustand bedeutet. Mehr so ​​etwas wie Einheitenpositionen, Zustand der Ressourcen und so weiter. Dinge wie Grafiken, Partikelsysteme usw. sind normalerweise deterministisch und können als "Animation X, Zeit Y: Z" gespeichert werden.

Manchmal werden Wiederholungen als Anticheating-Schema verwendet. Dann ist das Speichern von Ereignissen hier wahrscheinlich das Beste.


10

Technisch gesehen sollten Sie Ihre Engine so schreiben, dass sie deterministisch ist, das ist keine Zufälligkeit. Angenommen, ein Charakter im Spiel zielt auf den Arm eines Gegners und feuert eine Waffe ab, dann sollte der Gegner in allen Fällen den gleichen Schaden erleiden.

Angenommen, eine Bombe detoniert am Ort X, sollten die durch diese Explosion erzeugten Partikel immer zum gleichen visuellen Ergebnis führen. Wenn Sie Zufälligkeit benötigen, erstellen Sie eine Reihe von Zufallszahlen, wählen Sie einen Startwert aus, wenn das Spiel gespielt wird, und speichern Sie diesen Startwert in der Wiederholung.

Im Allgemeinen ist Zufälligkeit in einem Spiel eine schlechte Idee. Selbst für Dinge wie Multiplayer können Sie nicht die Hälfte Ihrer Spieler in der Lage sein, eine Explosion zu sehen, während die anderen dies nicht können, nur weil sie nicht den richtigen Zufallswert erhalten haben.

Machen Sie alles deterministisch, und es sollte Ihnen gut gehen.


1
Was ist mit KI? Ist KI nicht zufällig?
Jesse Jashinsky

18
Das ist wirklich nicht nötig. Verwenden Sie für alle zufälligen Ereignisse gesetzte Pseudozufallszahlen und speichern Sie den Startwert in der Wiedergabedatei. Auf diese Weise werden bei der Wiedergabe dieselben "Zufallszahlen" generiert.
Ben S

13
-1 für ein klares Missverständnis darüber, wie "Zufälligkeit" in Computern funktioniert
BlueRaja - Danny Pflughoeft

10
ähm ... nein ... ich bin mir vollkommen bewusst, dass es keine "wahre" Zufälligkeit gibt. Die meisten Leute versuchen jedoch, dies zu umgehen, indem sie ihren zufälligen Startwert auf etwas wie die Systemzeit setzen. Ich sage jedoch, dass so etwas nicht getan werden sollte. Es ist mir egal, ob er die System-API oder eine vordefinierte Tabelle mit Zufallszahlen verwendet. Was ich ursprünglich gesagt habe, war richtig. Jede Funktion in seinem Motor sollte basierend auf ihren Eingaben das gleiche Ergebnis liefern. Zeit sollte niemals ein Faktor sein.
Timothy Baldridge

2
Wenn Partikel in keiner sinnvollen Weise mit der Spielmechanik interagieren, spielt es keine Rolle, ob die RNGs für sie unterschiedlich sind. Dies würde im Fall einer netzwerk-synchronisierten Simulation helfen (wie es bei den meisten RTS-Spielen und vielen anderen Spielgenres der Fall ist), da die Simulation etwas weniger muss, um jeden Frame zu synchronisieren (die Partikeleffekte werden nur auftreten) einzeln aktualisiert).
RCIX

10

Gehen Sie angesichts des Ausgangszustands und einer Reihe von Aktionen mit Zeitstempeln einfach die Sequenz durch, da die aufgezeichneten Aktionen wiederholt werden sollen.

Verwenden Sie gesetzte Pseudozufallszahlen und speichern Sie den Startwert in der Wiedergabedatei , damit zufällige Ereignisse genau gleich wieder auftreten .

Solange Sie denselben Algorithmus verwenden, um die Zufallszahlen aus dem Startwert zu generieren, können Sie alle Ereignisse so neu erstellen, wie sie im Live-Spiel aufgetreten sind, ohne vollständige Schnappschüsse des Spielstatus zu benötigen.

Dies erfordert, dass Wiederholungen nacheinander angesehen werden , aber das ist für Spielwiederholungen ziemlich normal (siehe Starcraft 2). Wenn Sie den wahlfreien Zugriff auf die Zeitachse zulassen möchten, können Sie in festgelegten Intervallen (z. B. jede Minute) vollständige Status-Snapshots erstellen, um mit einer festgelegten Granularität über die Zeitleiste zu springen.


Wenn Sie jede bestimmte Anzahl von Sekunden (z. B. 5 oder 10) erneut setzen, ist es einfach genug, in Ihrem Wiederholungs-Stream aufzuzeichnen und auch vorwärts oder rückwärts zu springen (im Wesentlichen zu PRNG "Keyframes").
Wedge

7

NVidia PhysX (eine Physik-Simulations-Engine, die häufig in Spielen verwendet wird) kann den gesamten Zustand der physischen Szene im Laufe der Zeit aufzeichnen. Dies beinhaltet alle treibenden Eingaben von der Spiel-Engine, was bedeutet, dass Sie keine Zufallszahlen-Seeds verfolgen müssen, wie andere vorgeschlagen haben. Wenn Sie diesen Szenendump ausführen, können Sie ihn in einem externen Tool (von NVidia bereitgestellt) wiedergeben. Dies ist sehr praktisch, um Probleme mit Ihren physischen Modellen aufzuspüren. Sie können jedoch auch denselben Physik-Stream verwenden, um Ihre Grafik-Engine zu steuern, wodurch Sie eine normale Kamerasteuerung erhalten, da nur die Physik aufgezeichnet wurde, die die Grafiken steuert. In vielen Spielen schließt dies die Partikeleffekte ein (PhysX enthält einige sehr ausgefeilte Partikelsysteme). Was den Sound betrifft, schätze ich, dass er wörtlich (als Soundstrom) aufgezeichnet wurde, aber ich '


4

Ihre ursprüngliche Idee ist richtig, und für die wirklich komplexen Effekte werden sie nicht ausschließlich in Erinnerung behalten. Beispielsweise speichert das Warcraft 3-Wiedergabesystem nicht den Status von Animationen oder Partikeleffekten bei zufälligen Effekten usw. Außerdem können die meisten Dinge von einem Startpunkt aus deterministisch berechnet werden, so für die meisten Systeme Wenn Sie Zufallsvariablen verwenden (z. B. eine Partikelexplosion, die einen zufälligen Versatz ergibt), benötigen Sie lediglich die Zeit des Effekts und den zufälligen Startwert. Sie können den Effekt dann erneut generieren, ohne wirklich zu wissen, wie er am Ende aussehen wird. Sie wissen, dass er einen deterministischen Codepfad durchläuft.

Wenn Sie rein konzeptionell darüber nachdenken, um eine Zeitleiste mit Ereignissen wiederzugeben, benötigen Sie lediglich die Benutzeraktionen. Das Programm reagiert genauso, außer bei Zufallsvariablen. In diesem Szenario können Sie entweder die Zufälligkeit ignorieren (spielt es WIRKLICH eine Rolle, ob die Effekte genau gleich aussehen, oder können sie zufällig neu generiert werden) oder den Startwert speichern und die Zufälligkeit vortäuschen.


3

Wirf meine zwei Pence rein.

Je nachdem, was Sie möchten, kann die Wiedergabe über erfolgen

  1. Videopuffer aufnehmen und später wiedergeben,
  2. Erfassen des Objektstatus in jedem Frame und spätere Wiedergabe

Meistens möchten die Leute eine interaktive Wiedergabe, also ist 2. der richtige Weg. Abhängig von Ihren Einschränkungen gibt es dann verschiedene Möglichkeiten, diesen Prozess zu optimieren

  • Stellen Sie sicher, dass das System eine deterministische Simulation * ist, sodass jede Eingabe eine konsistente und erwartete Ausgabe generiert
  • Wenn Zufälligkeit erforderlich ist, stellen Sie sicher, dass Zufallszahlen zu einem späteren Zeitpunkt genau reproduziert werden können [siehe Seeding mit Pseudo-Zufallszahlengeneratoren PRNG oder verwenden Sie zufällige Zufallsmengen]
  • Teilen Sie Spielelemente in "mechanische" und "ästhetische" Elemente. Mechanische Elemente beeinflussen das Ergebnis (z. B. Umfallen der Säule und Blockieren des Pfades), ästhetische Elemente dienen der Darstellung und beeinflussen keinen Entscheidungsprozess im System [z. B. visuelle Partikeleffekte wie Funken].

Es ist wirklich ein faszinierendes Thema. Ich erinnere mich, dass ein Starttitel für die ursprüngliche Xbox Wreckless eine gute Wiedergabefunktion hatte. Leider hat die Wiederholung bei mehr als einer Gelegenheit versagt;)

oh yeah, wie könnte jemand Blinx Time Sweeper vergessen ! großartige interaktive Wiederholung, die in die eigentliche Spielmechanik integriert wurde!


* = Anscheinend gibt es einige Kommentare zum Zeitschritt. Ich benutze "Simulation" hier, um diese Funktion zu erfassen. Im Kern muss Ihr Motor in der Lage sein, diskrete Zeitrahmen zu erzeugen. Selbst wenn die Verarbeitung eines Wiederholungsrahmens länger oder kürzer dauert als der des Originals, muss das System erkennen, dass das gleiche Delta vergangen ist. Dies bedeutet, dass der Frame-Zeitschritt mit jedem aufgezeichneten Eingang aufgezeichnet und dieses Delta Ihrer Motortaktung zugeführt wird.


2

Vielleicht könnten Sie einfach einen Stapel von Befehlen speichern, die von jedem Spieler gesendet werden. Anstatt zu speichern, dass eine Bombe zu einem bestimmten Zeitpunkt explodiert oder dass ein bestimmtes Auto zerstört wird, speichern Sie einfach die von jedem Spieler gesendeten Tastendrücke. In der Wiederholung simulieren Sie das Spiel einfach so, wie es mit diesen Druckmaschinen geschehen wäre. Ich habe das Gefühl, dass dies das Potenzial hat, weniger Platz zu beanspruchen, aber ich habe noch nie an einem solchen Wiedergabesystem gearbeitet.

Interessante Frage. Mich würde interessieren, wie es in professionellen Spielen gemacht wird.


2

Dan Bryant

Ferner würde das Aufzeichnen von zufälligen Startwerten für die Rückspulunterstützung nicht ausreichen, da das zufällige Fortschreiten kein reversibles Verfahren ohne besondere Unterstützung in der gesamten Logik ist, die auf der Zufälligkeit beruht. Es ist flexibler, die Ergebnisse der Zufallsoperationen als Teil des Ereignisstroms aufzuzeichnen.

Genau das habe ich mir zuerst gedacht, als ich herausfinden wollte, wie sie es geschafft haben, damit das Spiel jedes Mal gleich bleibt. Bei Doom dachte ich darüber nach, wie zufällig die Dreharbeiten verliefen: D. Speichern Sie jede Zufallszahl, die verwendet wurde, ich fand heraus, dass es eine Lösung sein könnte. Das war, bevor ich auf ein PDF-Papier über die Crysis-Technologie stieß. Einige Texturen rauschen dort und Gras- oder Baumdisposition scheinen Pseudorandomisierung mit festem reversiblem Samen zu verwenden, um es so zu machen, dass Sie keine veränderte Disposition von Lärm, Bäumen und Gras sehen, wann immer Sie schauen!

Vermeiden Sie gleichzeitig, Millionen von Bäumen und Grasschächten zu lagern. Anscheinend kann eine Pseudozufallsfolge jederzeit dieselbe wiedergeben, da die Logik festgelegt ist, um nur eine gefälschte statistisch zufällige Folge von Zahlen zu erstellen.


Wenn Sie Dan darauf aufmerksam machen möchten, fügen Sie unter seinem Beitrag einen Kommentar hinzu - andernfalls wird er ihn wahrscheinlich nicht sehen.
Halfer

Könnte es sein, dass ich nur ein Gast bin, aber ich konnte keine Funktion "Kommentar hinzufügen" im übergeordneten Beitrag sehen, antwortete Dan, geschweige denn Dans Antwort. Ich habe gesehen, dass es eine Funktion zum Verbessern der Bearbeitung gibt, auch für Posts, die nicht meine sind, aber wie funktioniert das?
Antonym

Ah, gute Frage! Hier brauchen Sie anscheinend 50 Wiederholungspunkte, um andere Fragen oder Antworten als Ihre eigenen zu kommentieren - ich entschuldige mich. 50 ist jedoch sehr einfach zu bekommen - nur ein paar nützliche Beiträge werden dies normalerweise erreichen. Ja, Sie können die Fragen und Antworten anderer Personen bearbeiten. Ihre Änderungen werden jedoch von anderen Personen bis zum Jahr 2000 überprüft. Hier finden Sie Ihre Berechtigungstabelle .
halfer

1

Das Problem einer konsistenten Wiederholung ist das gleiche (na ja, einfacher) wie bei einem konsistenten Multiplayer-Spiel.

Wie bereits erwähnt, werden Wiederholungen in RTS-Spielen gespeichert, indem alle Eingaben aufgezeichnet werden (was Auswirkungen hat. Scrollen hat keine Auswirkungen). Der Mehrspielermodus überträgt auch alle Eingaben

Das Aufzeichnen aller Eingaben ist nicht nur eine Vermutung - es gibt eine Bibliothek zum Lesen von Warcraft3-Wiederholungen, die dies enthüllt.

Die Eingabe enthält Zeitstempel für diese Antwort.


Nein, es ist nicht dasselbe (oder einfacher) wie ein konsistentes MP-Spiel. Wenn Sie MP spielen, erfordern Spiele normalerweise, dass jeder die gleiche Version des Spiels hat, was bei gespeicherten Sitzungen nicht unbedingt der Fall ist (da dies möglicherweise mit einer älteren Version des Spiels gespeichert wurde). Dies ist besonders wichtig, wenn einer der Spieler ein KI-Gegner ist. Stellen Sie sich vor, Sie spielen ein Spiel erneut, bei dem eine Einheit in einer neueren Version nur einen Angriffspunkt mehr hat als in der aufgezeichneten Version. Dies könnte zu einem völlig anderen Ergebnis führen.
Drakon

-1

Ich würde glauben, dass das Spiel in bestimmten Schritten eine Momentaufnahme des Zustands von allem machen würde (ALLES). Wenn dann die Wiedergabe stattfindet, kann die einfache Verwendung der linearen Interpolation verwendet werden, um die "Löcher" zu füllen. Zumindest denke ich, dass es so gemacht wird.

Sie haben Recht, dass das Aufzeichnen der Eingänge unzuverlässig wäre / nicht den gleichen Ausgang garantiert. Das Spiel muss definitiv den Zustand aller Objekte (oder zumindest der wichtigen) verfolgen.


2
Nein, wenn Sie dieselben Eingaben eingeben, erhalten Sie genau das gleiche Ergebnis wie beim ersten Mal. Sie müssen nur sicherstellen, dass Sie das richtige Timing erhalten, indem Sie die Eingabe zwischen denselben Frames einspeisen, in denen sie ursprünglich empfangen wurde. Das regelmäßige Speichern des gesamten Spielstatus kann eine enorme Menge an Speicher erfordern und auch zu inkonsistenten Ergebnissen führen.
Peter Ruderman

@Peter, "das Füttern der gleichen Eingaben führt zu genau dem gleichen Ergebnis": nein. In vielen Spielen gibt es ein zufälliges Element, das bei jeder Wiederholung unterschiedlich sein kann. Sie müssen mehr als die Eingaben im Auge behalten.
Houbysoft

Das ist richtig. Sie müssen auch die Samen Ihrer PRNGs speichern (siehe meine Antwort auf diese Frage).
Peter Ruderman

1
Ich weiß, es ist leistungs- und speicherintensiv, aber wenn Sie eine Kleinigkeit in Bezug auf die Eingabe oder die Zufallsgeneratoren verpassen ... oder wirklich irgendetwas, wird die Wiedergabe mit einer schrecklichen Tangente ablaufen!
Bob Fincheimer

@BlueRaja, Bobs Idee für einen Speicher-Snapshot ist nicht unbedingt so weit hergeholt, obwohl eine gute Engine Status-Deltas aufzeichnen kann, anstatt den gesamten Speicher für jede Iteration zu codieren. Dies ist auf Motorebene wahrscheinlich einfacher zu unterstützen. Ferner würde das Aufzeichnen von zufälligen Startwerten für die Rückspulunterstützung nicht ausreichen, da das zufällige Fortschreiten kein reversibles Verfahren ohne besondere Unterstützung in der gesamten Logik ist, die auf der Zufälligkeit beruht. Es ist flexibler, die Ergebnisse der Zufallsoperationen als Teil des Ereignisstroms aufzuzeichnen.
Dan Bryant
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.