Physiksimulation auf Client und Server ausführen?

13

Ich implementiere einen Multiplayer-Asteroiden-Klon, um mehr über die Client / Server-Netzwerkarchitektur in Spielen zu erfahren. Ich habe Zeit damit verbracht, die Veröffentlichungen von GafferOnGames und Valve über deren Client / Server-Technologie zu lesen. Ich habe Probleme mit zwei Konzepten.

  1. Derzeit besitze ich einen autoritativen Spieleserver, der mit box2d die Physik simuliert und etwa 20 Mal pro Sekunde den Status der Welt an Kunden sendet. Jeder Client verfolgt die letzten erhaltenen Snapshots und wechselt zwischen zwei Status, um die Bewegung von Sprites auszugleichen. Es ist jedoch nicht so glatt. Es kann für eine Weile glatt sein, dann ruckelt es ein bisschen, dann wieder glatt usw. Ich habe sowohl TCP als auch UDP ausprobiert, beide sind ungefähr gleich. Irgendeine Idee, was mein Problem sein könnte? (Hinweis: Ich habe dies zuerst für Einzelspieler implementiert und die Sprite-Bewegung ist mit 60 fps perfekt flüssig, wenn die Physik-Welt nur 20 Mal pro Sekunde aktualisiert wird.)

  2. Um das erste Problem zu lösen, dachte ich, der Client sollte vielleicht auch eine Box2D-Simulation ausführen und einfach die Positionen seiner Sprites aktualisieren, damit sie mit den Server-Snapshots übereinstimmen, wenn sie nicht übereinstimmen. Ich dachte, dies könnte reibungsloser sein, da meine Single-Player-Implementierung reibungslos verläuft. Ist das eine gute Idee?

    Auch wenn das oben genannte Problem nicht behoben werden kann, ist es für die clientseitige Vorhersage erforderlich? Wenn ein Spieler beispielsweise versucht, sein Schiff zu bewegen, wie kann er dann feststellen, ob er einen Asteroiden, eine Mauer oder ein feindliches Schiff ohne physikalische Simulation getroffen hat? Es scheint, als würde ihr Schiff das Objekt passieren, mit dem es kollidieren soll, bevor sie einen Schnappschuss vom Server erhalten, der besagt, dass sie das Objekt getroffen haben.

Vielen Dank!

Venesectrix
quelle

Antworten:

10

Führen Sie die Simulation auf jeden Fall sowohl auf den Clients als auch auf dem Server aus. Alles andere hat zu lange Latenzzeiten. Sie sollten sicherstellen, dass die Simulationen übereinstimmen, indem Sie Objekte in derselben Reihenfolge einfügen, einen festen Zeitschritt verwenden und Zeigervergleich vermeiden. Ich habe dies mit Box2D noch nicht ausprobiert, aber es ist im Allgemeinen möglich, in einer Physiksimulation auf allen Maschinen dasselbe Verhalten zu erzielen. Alle Berechnungen basieren in der Regel auf IEEE 754-Gleitkommazahlen (binary32 floats), und ihr Verhalten ist für Operationen streng definiert, um nur +-*/einige zu nennen. Sie müssen vorsichtig sein sin,cosund die mag hart, da sie sich zwischen den Laufzeiten unterscheiden können (dies ist besonders wichtig, wenn für mehrere Plattformen entwickelt wird). Stellen Sie außerdem sicher, dass Sie eine strikte Einstellung für Float-Optimierungen in Ihrem Compiler verwenden. Sie können weiterhin Objekte synchronisieren, indem Sie regelmäßig den Status von Objekten vom Server senden. Aktualisieren Sie nicht, es sei denn, der Unterschied ist größer als ein Schwellenwert, um unnötiges Ruckeln zu vermeiden.

Ein Problem, das mir in den Sinn kommt, ist die Erstellung neuer Objekte und wie sich dadurch die Simulation zwischen Clients ändert. Eine Möglichkeit, dies zu beheben, besteht darin, den Server alle Objekte erstellen zu lassen. Wenn der aktuelle Zeitschritt ist t, plant der Server ein Objekt, das hinzugefügt werden soll t+d. Auf diese Weise kann eine Liste neuer Objekte mit hinzuzufügenden Objekten und dem Zeitpunkt, zu dem sie hinzugefügt werden müssen, auf allen Clients verwaltet und vom Server rechtzeitig aktualisiert werden. Wenn des groß genug ist, minimieren Sie das Risiko unterschiedlicher Ergebnisse. Wenn Sie mit Unterschieden wirklich nicht umgehen können, können Sie einen Client zwingen, für einen bestimmten Zeitschritt auf Informationen über neue Objekte zu warten, bevor Sie diesen Zeitschritt simulieren.

