Ich arbeite derzeit an einem ziemlich einfachen Multiplayer-Plattformer. Ich habe eine ganze Reihe von Artikeln über die Techniken gelesen, mit denen die Latenz verborgen wird, aber ich kann mich immer noch nicht mit bestimmten Konzepten auseinandersetzen. Ich finde das Thema sehr interessant und probiere gerne selbst Ideen aus, aber ich denke, dass es für meine Frage effizienter ist, gamedev stackexchange zu fragen. Ich werde mein Bestes geben, um meine aktuelle Situation zu beschreiben und welche Frage sich dabei stellte.
Im Moment möchte ich nur einen einzelnen Spieler mit dem Server synchronisieren. Theoretisch ging ich davon aus, dass ein Spieler mit clientseitiger Vorhersage keine Serverkorrekturen benötigt, da es keine externen Faktoren gibt, die seine Bewegung beeinflussen. Daher hat mein Prototyp derzeit nur einen Player mit einem Server synchronisiert, ohne dass Serverkorrekturen gesendet werden.
Wenn Sie mit dem Networking von Spielen vertraut sind, können Sie die Kontextabschnitte überspringen, obwohl ich auf dem Weg möglicherweise auch etwas falsch gemacht habe.
Die Client-Schleife (einmal pro Frame, einmal alle ~ 16,67 ms)
Die vereinfachte Client-Schleife sieht folgendermaßen aus:
Suchen Sie nach lokalen Eingaben (WASD) und verpacken Sie diese als Aktionen (z
Type=MoveLeft, Time=132.0902, ID=15
. B. ). Wir behalten die verpackten Aktionen bei, um sie später zu senden. Außerdem wenden wir die gewünschte Aktion direkt auf die lokale Physiksimulation des Spiels an. Wenn wir zum Beispiel eineMoveLeft
Aktion haben, üben wir eine Kraft nach links auf die Geschwindigkeit des Spielers aus.Aktivieren Sie diese Option, um Aktionen zu senden. Um zu verhindern, dass die Bandbreite des Clients missbraucht wird, senden Sie die gepackten Aktionen nur in bestimmten Intervallen (z. B. 30 ms).
Übernehmen Sie Serveränderungen. Ab einem bestimmten Punkt werden die vom Server empfangenen Deltas und Korrekturen verarbeitet und auf die lokale Simulation des Spiels angewendet. Für diese spezielle Frage wird dies nicht verwendet.
Aktualisieren Sie die lokale Physik. Führen Sie die Physikschleife auf dem Hauptplayer aus. Grundsätzlich erfolgt hierdurch die clientseitige Vorhersage der Bewegung des Spielers. Dies erhöht die Schwerkraft der Geschwindigkeit des Spielers, wendet die Geschwindigkeit des Spielers auf seine Position an, behebt Kollisionen auf dem Weg usw. Ich sollte angeben, dass die Physiksimulation immer mit festen Delta-Sekunden ausgeführt wird (abhängig von den tatsächlichen Delta-Sekunden mehrmals aufgerufen). .
Ich überspringe einige spezifische Details zur Physik und zu anderen Abschnitten, da ich der Meinung bin, dass sie für die Frage nicht erforderlich sind. Sie können mich jedoch gerne informieren, ob sie für die Frage relevant sind.
Die Serverschleife (alle 15ms)
Die vereinfachte Serverschleife sieht folgendermaßen aus:
Aktionen handhaben. Suchen Sie nach empfangenen Aktionspaketen von Clients und wenden Sie diese auf die Serverphysik-Simulation an. Zum Beispiel könnten wir 5
MoveLeft
Aktionen erhalten und die Kraft 5 Mal auf die Geschwindigkeit anwenden . Es ist wichtig zu beachten, dass ein ganzes Aktionspaket in einem "Frame" ausgeführt wird , im Gegensatz zum Client, auf den es angewendet wird, sobald die Aktion ausgeführt wird.Aktualisiere die Spielelogik. Wir aktualisieren die Spielphysik, bewegen Spieler und beheben Kollisionen usw. Wir packen auch alle wichtigen Ereignisse ein, die später an Spieler gesendet wurden (z. B. die Gesundheit eines Spielers ist gesunken, ein Spieler ist gestorben usw.).
Korrekturen senden. Wir senden regelmäßig (z. B. alle 35 ms) Deltas an andere Spieler (z. B. Spielerpositionen, Gesundheit usw.), wenn diese sich kürzlich geändert haben. Dieser Teil ist derzeit nicht implementiert, da ich möchte, dass die Simulation eines einzelnen Players ohne Korrekturen auf Client und Server dieselben Ergebnisse liefert, um sicherzustellen, dass die clientseitige Vorhersage einwandfrei funktioniert.
Das Problem
Das derzeitige System funktioniert unter einfachen Umständen einwandfrei, und ich war erfreut zu sehen, dass es mit einfachen horizontalen Bewegungen sehr ähnliche Ergebnisse lieferte (die Ungenauigkeiten sind meiner Meinung nach auf Gleitkomma-Präzisionsfehler zurückzuführen):
Bitte ignorieren Sie die Prototypgrafiken. Weißes Rechteck = Spieler, Rote Rechtecke = Hindernisse, Blau = Hintergrund
Ich erhalte jedoch Synchronisierungsfehler, nachdem ich zeitkritische Bewegungen ausgeführt habe, z. B. Springen und Bewegen in der Nähe eines isolierten Hindernisses:
Theoretisch würde ich erwarten, dass beide immer zu den gleichen Ergebnissen führen, da der Klient keine externen Faktoren hat, die seine Position beeinflussen. In der Praxis glaube ich das Problem zu verstehen.
Da das Springen um ein solches Hindernis sehr stark vom Timing des Spielers abhängt, wirken sich kleine Abweichungen davon, wann die Geschwindigkeit auf die Position angewendet wird, auf das Ergebnis aus (z. B. könnte sich der Kunde gerade rechtzeitig entfernen, um eine Kollision mit dem Spieler zu vermeiden Hindernis, während der Server dies tun würde, da er später das gesamte Aktionspaket empfängt und für eine kurze Zeit auf dem Hindernis stecken bleibt und das Endergebnis ändert). Der Unterschied zwischen dem Umgang des Clients und des Servers besteht hauptsächlich darin, dass der Client alle seine Aktionen sofort ausführt, während der Server sie alle in großen Mengen ausführt, wenn er sie empfängt.
Die Frage
Dieser lange Kontext führt schließlich zu meiner Frage (danke, dass Sie so weit gelesen haben): Ist es normal, Serverkorrekturen zu verlangen, selbst wenn nur ein Spieler mit dem Server synchronisiert ist, oder sollte ich bestimmte Techniken verwenden, um eine Desynchronisation in zeitkritischen Situationen zu vermeiden ?
Ich habe über bestimmte mögliche Lösungen nachgedacht, mit denen ich einige weniger vertraut bin:
Implementieren Sie die Serverkorrektur. Nehmen Sie einfach an, dass dies normales Verhalten ist, und korrigieren Sie Fehler, sobald sie auftreten. Ich wollte es trotzdem implementieren, aber ich wollte nur sicherstellen, dass das, was ich bisher getan habe, akzeptabel ist.
Verwenden Sie die bereitgestellte Client-Zeit, um die gewünschten Aktionen anzuwenden. Ich denke, dies wäre ähnlich wie eine Verzögerungskompensation, bei der man "in der Zeit zurückgehen" und nach Bewegung suchen muss. Ähnlich wie beim Anwenden von Serverkorrekturen gehen Sie in die Vergangenheit zurück und wenden die nächsten Aktionen danach erneut an. Ich mag die Idee wirklich nicht. Es sieht komplex und ressourcenintensiv aus und erfordert das Vertrauen in die vorgegebene Zeit des Kunden (obwohl ich vorhabe, wirklich zu überprüfen, ob die Zeit relativ legitim aussieht).
Fragen Sie GameDevelopment StackExchange nach einer großartigen neuen Idee, mit der alle meine Probleme behoben werden können.
Ich fange gerade erst in der Welt des Game Networking an. Sie können also gerne eines der oben genannten Konzepte korrigieren / kritisieren / beleidigen oder Ideen / Ressourcen angeben, die mir auf meiner Reise in die wunderbare Welt des Networking helfen könnten. Verzeihen Sie mir, wenn ich meine Antwort woanders hätte finden können, bin ich dabei gescheitert.
Vielen Dank für Ihre wertvolle Zeit.
quelle
Antworten:
In solchen Fällen ist es möglicherweise besser, wenn Sie den Kunden leicht autorisieren lassen. Für solch präzise Steuerungen ist es äußerst unwahrscheinlich, dass Sie selbst bei wirklich fortschrittlicher Korrektur und Vorhersage ein gutes Verhalten erzielen.
Der Client muss vom Senden von Nachrichten "Ich bin gesprungen" bis zum Senden von Nachrichten "Ich bin zum Zeitpunkt T von X, Y gesprungen" reichen. Der Server überprüft dann, ob sich der Standort in unmittelbarer Nähe zu dem befindet, von dem er glaubt, dass der Spieler zum Zeitpunkt T war (was Sie in der Vergangenheit auf eine relativ kleine Zeit beschränken können), um sich vor Betrug zu schützen, und simuliert dann den Sprung von der Position des Clients geschickt. Der Server korrigiert den Client nur, wenn er weit aus dem Ruder gelaufen ist (normalerweise aufgrund von Verzögerungen oder Ähnlichem).
Diese Art von Technik wird in Verbindung mit Korrektur und Interpolation verwendet, damit sich das Spiel auf dem lokalen Client ansprechend anfühlt und für Remote-Clients reibungslos aussieht.
quelle
~max(RTT)
in der Vergangenheit eine Art Snapshot-Verlauf für Server-Ticks, aber ob Sie dies speziell für Ihr Spiel benötigen, weiß ich nicht. Dies kann noch praktischer für Spiele im Shooter-Stil sein, bei denen Sie auch eine gewisse Treffer- / Schusserkennung auf dem Client durchführen möchten und nicht nur wissen müssen, wo sich ein Spieler vor 46 ms befand, sondern auch, wo sein Ziel vor 46 ms war und wo Verschieben von Okklusionsplattformen wo.