Ich implementiere ein MMO, bei dem der Spieler auf seinem Raumschiff im Raum fliegt, es mit den Pfeiltasten steuert und mit anderen Spielern zusammenarbeitet.
Ich möchte es implementieren, damit Spieler in der Lage sind, ihrem Schiff vor einer Rakete oder etwas anderem auszuweichen. Deshalb versuche ich, den gesamten Spielstatus auf der Clientseite mithilfe des gleichen Algorithmus zur Weltsimulation wie bei der Servernutzung vorherzusagen. Diese Spielewelt ist in C # geschrieben und wird direkt im Client (in Unity3D) und über CLR auf einem C ++ - Server (unter Linux) aufgerufen. Verbindung über UDP.
Problem ist, wie man zum Beispiel 1000 Spieler innerhalb einer einzelnen Karte verwaltet (ausgenommen alle anderen Spielobjekte, Mobs ...): Sagen wir, ich werde:
- Synchronisieren Sie den Server mit den Clients 50-mal pro Sekunde
- Sende jedem Kunden nur die Zustände der Spielobjekte (und Spieler), die er sehen kann (innerhalb eines bestimmten Radius)
- muss jedem Spieler innerhalb seines Sichtradius 100 Objekte schicken
- muss durchschnittlich 50 Bytes pro Spielobjekt senden (ID, x, y-Koordinaten, Rotation, Status ...)
Daher wird eine solche Netzwerkbandbreite benötigt: 1000 (Clients) * 50 (Zeiten pro Sekunde) * 100 (Objekte, die an jeden Spieler gesendet werden sollen) * 50 (Bytes pro Objekt) = 250 000 000 Bytes pro Sekunde! Es ist unmöglich!
Ist es möglich, diesen Wert irgendwie zu reduzieren? Lassen Sie die Clients beispielsweise ihre Spielwelten (über einen längeren Zeitraum) vollständig simulieren und ihnen nur Eingaben von anderen Clients senden und die Spielwelten synchronisieren, sagen wir, alle paar Sekunden, aber dies führt aufgrund von Float-Berechnungen zu merkwürdigen Desynchronisierungsproblemen .
Wie sind solche Spiele eigentlich programmiert? Vielen Dank.
quelle
Antworten:
Sie benötigen nur etwa 30 Updates (oder sogar weniger, vielleicht 10 oder 20) pro Sekunde. interpolieren Sie die Positionen von beweglichen Objekten clientseitig. Im Allgemeinen sollten Sie Daten nur dann senden, wenn sie WIRKLICH benötigt werden. In WoW erhalten Sie möglicherweise mehr Updates von den Spielern, mit denen Sie in einer Gruppe sind, als von den Spielern, die sich am selben Ort befinden. Auch wenn ein anderer Spieler weit von Ihnen entfernt ist, erhalten Sie nicht so viele Aktualisierungen pro Sekunde über ihn.
Senden Sie dann nur einen vollständigen Schnappschuss an jeden Spieler, wenn er eine Verbindung herstellt. Danach senden Sie nur die Änderungen der Spielobjekte. Wenn keine Änderung aufgetreten ist, senden Sie sie nicht.
Dann nutzen Sie BitVectors oder wie auch immer Sie sie nennen, um die Menge nicht benötigter Daten zu reduzieren! Beispiel: Sie können auch versuchen, einen Gleitkommawert mit nur einem Byte zu schreiben (in einem Bereich von 0 bis 1 oder -1 bis 1), sodass Sie nur 256 oder 128 verschiedene Werte haben. Durch die Interpolation bemerkt der Spieler jedoch keine ruckartigen Bewegungen.
Ein Beispiel mit LidgrenLibrary zum Komprimieren von Daten finden Sie hier: http://code.google.com/p/lidgren-network-gen3/wiki/Optimization
Weiter: Versuchen Sie, den Sichtradius der Spieler während ihrer Bewegung zu verringern und nur wichtige Informationen in dieser Zeit zu übertragen. Wenn sie dann anhalten, vergrößern Sie ihren Sichtradius erneut. Sie können ein räumliches Hashing-System oder einen BSP-Baum verwenden, um den Aufwand für die Suche nach Objekten zu verringern, die sich "in Reichweite" befinden. Dies ist eine gute Lektüre für das Thema: http://en.wikipedia.org/wiki/Collision_detection
Komprimieren Sie die Daten auch SELBST. Nur SIE kennen die Datenstruktur und die zeitliche Kohärenz in den Daten (die ausgenutzt werden können und sollten). Ein allgemeiner Algorithmus wie Bzip2 oder Deflate sollte verwendet werden, aber nur als letzte Komprimierungsstufe!
Für nicht spielkritische Informationen können Sie auch zusätzliche P2P-Techniken verwenden. Beispiel: Ein Spieler spielt die "Hallo" -Animation ab. (Nur ein grafischer Effekt) Der Spieler sendet diese Informationen an den Server, der Server leitet sie jedoch nicht an die anderen Spieler weiter. Stattdessen wird dieser unkritische Effekt vom Spieler selbst an die anderen Clients in Reichweite gesendet.
EDIT (wegen des Kommentars):
Zusätzliche Methoden zum Verringern der durchschnittlichen Bitzahl pro Sekunde für jeden Spieler:
Sie haben geschrieben, dass Sie "Objekt wurde nicht geändert" senden. Es gibt keinen Grund, dies zu tun. Wenn Sie wegen Paketverlusts besorgt sind (und Ihre Simulation aus diesem Grund nicht mehr synchron ist), beachten Sie Folgendes: Bei jedem festgelegten Zeitschritt (z. B. 100, 200, 300, 400 ...) wird der Simulationsstatus gehasht und an den Server gesendet . Der Server bestätigt oder sendet einen vollständigen Schnappschuss aller Daten zurück.
Für Dinge wie Raketen oder sogar Spieler können Sie nicht nur interpolieren, sondern auch extrapolieren, um die Simulation realistischer zu gestalten. Beispiel 'Rakete': Anstatt mit Nachrichten wie "Befindet sich jetzt an Position x" zu aktualisieren, senden Sie einfach eine Nachricht mit folgendem Inhalt: "Rakete gestartet: Position (Vektor), Uhrzeit (bei welchem Simulationsschritt die Rakete gestartet wurde), Geschwindigkeit ( Vektor)". Sie müssen also nicht einmal die Drehung einbeziehen, da die Spitze immer in der "Geschwindigkeits" -Richtung ist.
Kombinieren Sie mehrere Befehle in einer Nachricht und senden Sie niemals Nachrichten, die kleiner als 16-20 Byte sind, da der udp-Header größer als die Nachricht selbst ist. Senden Sie auch keine Pakete, die größer als die MTU Ihres Protokolls sind, da die Fragmentierung die Übertragungsgeschwindigkeit verlangsamt.
quelle
Hier sind zwei Ansätze:
Erstens:
Wechseln Sie zu deterministischer Physik, senden Sie Spielerbefehle, AI-Aktionen, Objekte, die sichtbar werden, und alles, was nicht clientseitig bestimmt werden kann, an Clients. Dies muss Nicht-Befehle beinhalten, eine Bestätigung, dass bis zu einem bestimmten Zeitpunkt nur die gesendeten und empfangenen Befehle gültig sind.
Der Client muss zwei oder drei gleichzeitige Simulationen ausführen.
1: Hält an, wenn Daten für den nächsten Schritt fehlen.
2: Verwenden Sie weiterhin Schätzdaten und geben Sie den für das Rendern verwendeten Status an. 3: Immer wenn Nr. 1 zum Stillstand kommt, kopiert diese Simulation den Zustand von Nr. 1, holt die aktuelle Zeit ein und übernimmt Nr. 2, die dann fallengelassen wird.
Wenn der Aufholprozess schnell genug ist, können Sie die Unterschiede zwischen Nr. 2 und Nr. 3 weglassen und die alten Daten sofort löschen.
Zweitens:
Verwenden Sie keine deterministische Physik, sondern senden Sie alle paar Sekunden "Vollbilder". Sie können das Übertragen von temporären Elementen wie Kugeln ganz einfach auslassen.
In beiden Fällen sollten Sie vorsichtig sein, wenn der Kunde vorhersagt, dass jemand stirbt. Es ist irgendwie albern, wenn ein Gegner explodiert.
Und +1 für das Rechnen, zu viele Leute machen keine einfachen Schätzungen des Ressourcenverbrauchs.
quelle
Ein paar Fragen zuerst.
Sind die "Raketen oder etwas anderes" intelligent oder dumm? Wenn sie dumm sind, brauchen Sie nur den Zeitstempel des Feuers, den Ursprung und den Vektor, um ihren Weg zu simulieren. Wenn sie intelligent sind, wie intelligent sind sie? Können Sie zum Zeitpunkt des Feuers berechnen, ob sie treffen oder verfehlen werden? In diesem Fall können Sie den gesamten Pfad auf dem Client simulieren. ("Bei T13 wird die Rakete das Schiff treffen, weil das Spiel den Ausweichwurf verloren hat / der Schütze einen kritischen Treffer erzielt hat.")
Im Allgemeinen gibt es jedoch so gut wie keinen Grund: A) eine Taktrate von 50 Hz zu haben (die meisten Schützen kommen mit 15-20 und weniger MMOs davon). B) jeden Frame den vollen Status senden. (Kommt es überhaupt auf die Rotation einer Rakete im Weltraum an? Oder können Sie einfach davon ausgehen, dass sich ihre "Front" entlang des Vektors orientiert, den sie bewegt?)
Verbringen Sie Zeit mit Vorhersage und Interpolation, und Sie werden sehen, wie Ihre Bandbreite sinkt. Ein Projekt, an dem ich gearbeitet habe, hatte eine Aktualisierungsrate von 10 Hz und eine Objektzustandsdarstellung von 14 Byte. (Komprimiere alles, was du kannst! Ich glaube, wir haben 6 Bits verwendet, um die Rotation um die x-Ebene zu definieren, und dann weitere 6 Bits für eine Neigung über / unter dieser Ebene. Es sah nicht unterscheidbar aus, eine tatsächliche Rotationsmatrix / Quaternion zu senden.)
Sie können auch Objekte priorisieren. Zeigen Sie, vielleicht gibt es 100 Objekte in der relevanten Menge, aber kennen Sie sein Ansichtsstumpf auf dem Server? Wenn etwas nicht in seiner Sicht ist, können Sie die Aktualisierungshäufigkeit um eine Größenordnung verringern?
Die allgemeine Idee ist nicht, eine perfekte Simulation auf dem Client zu erstellen, das ist unmöglich. Die Idee ist, ein unterhaltsames Spiel zu erstellen, bei dem die Spieler nicht bemerken, dass es keine perfekte Simulation ist.
quelle