Platform multiplayer - Le correzioni del server sono normalmente richieste con un singolo client sul server?


10

Attualmente sto lavorando su un platform multiplayer piuttosto semplice. Ho letto parecchi articoli sulle tecniche usate per nascondere la latenza, ma non riesco ancora a capire meglio alcuni concetti. Trovo l'argomento molto interessante e mi piace provare le idee da solo, ma penso che chiedere a gamingev stackexchange sarà più efficiente per la mia domanda. Farò del mio meglio per descrivere la mia situazione attuale e quale domanda è sorta lungo il cammino.

In questo momento, voglio solo avere un singolo giocatore sincronizzato con il server. Teoricamente, ho ipotizzato che un giocatore da solo con la previsione sul lato client non avrebbe richiesto correzioni del server, poiché non ci sono fattori esterni che influenzano il suo movimento. Pertanto, il mio prototipo attualmente ha solo un giocatore sincronizzato con un server senza invio di correzioni del server.

Se hai familiarità con le reti di gioco, penso che potresti saltare le sezioni di contesto, anche se potrei aver fatto qualcosa di sbagliato lungo la strada.

Il ciclo client (una volta per frame, una volta ogni ~ 16.67ms)

Il ciclo client semplificato assomiglia a:

  1. Verificare l'input locale (WASD) e impacchettarli come azioni (ad es Type=MoveLeft, Time=132.0902, ID=15.). Conserviamo le azioni in pacchetto per inviarle in seguito. Inoltre, applichiamo direttamente l'azione desiderata alla simulazione fisica locale del gioco. Ad esempio, se abbiamo MoveLeftun'azione, applichiamo una forza verso sinistra sulla velocità del giocatore.

  2. Controlla per inviare azioni. Per evitare di abusare della larghezza di banda del client, inviare le azioni in pacchetti solo a determinati intervalli (ad es. 30ms).

  3. Applica modifiche al server. Ad un certo punto questo gestirà i delta e le correzioni ricevute dal server e li applicherà alla simulazione locale del gioco. Per questa domanda particolare, questo non viene utilizzato.

  4. Aggiorna la fisica locale. Esegui il loop fisico sul giocatore principale. Fondamentalmente, questo fa la previsione sul lato client del movimento del giocatore. Questo aggiunge gravità alla velocità del giocatore, applica la velocità del giocatore alla sua posizione, corregge le collisioni lungo il percorso, ecc. Dovrei specificare che la simulazione fisica viene sempre eseguita con un delta fisso (chiamato più volte a seconda del vero delta secondi) .

Sto saltando alcuni dettagli specifici sulla fisica e altre sezioni perché ritengo che non siano necessari per la domanda, ma mi sento libero di farmi sapere se sarebbero rilevanti per la domanda.

Il loop del server (ogni 15ms)

Il loop del server semplificato è simile a:

  1. Gestire le azioni. Controllare i pacchetti di azioni ricevuti dai client e applicarli alla simulazione fisica del server. Ad esempio, potremmo ricevere 5 MoveLeftazioni e applicheremo la forza alla velocità 5 volte . È importante notare che un intero pacchetto di azioni viene eseguito su un "frame" , contrariamente al client in cui viene applicato non appena si verifica l'azione.

  2. Aggiorna la logica di gioco. Aggiorniamo la fisica del gioco, spostando i giocatori e risolvendo le collisioni, ecc. Inoltre confezioniamo tutti gli eventi importanti che sono stati inviati ai giocatori (ad esempio, la salute di un giocatore è caduta, un giocatore è morto, ecc.) In seguito.

  3. Invia correzioni. Inviamo regolarmente delta (ad es. Una volta ogni 35ms) ad altri giocatori (ad es. Posizioni dei giocatori, salute, ecc.) Se recentemente sono cambiati. Questa parte non è attualmente implementata, poiché desidero che la simulazione di un singolo giocatore dia gli stessi risultati sul client e sul server senza correzioni, per assicurarsi che la previsione sul lato client funzioni correttamente.

Il problema

Il sistema attuale funziona bene in circostanze semplici, e sono stato felicemente sorpreso di vedere che ha dato risultati molto simili con semplici movimenti orizzontali (le imprecisioni sono dovute a errori di precisione in virgola mobile, credo):

La sincronizzazione funziona bene con semplici collisioni / movimenti

Ignora la grafica del prototipo. Rettangolo bianco = giocatore, rettangoli rossi = ostacoli, blu = sfondo

Tuttavia, ricevo errori di sincronizzazione dopo aver fatto movimenti sensibili al tempo, come saltare e avvicinarmi a un ostacolo isolato:

La sincronizzazione non funziona perché ho saltato l'ostacolo specificato in momenti sensibili al tempo

In teoria, mi aspetterei che entrambi finiscano sempre con gli stessi risultati, in quanto non vi sono fattori esterni per il cliente che influenzano la sua posizione. In pratica, tuttavia, penso di capire il problema.

