Ich bin daran interessiert, die verschiedenen Möglichkeiten zu bewerten, wie sich der Netcode in eine Spiel-Engine "einhaken" kann. Ich entwerfe gerade ein Multiplayer-Spiel und habe bisher festgestellt, dass ich (zumindest) einen separaten Thread haben muss, um die Netzwerk-Sockets zu verwalten, der sich vom Rest der Engine unterscheidet, die die Grafikschleife und das Scripting verwaltet.
Ich hatte eine Möglichkeit, ein vernetztes Spiel vollständig mit einem Thread zu erstellen, nämlich das Netzwerk nach dem Rendern jedes Frames mit nicht blockierenden Sockets zu überprüfen. Dies ist jedoch eindeutig nicht optimal, da die Zeit, die zum Rendern eines Frames benötigt wird, zur Netzwerkverzögerung hinzugefügt wird: Nachrichten, die über das Netzwerk eingehen, müssen warten, bis das aktuelle Frame-Rendering (und die Spielelogik) abgeschlossen sind. Aber zumindest auf diese Weise würde das Gameplay mehr oder weniger reibungslos bleiben.
Ein separater Thread für das Netzwerk ermöglicht es dem Spiel, vollständig auf das Netzwerk zu reagieren. Beispielsweise kann es ein ACK-Paket sofort nach Erhalt einer Statusaktualisierung vom Server zurücksenden. Aber ich bin ein wenig verwirrt darüber, wie ich am besten zwischen dem Spielcode und dem Netzwerkcode kommunizieren kann. Der Netzwerkthread schiebt das empfangene Paket in eine Warteschlange, und der Spielthread liest zum richtigen Zeitpunkt während seiner Schleife aus der Warteschlange, sodass wir diese Verzögerung von bis zu einem Frame nicht beseitigt haben.
Es scheint auch so, als ob ich möchte, dass der Thread, der das Senden von Paketen behandelt, von dem Thread getrennt ist, der nach Paketen sucht, die über die Pipe kommen, da er keine senden kann, während er sich in der Mitte befindet Überprüfen, ob eingehende Nachrichten vorhanden sind. Ich denke über die Funktionalität von select
oder ähnlichem nach.
Ich denke meine Frage ist, wie man das Spiel am besten für die beste Netzwerkreaktivität gestaltet. Es ist klar, dass der Client Benutzereingaben so schnell wie möglich an den Server senden sollte, damit ich den Net-Send-Code unmittelbar nach der Ereignisverarbeitungsschleife innerhalb der Spielschleife erhalten kann. Ist das sinnvoll?
quelle
Nein, tust du nicht.
Ist nicht unbedingt wichtig. Wann wird Ihre Logik aktualisiert? Es macht wenig Sinn, Daten aus dem Netzwerk zu holen, wenn Sie noch nichts damit anfangen können. Ebenso macht es wenig Sinn zu antworten, wenn Sie noch nichts zu sagen haben.
Wenn Ihr Spiel so schnell ist, dass das Warten auf das Rendern des nächsten Frames eine erhebliche Verzögerung darstellt, werden genügend Daten gesendet, sodass Sie keine separaten ACK-Pakete senden müssen. Fügen Sie einfach ACK-Werte in Ihre normalen Daten ein Nutzlasten, wenn Sie sie überhaupt brauchen.
Für die meisten vernetzten Spiele ist es durchaus möglich, eine Spielschleife wie diese zu haben:
Sie können Aktualisierungen vom Rendern entkoppeln, was sehr zu empfehlen ist, aber alles andere kann so einfach bleiben, es sei denn, Sie haben einen bestimmten Bedarf. Was für ein Spiel machst du genau?
quelle
Das stimmt überhaupt nicht. Die Nachricht geht über das Netzwerk, während der Empfänger den aktuellen Frame rendert. Die Netzwerkverzögerung wird auf der Clientseite auf eine ganze Anzahl von Frames begrenzt. Ja, aber wenn der Kunde so wenig FPS hat, dass dies eine große Sache ist, dann haben sie größere Probleme.
quelle
Die Netzwerkkommunikation sollte gestapelt werden. Sie sollten sich um ein einzelnes Paket bemühen, das bei jedem Spiel-Tick gesendet wird (was häufig der Fall ist, wenn ein Frame gerendert wird, aber wirklich unabhängig sein sollte).
Ihre Spieleinheiten kommunizieren mit dem Netzwerk-Subsystem (NSS). Das NSS stapelt Nachrichten, ACKs usw. und sendet einige (hoffentlich eines) UDP-Pakete mit optimaler Größe (normalerweise ~ 1500 Byte). Das NSS emuliert Pakete, Kanäle, Prioritäten, erneutes Senden usw., während nur einzelne UDP-Pakete gesendet werden.
Lesen Sie das Gaffer im Tutorial der Spiele durch oder verwenden Sie einfach ENet, das viele von Glenn Fiedlers Ideen umsetzt.
Oder Sie können einfach TCP verwenden, wenn Ihr Spiel keine zuckenden Reaktionen benötigt. Dann verschwinden alle Stapel-, Sende- und ACK-Probleme. Sie möchten jedoch weiterhin, dass ein NSS Bandbreite und Kanäle verwaltet.
quelle
"Reaktionsfähigkeit nicht völlig ignorieren". Es gibt wenig zu gewinnen, wenn bereits verzögerten Paketen eine weitere Latenz von 40 ms hinzugefügt wird. Wenn Sie ein paar Frames (mit 60 fps) hinzufügen, verzögern Sie die Verarbeitung einer Positionsaktualisierung um weitere Frames. Es ist besser, Pakete schnell anzunehmen und schnell zu verarbeiten, damit Sie die Genauigkeit der Simulation verbessern.
Ich hatte großen Erfolg bei der Optimierung der Bandbreite, indem ich über die Mindeststatusinformationen nachdachte, die erforderlich sind, um das darzustellen, was auf dem Bildschirm angezeigt wird. Schauen Sie sich dann jedes Datenbit an und wählen Sie ein Modell dafür aus. Positionsinformationen können als Deltawerte über die Zeit ausgedrückt werden. Sie können dafür entweder Ihre eigenen statistischen Modelle verwenden und ewig damit verbringen, sie zu debuggen, oder Sie können eine Bibliothek verwenden, um Ihnen zu helfen. Ich bevorzuge die Verwendung des Gleitkommamodells DataBlock_Predict_Float dieser Bibliothek. Dadurch ist es wirklich einfach, die für das Diagramm der Spielszene verwendete Bandbreite zu optimieren.
quelle