Rasmus
quelle
Vielen Dank für Ihre Antwort. Ich glaube nicht, dass box2d garantiert auf verschiedenen CPUs die gleichen Ergebnisse erzielt. Dies wäre das Szenario für uns, da wir ein Desktop-Spiel schreiben. Ich würde hoffen, dass die Unterschiede mit regelmäßigen Updates von einem autorisierenden Server geringfügig und leicht zu korrigieren sind, aber ich habe es nie versucht.
Venesectrix
Erin Catto ist der Ansicht, dass der Versuch, den gesamten Zustand mehrerer Box2D-Welten synchron zu halten, ein Kampf ohne Erfolg ist ( box2d.org/forum/viewtopic.php?f=3&t=8462 )
Pavel,
Die Anweisung "IEEE 754 binary32 floats [..] Verhalten ist streng definiert für Operationen wie +-*/" ist völlig falsch. Alle diese Operationen in IEEE-754 können je nach Implementierung variieren. Sehen Sie hier und hier für weitere Informationen.
BlueRaja - Danny Pflughoeft
1
Nein, das ist völlig richtig. Das Problem, das Ihr Link beschreibt, hängt mit verschiedenen Modi der x87-CPU und Implementierungen von Transzendenten zusammen. IEEE 754 binary32 ist für die Grundoperationen genau definiert. Es liegt an Ihnen, die richtigen Modi einzustellen und die richtigen Anweisungen zu verwenden, damit der Standard eingehalten wird. Die einfache Verwendung von SSE-Anweisungen und nicht der x87-FPU hilft sehr.
Rasmus
4

Es sieht wahrscheinlich nicht so gut aus, da die Interpolation zwischen ihnen davon abhängt, dass immer der nächste Datensatz zur Interpolation zur Verfügung steht. Dies bedeutet, dass bei einer kurzen Verzögerung alles warten muss, um aufzuholen.

Es gibt einen alten Artikel in GameDev über die Verwendung von kubischen Splines, um die Position eines Objekts nach dem Punkt vorherzusagen, an dem Sie zuletzt Daten dafür hatten. Was Sie dann tun, ist, diese Position zu verwenden und dann den Spline anzupassen, wenn Sie neue Daten erhalten, um die neue Position zu berücksichtigen. Es ist wahrscheinlich auch viel billiger als das Ausführen einer zweiten Physiksimulation, und Sie müssen sich nicht entscheiden, wem Sie vertrauen, da Sie den Client, der es erstellt, explizit implementiert haben. :)

Matt Kemp
quelle
Dies könnte der Fall sein. Was ich versuche, ist zu verzögern, bis ich 3 Schnappschüsse vom Server erhalten habe. An dem Punkt, an dem ich von Schuss 1 zu Schuss 2 lerpiere. Dann von Schuss 2 zu Schuss 3. Wenn ich irgendwann ein Paket verpasse, kann ich von 1 zu 3 lerpieren, anstatt von 1 zu 2, wenn das Sinn macht. Ich kann dies jedoch noch nicht richtig implementieren. Danke für den Link zum Artikel!
Venesectrix
1

Ich habe selbst ähnliche Sachen gemacht und Box2D nur auf den Clients ausgeführt. Ich habe es so gemacht, dass der Client seine eigene Simulation so gut wie von selbst ausführt und die aktuelle Geschwindigkeit (und Rotation) für jedes Synchronisierungspaket an den Server sendet. Der Server sendet diese Informationen dann an andere Spieler, die die neu empfangenen Geschwindigkeiten auf die replizierten Entitäten setzen. Es war sehr reibungslos, ohne merkliche Unterschiede zwischen den Kunden.

Das Problem hierbei ist natürlich, dass es keine zentrale Kontrolle über Entitäten gibt, aber ich denke, dass dies auch auf der Serverseite durch eine serverseitige Simulation der Physik möglich ist