Poiché saltare attorno a un ostacolo del genere dipende molto dalla tempistica del giocatore, piccole variazioni di quando la velocità viene applicata alla posizione avranno ripercussioni sul risultato (ad esempio il cliente potrebbe allontanarsi appena in tempo per evitare una collisione con il ostacolo, mentre il server lo farebbe poiché riceverà in seguito l'intero pacchetto di azioni e rimarrà bloccato sull'ostacolo per un breve periodo di tempo, modificando il risultato finale). La differenza tra il modo in cui il client e il server lo gestiscono è principalmente che il client esegue tutte le sue azioni mentre si verificano, mentre il server le esegue tutte in blocco man mano che le riceve.

La domanda

Questo lungo contesto porta infine alla mia domanda (grazie per aver letto fino a questo punto): è normale richiedere correzioni del server anche quando c'è solo un giocatore sincronizzato con il server, o dovrei usare alcune tecniche per evitare la desincronizzazione in situazioni sensibili al tempo ?

Ho pensato ad alcune possibili soluzioni, alcune delle quali mi sento meno a mio agio:

  1. Implementare la correzione del server. Supponi semplicemente che si tratti di un comportamento normale e di errori corretti nel momento in cui si verificano. Volevo implementarlo comunque, ma volevo solo assicurarmi che ciò che ho fatto finora sia accettabile.

  2. Utilizzare il tempo client fornito per applicare le azioni desiderate. Immagino che questo sarebbe simile alla compensazione del ritardo, che richiede di "tornare indietro nel tempo" e controllare i movimenti. Un po 'come applicare le correzioni del server, tornare indietro nel tempo e riapplicare le azioni successive. Non mi piace l'idea. Sembra complesso, costoso nelle risorse e richiede di fidarsi del tempo dato dal cliente (anche se ho intenzione di verificare davvero che il tempo appaia relativamente legittimo).

  3. Chiedi a GameDevelopment StackExchange un'idea fantastica che risolverà tutti i miei problemi.

Sto appena iniziando nel mondo del gioco in rete, quindi sentiti libero di correggere / criticare / insultare uno qualsiasi dei concetti di cui sopra o dare idee / risorse che potrebbero aiutarmi nel mio viaggio nel meraviglioso mondo del networking. Scusatemi se avessi potuto trovare la mia risposta altrove, non ci sono riuscito.

Grazie mille per il tuo prezioso tempo.


Il server e il client eseguono frame a velocità diverse. Cosa succede se il client esegue due azioni su frame consecutivi, ma il server rileva un gap di un frame tra di loro?
user253751

@immibis mi ha basato su gafferongames.com/game-physics/fix-your-timestep per ridurre al minimo questo effetto.
Jesse Emond,

Risposte:


11

In questi casi, è meglio lasciare che il cliente sia leggermente autorevole. Per controlli così precisi è estremamente improbabile che tu ottenga un buon comportamento anche con una correzione e una previsione davvero avanzate.

Il client deve estendersi dall'invio di messaggi "I jumped" all'invio di messaggi "I jumped from X, Y at time T". Il server quindi verifica che la posizione sia nelle immediate vicinanze di ciò che pensa che il giocatore fosse al momento T (che è possibile limitare a un tempo ragionevolmente piccolo in passato) per proteggere dagli imbrogli, quindi simulare il salto dalla posizione del client inviato. Il server corregge il client solo quando è fuori portata (di solito a causa di un ritardo o simili).

Questo tipo di tecnica viene utilizzata insieme alla correzione e all'interpolazione al fine di rendere il gioco reattivo sul client locale e un aspetto fluido per i client remoti.


Molto interessante. Cercherò di implementare questo e vedere come va. Grazie mille per il tempo dedicato a rispondere. A proposito, hai citato "nelle immediate vicinanze" e "un tempo ragionevolmente piccolo in passato", controlleresti semplicemente con una distanza e un tempo costanti, rispettivamente? O useresti tecniche più sofisticate come mantenere una cronologia delle posizioni e utilizzare il tempo medio di andata e ritorno del cliente (o qualsiasi altra cosa, davvero)?
Jesse Emond,

Qualunque cosa funzioni per il tuo gioco. Inizia semplice, complicalo solo nella misura che ritieni necessaria. Alcuni server mantengono una sorta di cronologia delle istantanee per ~max(RTT)i tick dei server in passato, ma non so se sia necessario per il tuo gioco. Può essere ancora più utile per i giochi in stile sparatutto in cui vuoi anche fare un certo livello di rilevamento di colpi / colpi sul client e devi non solo sapere dove era un giocatore 46ms fa, ma anche dove era il suo bersaglio 46ms fa e dove spostando le piattaforme di occlusione dove.
Sean Middleditch il

Perfetto. Sperimenterò e vedrò cosa funziona meglio. Contrassegnandolo come risposta accettata, grazie ancora!
Jesse Emond,
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.