Come sincronizzare gli orologi nel gioco multiplayer?


8

Ho da 2 a 3 clienti, che possono scambiare messaggi tramite Apple Game Center.

L'unica sincronizzazione di cui ho bisogno è: avviare il gioco nello stesso momento.

Immagino che questo implichi la sincronizzazione dell'orologio. Come realizzare questo?


3
La risposta breve è "non puoi". L'inevitabile (e incoerente) ritardo nelle comunicazioni tra i dispositivi significa che anche se un dispositivo dice "Credo che ora sia 12: 00: 00.00", potrebbe facilmente essere ovunque dalle 12: 00: 00.10 alle 12:00:05 dal volta che quel messaggio è ricevuto altrove. In un modello basato su server non puoi fare molto meglio che avere semplicemente il tuo server che invia il messaggio "Avvia gioco" ai client contemporaneamente.
Steven Stadnicki,

Bene che non ho bisogno della perfezione. Come farlo meglio di niente? Forse: ogni giocatore invia il messaggio "START", e inizia non appena riceve il messaggio START da tutti gli altri giocatori
GameCoder

1
I ritardi di rete di @StevenStadnicki non lo rendono impossibile. Il problema generale si chiama "sincronizzazione dell'orologio" ed è ben studiato. (Tuttavia, se controlli solo gli endpoint, non è possibile tenere conto dell'asimmetria dei ritardi.)
Praxeolitic,

Potrei fraintendere il tuo problema, ma non puoi semplicemente fare in modo che il messaggio che invii ai clienti indichi un orario di inizio leggermente in futuro? Se è il momento nowe si invia un messaggio per iniziare esattamente now + halfSecondfino a quando tutti ricevono il messaggio entro mezzo secondo e fino a quando i loro orologi di sistema sono sincronizzati correttamente, si avviano tutti contemporaneamente.
Segna il

Risposte:


12

Il commento di Steven è giusto: questo è teoricamente impossibile da fare.

Fortunatamente, in pratica puoi avvicinarti, ed è così che funzionano cose come NTP .

Ad esempio, meglio di inviare un messaggio a 3 client che dicono "inizia ora", è possibile scambiare in anticipo un paio di messaggi ping per misurare il tempo necessario per inviare un messaggio al client e quando si invia il messaggio iniziale, invece di "inizia ora", dì "inizia tra X millisecondi" e regola X per i diversi tempi necessari per l'arrivo di un messaggio.

per esempio.:

  • Si invia un messaggio al client 1 e si riceve una risposta 20ms più tardi. Supponi che siano necessari circa 10ms per inviare un messaggio al client 1.
  • Fai lo stesso per il Client 2 e ricevi una risposta dopo 28ms, quindi è probabile che il tempo di trasmissione sia di circa 14ms.
  • Quindi invii un messaggio al Cliente 1 dicendo "inizia il gioco in 50 ms" e ne invii uno al Cliente 2 dicendo "inizia il gioco in 46 ms". Il client 2 riceverà il messaggio circa 4 ms più tardi, ma attenderà 4 ms in meno prima di iniziare il gioco.

Ciò non può garantire la sincronizzazione perché il tempo impiegato per inviare un messaggio su Internet varia e perché può essere diverso in ciascuna direzione. Il primo è possibile ridurre gli effetti eseguendo la misurazione più volte e prendendo una lettura mediana. Il secondo è più complicato e potrebbe essere teoricamente impossibile da risolvere (anche se non ricordo la prova in questo momento). La buona notizia è che probabilmente non hai bisogno di tanta precisione.


Probabilmente dovrò limitare l'attività delle mie app durante la sincronizzazione - in questo momento concedo un po 'di tempo alla CPU al sottosistema di rete in ogni frame di disegno. Se framerate è 30 FPS, risponderò comunque al ping in 1/30 = 33 ms. Potrei anche aggiungere i 33 ms, o la differenza tra "tempo di ricezione dello stack TCP" e il mio attuale MilisecondTicks () ..
GameCoder

2
Se speri di mantenere i sistemi perfettamente sincronizzati fotogramma per fotogramma durante il gioco, penso che sia un gioco perdente e dovresti rinunciare ora. Gli orologi e la latenza andranno alla deriva e le informazioni impiegheranno sempre tempo a viaggiare. Qualunque cosa tu stia cercando di fare, probabilmente non hai bisogno di questo livello di sincronizzazione.
Kylotan,

Penso che ci manchi il punto. Non è la perfezione che mi disturba, è l'esperienza dell'utente. Questo può essere buono o migliore, e vorrei il meglio. Questo è tutto.
GameCoder

2
Una buona esperienza utente non richiede una sincronizzazione precisa. Ecco perché la maggior parte dei giochi non lo tenta.
Kylotan,

1
È teoricamente impossibile se ogni giocatore controlla la propria mazza, perché ci vuole un tempo diverso da zero affinché tali informazioni raggiungano l'altro computer, durante il quale le 2 parti hanno informazioni diverse. Invece trovi i modi per affrontare le differenze. Il tuo problema non è davvero diverso da qualsiasi altro gioco online frenetico e ci sono molte altre domande su come gestire la rete per loro su questo sito. Uno è qui: gamedev.stackexchange.com/questions/22444/…
Kylotan

3

Come accennato, questo è impossibile, quindi proverei un altro approccio:

Se non si dispone di un server dedicato, eleggere un client partecipante per diventare l'host (questo può essere trasferito in caso di necessità).

L'host eseguirà ora tutte le logiche di gioco importanti, come il rilevamento dei colpi, i controlli AI, la gestione dell'inventario, ecc., Nonché il monitoraggio del tempo (ad esempio, il tempo di gioco dettato).

Gli altri client cercheranno semplicemente di rimanere sincronizzati con l'host, provando a stimare o approssimare il valore previsto. Se il ritardo aumenta o si verifica una perdita di pacchetti, le cose potrebbero diventare instabili, ma è banale recuperare il ritardo, essenzialmente solo aspettando il prossimo aggiornamento.

La maggior parte dei giochi (in particolare FPS) nasconde questo fatto facendo il proprio calcolo locale per i movimenti del giocatore, i colpi sparati, ecc. Per evitare che il gioco si senta ritardato. Tutto è ancora corretto in base ai dati del server. Ciò può creare confusione, ad esempio ti vedi sparare al nemico, ma nello stesso momento in cui cadi morto (senza che il nemico subisca un colpo), ma è ancora un approccio molto migliore della sincronizzazione completa.


Se insisti ancora a mantenere tutto sincronizzato, probabilmente vorrai creare una sorta di contatore di passi o frame, quindi tutti i client elaborano solo un passo logico, quindi sincronizzando i loro dati, ecc. Tieni presente che questa può essere sia larghezza di banda intensivo e lento, quindi non consiglierei di farlo a meno che tu non abbia molti altri dati e il tuo gameplay è a turni (ad esempio giochi in stile artiglieria / vermi).


1

Raccomando di sincronizzare i timer di sistema su tutti i client e sul server mediante il protocollo NTP [Stratum 2], quindi il server invia un comando per avviare il gioco all'ora specificata, ad esempio, quando tutti i timer raggiungono 0:05:00. Questo approccio dovrebbe darti 3-4 secondi di sincronizzazione accurata, credo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.