Manabreak
quelle
Danke für deinen Beitrag. Wir benötigen eine zentrale Steuerung, um Betrug zu verhindern. Daher muss der Server mindestens eine Simulation ausführen, um zu wissen, ob das, was die Clients sagen, möglich ist oder nicht.
Venesectrix
1

Ich persönlich würde es vorziehen, die Simulationen nur auf dem Server auszuführen und Änderungen an linearen / Winkelgeschwindigkeiten / Beschleunigungen der beteiligten Objekte zu übertragen, wann immer sie auftreten. Wenn ein bestimmtes Objekt aus irgendeinem Grund seine physikalischen Eigenschaften ändert (z. B. die oben genannten Geschwindigkeiten und Beschleunigungen), wird diese spezielle Änderung vom Server an den Client gesendet und der Client ändert seine Seite von Objektdaten entsprechend.

Der Vorteil gegenüber Ihrer aktuellen Implementierung besteht darin, dass die Notwendigkeit clientseitiger Interpolationen entfällt und ein sehr genaues Verhalten für die Objekte erzeugt wird. Das Problem ist, dass diese Methode sehr anfällig für Latenzen ist, die zu einem sehr großen Problem werden, wenn die Spieler geografisch zu weit voneinander entfernt sind.

Was Frage 1 betrifft, so würde das Problem in Latenzschwankungen bestehen, da es keine absolute Garantie dafür gibt, dass zwischen jedem Empfang des Schnappschusses ein genau perfektes Intervall von 20 Sekunden liegt. Lassen Sie mich veranschaulichen (wobei "t" die in Millisekunden gemessene Zeit ist):

1) Bei t = 20 seit dem Start des Spiels hat der Client einen Schnappschuss erhalten und die Interpolation erfolgreich und reibungslos durchgeführt.

2) Bei t = 40 gab es eine Latenzzeit zwischen dem Server und dem Client, und der Schnappschuss traf nur tatsächlich bei t = 41 ein.

3) Bei t = 60 hat der Server einen weiteren Snapshot gesendet, aber eine Sekunde der Simulation wurde wegen der Latenzzeit clientseitig verschwendet. Wenn der Schnappschuss bei t = 60 ankommt, interpoliert der Client nicht die 40 und 60 Zeitpunkte, sondern die Zeitpunkte 41 bis 60, wodurch ein anderes Verhalten erzeugt wird. Diese Ungenauigkeit könnte die Ursache für das eventuelle "Ruckeln" sein.

Was Frage 2 betrifft, könnte Ihre Idee funktionieren, wenn Sie etwas implementieren, das effizient nachverfolgt, ob jedes Objekt wirklich Client-Server-synchronisiert ist, ohne dass Pakete für jeden Frame gesendet werden müssen, um die Position der Objekte mitzuteilen. Selbst wenn Sie dies in diskreten Intervallen tun, werden Sie nicht nur auf dasselbe Problem wie bei Frage 1 stoßen, sondern auch über zu große Datenmengen verfügen, um diese zu übertragen (was eine schlechte Sache ist).

UBSophung
quelle
Ich bin mir nicht sicher, ob ich dem folge, was du in deinem ersten Absatz sagst. Wenn die Simulation nur auf dem Server ausgeführt wird und Sie nur Geschwindigkeits- / Beschleunigungsänderungen übertragen, woher weiß der Client dann, wo die Sprites gezeichnet werden sollen? Die Clients müssten die Objekte basierend auf der empfangenen Geschwindigkeit / Beschleunigung simulieren, um sie richtig zu zeichnen. Ich denke, Sie haben möglicherweise Recht, wenn Sie Schnappschüsse in anderen Abständen als den von mir erwarteten erhalten. Irgendeine Idee, wie man damit umgeht?
Venesectrix
Die Clients kennen die anfänglichen und aktuellen Positionen, Geschwindigkeiten und Beschleunigungen der Objekte und aktualisieren die Position, die sie für die Objekte halten (unabhängig vom Server), entsprechend. Der Server wird möglicherweise solche Eigenschaften auf den Clients über Nachrichten ändern, da der Server die Physik- und Kollisionserkennung durchführt (die die Geschwindigkeit / Beschleunigung und Richtung eines bestimmten Objekts früher oder später
ändern muss