Wie synchronisiere ich Uhren im Multiplayer-Spiel?

8

Ich habe 2 bis 3 Clients, die Nachrichten über das Apple Game Center austauschen können.

Die einzige Synchronisation, die ich brauche, ist: Starten Sie das Spiel im selben Moment.

Ich denke, dies beinhaltet eine Uhrensynchronisation. Wie kann man das erreichen?

GameCoder
quelle
3
Die kurze Antwort lautet "Sie können nicht". Die unvermeidliche (und inkonsistente) Verzögerung bei der Kommunikation zwischen Geräten bedeutet, dass selbst wenn ein Gerät sagt "Ich glaube, es ist jetzt 12: 00: 00.00", es leicht irgendwo zwischen 12: 00: 00.10 und 12:00:05 liegen kann Zeit, zu der diese Nachricht an anderer Stelle empfangen wird. In einem serverbasierten Modell können Sie nicht viel besseres tun, als wenn Ihr Server gleichzeitig die Nachricht "Spiel starten" an die Clients sendet.
Steven Stadnicki
Gut, dass ich keine Perfektion brauche. Wie macht man es besser als nichts? Vielleicht: Jeder Spieler sendet eine "START" -Nachricht und startet, sobald er eine START-Nachricht von allen anderen Spielern erhält
GameCoder
1
@StevenStadnicki Netzwerkverzögerungen machen dies nicht unmöglich. Das allgemeine Problem heißt "Taktsynchronisation" und ist gut untersucht. (Wenn Sie jedoch nur die Endpunkte steuern, ist es nicht möglich, die Asymmetrie der Verzögerungen zu berücksichtigen.)
Praxeolitic
Ich verstehe Ihr Problem möglicherweise falsch, aber können Sie nicht einfach die Nachricht, die Sie an Kunden senden, auf eine Startzeit in der Zukunft hinweisen? Wenn die Zeit gekommen ist nowund Sie eine Nachricht senden, um genau now + halfSeconddann zu beginnen , werden alle zur gleichen Zeit gestartet, solange alle die Nachricht innerhalb einer halben Sekunde empfangen und ihre Systemuhren korrekt synchronisiert sind.
Mark

Antworten:

12

Stevens Kommentar ist richtig: Dies ist theoretisch unmöglich zu tun.

Glücklicherweise kann man in der Praxis nah dran sein, so funktionieren Dinge wie NTP .

Besser als nur eine Nachricht an 3 Clients mit der Aufschrift "Jetzt starten" zu senden, können Sie vorab einige Ping-Nachrichten austauschen, um die Zeit zu messen, die erforderlich ist, um eine Nachricht an den Client zu senden, und wenn Sie die Startnachricht senden. Anstelle von "Jetzt starten" sagen Sie "In X Millisekunden starten" und passen X an die unterschiedlichen Zeiten an, zu denen eine Nachricht eintrifft.

z.B.:

  • Sie senden eine Nachricht an Client 1 und erhalten 20 ms später eine Antwort zurück. Sie vermuten, dass es ungefähr 10 ms dauert, bis eine Nachricht an Client 1 gesendet wird.
  • Sie tun dasselbe für Client 2 und erhalten 28 ms später eine Antwort. Die Übertragungszeit dort beträgt also wahrscheinlich etwa 14 ms.
  • Sie senden also eine Nachricht an Client 1 mit der Aufschrift "Spiel in 50 ms starten" und eine Nachricht an Client 2 mit der Aufschrift "Spiel in 46 ms starten". Client 2 erhält die Nachricht ca. 4 ms später, wartet jedoch 4 ms weniger, bevor das Spiel gestartet wird.

Dies kann keine Synchronisierung garantieren, da die zum Senden einer Nachricht über das Internet benötigte Zeit unterschiedlich ist und in jeder Richtung unterschiedlich sein kann. Zum einen können Sie die Auswirkungen reduzieren, indem Sie die Messung mehrmals durchführen und einen Medianwert ablesen. Der zweite ist schwieriger und möglicherweise theoretisch unmöglich zu lösen (obwohl ich mich momentan nicht an den Beweis erinnern kann). Die gute Nachricht ist, dass Sie wahrscheinlich nicht so viel Genauigkeit benötigen.

