Come posso sincronizzare lo stato del gioco multiplayer in modo più efficiente rispetto agli aggiornamenti full-state?


10

Ho già fatto un po 'di codifica della rete di giochi, ma principalmente con TCP per i giochi senza necessità in tempo reale. Sto lavorando a un gioco Java 2D con multiplayer in rete. Per l'apprendimento, voglio farlo da solo, senza un'API di rete esistente.

Come posso rappresentare in modo efficiente lo stato del gioco inviato ai client da un server? C'è il modo più ovvio ma probabilmente meno efficiente, che sarebbe quello di creare una sorta di oggetto di contesto dello stato del gioco con la posizione di ogni giocatore, lo stato dell'animazione, ecc., E inviarlo a ciascun giocatore ogni aggiornamento . Ciò non sembra terribilmente difficile da implementare, ma probabilmente sarebbe troppo grande per ottenere qualcosa di simile all'interazione in tempo reale (ovviamente la mia esperienza con questo è limitata, quindi potrei non essere corretto).

C'è un modo solido che qualcuno di voi ha usato prima per trasmettere solo cambiamenti di stato, e c'è anche una disparità abbastanza grande nelle prestazioni da valere il lavoro extra?


2
Prova lo stato completo di ogni frame e se è troppo lento (per un gioco 2d piuttosto semplice, probabilmente è abbastanza efficiente) quindi prova a ottimizzare. Se funziona bene, allora funziona bene e non è necessario modificarlo a meno che non si noti che la rete è un collo di bottiglia in seguito.
Robert Rouhani,

Risposte:


10

La trasmissione regolare dello stato di gioco completo in genere non è fattibile, anche se dipende molto dalla complessità del gioco. Per un semplice gioco con un piccolo modello mondiale potrebbe funzionare.

Personalmente ho avuto molto più successo con il seguente modello:

  • Stato del gioco memorizzato in un modello a oggetti ben definito in una struttura di dati spaziali (ad es. Un ottetto)
  • Tutte le modifiche allo stato del gioco (sul client o sul server) sono descritte come eventi. Un evento potrebbe essere una modifica della proprietà di un oggetto di gioco, una modifica a una tessera mappa, il movimento di un oggetto di gioco ecc.
  • Il motore di gioco sul server produce un flusso di eventi man mano che il gioco procede. Questi vengono applicati direttamente allo stato di gioco del server.
  • Gli eventi vengono inviati anche ai giocatori, ma solo se l'evento è rilevante per quel giocatore (ad es. L'evento è visibile dalla posizione corrente?)
  • I cambiamenti nella visibilità del giocatore possono anche comportare eventi per "rivelare" nuove parti della mappa ecc. Quando il giocatore si muove. Questo può anche essere usato per garantire che il giocatore ottenga una visione iniziale accurata dello stato di gioco rilevante quando si uniscono per la prima volta al gioco.
  • Lo stato del gioco per il giocatore viene aggiornato con gli eventi che riceve. Come tale ha solo un modello parziale dello stato del gioco, ma dovrebbe rimanere sincronizzato con il server presupponendo che tutti gli eventi siano elaborati correttamente

Ciò ha fornito buone prestazioni per me con mondi di gioco anche abbastanza grandi.

Un altro consiglio, lascia che il client si occupi di animazione, effetti particellari ecc. Senza riferimento al server. Non ha senso trasmetterli: devono solo essere "innescati" dagli eventi di gioco appropriati.


6

La sincronizzazione è generalmente divisa in due parti: incrementale e assoluta.

A volte devi trasmettere tutto, è grande, ma se lo impacchi nel modo giusto puoi farlo una volta ogni pochi secondi. È bene mettere tutto in atto, correggendo i guasti degli aggiornamenti incrementali.

Per ottenere un'esperienza in tempo reale, è necessario trasmettere rapidamente alcune modifiche, ma solo gli attributi che possono cambiare. Ad esempio, se un razzo vola in linea retta, non è necessario aggiornare la posizione, ogni cliente può calcolarlo dal punto di partenza. Ma quando colpisce, puoi generare un messaggio al riguardo, in modo che ogni client possa esplodere il razzo nel posto giusto. Problemi minori possono essere ignorati.

Ovviamente aggiorni solo cose, quando possono influenzare il cliente! Qualcosa di lontano dallo schermo non ne vale la pena. Alcuni valori possono essere aggiornati con minore frequenza. Ad esempio, le posizioni sono importanti per essere più o meno precisi, gli eventi (morte, spari, esplosione, ecc.) Devono essere inviati istantaneamente, mentre valori non direttamente importanti possono avere periodi di aggiornamento più bassi, ad esempio tabellone, chat.

Anche l'imballaggio dei dati è importante. È possibile trasmettere circa 1400 byte (dipende dalla configurazione, questo è il valore predefinito) in un pacchetto UDP, di solito ci sono pochi byte di intestazione. Quindi puoi aggiornare facilmente 50-100 posizioni di unità in un pacchetto.


Grazie per il consiglio Matzi. Sto ancora lavorando sull'implementazione del server e del client, ma ricontrollerò tra un paio di giorni e probabilmente accetterò la tua risposta.
Haz,

Buona fortuna a te! ;)
Matzi,

1

A seconda del tuo gioco, potresti prendere in considerazione un modello di "esecuzione sincronizzata" in cui ogni client gioca lo stesso gioco semplicemente condividendo input non deterministici come input da tastiera / joystick ed eventi timer. (Rispetto a un modello in cui ogni client esegue simulazioni locali e prevede di integrare i risultati di simulazioni remote). Il tuo motore di gioco generalmente deve essere completamente deterministico affinché questo funzioni, il che può essere un pesante fardello a seconda del gioco. Ma se il gioco è già deterministico, questo potrebbe essere un approccio più semplice.

Questo post #AltDevBlogADay copre alcuni aspetti di questo approccio in un moderno RTS (in particolare come rilevare quando i tuoi clienti iniziano a eseguire giochi "diversi").

Ricorda di mantenerlo semplice fino a prova contraria, però. :)


1
Queste sono buone letture dello sviluppatore di Factorio che utilizza questo approccio e suggeriscono la complessità di questo approccio, ma mostrano anche che è praticabile: factorio.com/blog/post/fff-76 factorio.com/blog/post/fff -147 factorio.com/blog/post/fff-188
AaronLS
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.