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.
quelle
Antworten:
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.
quelle
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.
quelle
Es gibt zwei Hauptmethoden:
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.
quelle
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.
quelle
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.
quelle
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 '
quelle
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.
quelle
Wirf meine zwei Pence rein.
Je nachdem, was Sie möchten, kann die Wiedergabe über erfolgen
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
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.
quelle
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.
quelle
Dan Bryant
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.
quelle
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.
quelle
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.
quelle