Serverseitige Spielschleife

8

Viele Java-Spiele verwenden thread.sleep (), um fps zu steuern. Sollte die Server-Spielschleife weiterlaufen und nur die Delta-Zeit berechnen, da der Server keine Grafiken anzeigt? Wie dieses Beispiel:

long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;   

while (gameRunning)
{
   long now = System.nanoTime();
   long updateLength = now - lastLoopTime;
   lastLoopTime = now;
   double delta = updateLength / ((double)OPTIMAL_TIME);

   doGameUpdates(delta);
}
Wolfrevo Kcats
quelle
11
"Viele Java-Spiele verwenden thread.sleep (), um fps zu steuern" Mann, ich hoffe nicht.
MichaelHouse
1
@ Byte56 Ich würde nicht viele sagen, aber einige könnten so etwas tun. Obwohl Sleepig etwas Übliches ist, ist sein Mechanismus nicht vordefiniert. Thread.Sleepist der einfachste Weg, einige könnten auf Betriebssystem-Interrupts warten. Sie können vSync sogar als Schlafmechanismus zählen.
Ali1S232

Antworten:

6

Es gibt viele Gründe, die ich nicht vorschlagen würde:

  1. Computerressourcen sind wertvoll. Selbst wenn sie frei sind, sollten Sie sie nicht verschwenden. Stellen Sie sich den Fall vor, in dem zwei oder mehr Server gleichzeitig auf einem Computer ausgeführt werden. Wenn eine einzelne Serverinstanz alle CPU-Zyklen belegt, schlagen andere Instanzen einfach fehl. Surly OS wird versuchen, mit diesem gierigen Verhalten umzugehen, aber es ist mit Kosten verbunden. Sie werden nicht wissen, wo das Betriebssystem Ihren Prozess pausiert und dem anderen CPU-Zyklen gibt. Möglicherweise möchten Sie Ihren Server auch neben dem eigentlichen Spiel freigeben, damit die Spieler ihre eigenen LAN-Spiele initiieren können. Es ist etwas ärgerlich, wenn ich einen meiner CPU-Kerne nur für den Betrieb eines Spieleservers reserviert habe!

  2. Die meisten Spiele, speziell vernetzte synchronisierte Spiele, verwenden einen festen Zeitschritt. einfach, weil sie vorhersagen wollen, was auf der Client-Seite passieren wird. Der dynamische Zeitschritt ist aus so vielen Gründen großartig, solange Sie eine einzelne Instanz Ihres Spiels ausführen und er mit keinem anderen Ort synchronisiert wird. Es wird Ihnen die Leistung des Systems gewähren, auf dem das Spiel in vollem Umfang ausgeführt wird. Aber es gibt wieder einen Preis dafür. Sie können nicht vorhersagen, was passieren wird, wenn Sie das Spiel erneut ausführen. Betrachten Sie eine einfache Physikkollision, bei der eine Box auf eine andere Box trifft. Selbst die geringste Änderung des Zeitschritts führt zu großen Unterschieden in der resultierenden Kollisionsauflösung.

  3. Es gibt einen einfachen Grund, warum Leute Thread.Sleep verwenden, wie Sie vorgeschlagen haben, weil das Hinzufügen von mehr Präzision nicht zu einem besseren Spiel führt. Wenn Sie ein Spiel spielen, werden Sie normalerweise nicht bemerken, ob ein Objekt ein oder zwei Pixel entfernt ist. Sie werden also nichts gewinnen, wenn Sie die Genauigkeit erhöhen. Außerdem gibt es eine Beschränkung der Netzwerkbandbreite, sowohl auf der Server- als auch auf der Clientseite. Das bedeutet, dass Sie normalerweise nicht mehr als 30-60 Updates pro Sekunde senden können. Ich kann also fragen, warum Sie Zustände berechnen sollten, die Sie einfach wegwerfen werden.

  4. Es gibt viele Fälle, in denen eine Erhöhung der Präzision Probleme verursachen kann. Beispielsweise verwenden Benutzer häufig die "vertikale Synchronisierung", damit der Grafikpuffer nicht aktualisiert wird, während Daten an den Monitor gesendet werden (was zu einer Unterbrechung führen kann). Auch die meisten Spiele verwenden Floats als primären Nummerncontainer, aber sie sind nicht präzise. Sie werden es vielleicht nicht bemerken, wenn die Zahlen zwischen 2 ^ -20 und 2 ^ 20 liegen, aber außerhalb dieses Bereichs werden Sie ungenaue Verhaltensweisen sehen. Wenn Sie beispielsweise versuchen, 10 ^ -5 bis 10 ^ 5 hinzuzufügen, wird Ihre Hinzufügung einfach ignoriert. Diese Fehler sind normalerweise nicht sichtbar, aber wenn Sie nicht die volle Kontrolle über Ihren Zeitschritt haben, können die Dinge hässlich werden. In Ihrem Fall gehe ich davon aus, dass Ihre Aktualisierungszeit höchstens 10 ^ -4 betragen sollte, da kein Rendering erforderlich ist, was bedeutet, dass alle Änderungen für Zahlen über 100 durcheinander gebracht werden!

  5. In einigen Spielen sind es nur Spielerbefehle, die unvorhersehbare Unterschiede bewirken. Daher möchten Sie möglicherweise nur Ihren Server verwenden, um die Befehle jedes Spielers an die anderen Spieler zu senden. In diesen Fällen können Sie einfach warten, bis einer der Clients dem Server ein Update sendet. Zwischen diesen Updates gibt es nichts zu berechnen, was bedeutet, dass Clients alles tun können (außer Broadcasting). Lassen Sie den Server also nur seine Arbeit erledigen und überlassen Sie alles andere den Clients.

Ali1S232
quelle
Danke, Sie haben dort gute Punkte gemacht. Ich glaube, ich brauche keinen variablen Zeitschritt. Nur noch eine Sache, was schlagen Sie als Schlafmechanismus vor?
Wolfrevo Kcats
@WlofrevoKcast Es basiert vollständig auf den Anforderungen Ihres Spiels, aber für die meisten Spiele sind interne Sprach-Timer (oder OS-Zeit-Interrupts) eine gute Wahl.
Ali1S232
4

Sie sollten dies (halbfester oder vollständig fester Zeitschritt?) Und dies (Gaffer on Games - Fix your timestep) lesen .

Ich bin nicht sicher, warum Sie einen Ziel-FPS in Ihre Serverlogik aufnehmen. Finden Sie einen festen Zeitschritt, der für Sie funktioniert, und aktualisieren Sie ihn entsprechend.

Grundsätzlich haben Sie eine weitere while-Schleife in Ihrer while (gameRunning)Schleife, die Zeit ansammelt, bis ein Update durchgeführt werden kann. Dann führen Sie Updates in festgelegten Intervallen durch.

MichaelHouse
quelle