Kylotan
quelle
Wahrscheinlich muss ich die Aktivität meiner Apps während der Synchronisierung einschränken. Im Moment gebe ich dem Netzwerksubsystem an jedem Zeichnungsrahmen etwas CPU-Zeit. Wenn die Framerate 30 FPS beträgt, werde ich den Ping trotzdem in 1/30 = 33 ms beantworten. Ich könnte auch die 33 ms oder die Differenz zwischen "TCP-Stack-Empfangszeit" und meinen aktuellen MilisecondTicks ()
hinzufügen
2
Wenn Sie hoffen, dass die Systeme während des Spiels Bild für Bild präzise synchronisiert werden, ist das meiner Meinung nach ein verlorenes Spiel, und Sie sollten jetzt aufgeben. Uhren und Latenz werden driften und Informationen brauchen immer Zeit, um zu reisen. Was auch immer Sie versuchen, Sie benötigen diese Synchronisierungsstufe wahrscheinlich nicht.
Kylotan
Ich denke, wir verpassen den Punkt. Es ist nicht die Perfektion, die mich stört, sondern die Benutzererfahrung. Das kann gut oder besser sein, und ich möchte das besser. Das ist es.
GameCoder
2
Eine gute Benutzererfahrung erfordert keine präzise Synchronisation. Deshalb versuchen es die meisten Spiele nicht.
Kylotan
1
Es ist theoretisch unmöglich, wenn jeder Spieler seinen eigenen Schläger kontrolliert, da es eine Zeit ungleich Null dauert, bis diese Informationen den anderen Computer erreichen, während der die beiden Seiten unterschiedliche Informationen haben. Stattdessen finden Sie Wege, um mit den Unterschieden umzugehen. Ihr Problem unterscheidet sich nicht wirklich von jedem anderen schnelllebigen Online-Spiel, und es gibt einige andere Fragen zum Umgang mit Netzwerken auf dieser Website. Man ist hier: gamedev.stackexchange.com/questions/22444/...
Kylotan
3

Wie bereits erwähnt, ist dies unmöglich, daher würde ich einen anderen Ansatz ausprobieren:

Wenn Sie keinen dedizierten Server haben, wählen Sie einen teilnehmenden Client als Host aus (dieser kann bei Bedarf übertragen werden).

Der Host führt nun alle wichtigen Spielelogiken wie Treffererkennung, KI-Steuerung, Inventarverwaltung usw. sowie Zeiterfassung (dh Diktieren der Spielzeit) aus.

Die anderen Clients versuchen lediglich, mit dem Host synchron zu bleiben und den erwarteten Wert zu schätzen oder zu approximieren. Wenn die Verzögerung zunimmt oder ein Paketverlust auftritt, werden die Dinge möglicherweise unruhig, aber es ist trivial, aufzuholen und im Wesentlichen nur auf das nächste Update zu warten.

Die meisten Spiele (insbesondere FPS) verbergen diese Tatsache, indem sie ihre eigene lokale Berechnung für die eigene Bewegung des Spielers, abgefeuerte Schüsse usw. durchführen, um zu vermeiden, dass sich das Spiel verzögert anfühlt. Alles wird immer noch basierend auf Serverdaten korrigiert. Dies kann zu Verwirrung führen, z. B. wenn Sie sehen, wie Sie den Feind erschießen, aber im selben Moment, in dem Sie tot umfallen (ohne dass der Feind einen Treffer erzielt), ist dies jedoch ein weitaus besserer Ansatz als die vollständige Synchronisierung.


Wenn Sie immer noch darauf bestehen, alles synchron zu halten, möchten Sie wahrscheinlich eine Art Schritt- oder Frame-Zähler erstellen, sodass alle Clients nur einen logischen Schritt verarbeiten und dann ihre Daten usw. synchronisieren. Beachten Sie, dass dies beide Bandbreiten sein können intensiv und verzögert, daher würde ich dies nicht empfehlen, es sei denn, Sie haben ansonsten viele Daten und Ihr Gameplay ist rundenbasiert (z. B. Spiele im Artillerie- / Worms-Stil).

Mario
quelle
1

Ich empfehle, System-Timer auf allen Clients und dem Server mithilfe des NTP-Protokolls [Stratum 2] zu synchronisieren. Anschließend sendet der Server einen Befehl, um das Spiel zum angegebenen Zeitpunkt zu starten, beispielsweise wenn alle Timer 0:05:00 erreichen. Dieser Ansatz sollte Ihnen 3-4 ms genaue Synchronisation geben, glaube ich.

ivan866
quelle