Protocollo di gioco RTS


18

Ho pensato a un gioco RTS multiplayer. La parte che non riesco a capire è mantenere sincronizzato il movimento dell'unità. Se sposto l'unità A per individuare XY, devo comunicarlo al server che inoltra all'altro client.

Sono curioso di sapere come sarebbero le comunicazioni. Vuoi semplicemente comunicare al server che sto spostando l'unità da A a XY da JZ? Forse dovresti comunicare il movimento coord by coord invece? Qual è la metodologia più efficiente per comunicare lo spostamento di unità da un client all'altro?

MODIFICARE

Questa è una domanda ripubblicata da StackOverflow . Ho scoperto che questo sito era probabilmente un posto migliore per la domanda.

Una delle migliori risposte da quel post:

Presumo che tu intenda utilizzare il paradigma di rete Client-Server? Nel qual caso non puoi fidarti dei client per gestire l'effettivo posizionamento delle unità, devi delegare quell'attività al server. Quindi prendi l'elenco dei comandi da ciascun client per tick e calcoli il movimento di ogni unità, una volta che questo è stato completato, il tick successivo trasmette la posizione di ogni unità relativa a ciascun client (su una mappa intera, o base per visualizzazione) e riavviare il processo.


2
La risposta dipende davvero dal metodo che si desidera utilizzare. Client - client o client - server. Il client al server è più semplice ma richiede un server affidabile
Cem Kalyoncu,

Risposte:


25

Non si desidera sincronizzare le posizioni di tutte le unità dal server a ciascun client; ciò richiederà molta più larghezza di banda del necessario. Dovresti anche occuparti di interpolare / estrapolare posizioni di unità, ecc. Quasi nessun RTS professionale utilizza client / server!

Invece, vuoi inviare solo i comandi dei giocatori. Invece di muovere immediatamente le unità quando il giocatore fa clic, metterai in coda il comando di movimento da eseguire in futuro, di solito solo un paio di fotogrammi. Tutti inviano i loro comandi a tutti. Un paio di fotogrammi dopo, tutti eseguono tutti i comandi e, poiché il gioco è deterministico, vedono tutti lo stesso risultato.

Il rovescio della medaglia è che ogni giocatore è lento come il giocatore più lento - se qualcuno rimane indietro nell'inviare comandi, tutti devono rallentare e aspettare che raggiunga (in Starcraft 2, questo è il "XXX sta rallentando il gioco " dialogo).


In effetti, di solito c'è un'altra cosa: eliminare del tutto il server . Chiedi a ogni client di inviare i propri comandi a tutti gli altri client. Questo riduce il ritardo (anziché un comando che va da te -> server -> avversario, passa da te -> avversario) e semplifica la codifica, poiché non è più necessario codificare un server separato. Questo tipo di architettura è chiamata peer-to-peer (P2P).

Il rovescio della medaglia è che ora hai bisogno di un modo per risolvere i conflitti, ma poiché i comandi dei giocatori sono indipendenti l'uno dall'altro nella maggior parte degli RTS, questo di solito non è un grosso problema. Inoltre, non si adatta bene: ogni volta che aggiungi un nuovo giocatore, ogni giocatore deve inviargli i suoi comandi. Non realizzerai un MMO RTS usando P2P.


Questa configurazione (che invia solo comandi tramite P2P) è il modo in cui funzionano la maggior parte degli RTS, inclusi Starcraft, C&C e AoE, ed è l'unico modo in cui AoE potrebbe supportare 1500 unità su una connessione a 28,8 kbps .

(immagine della rete in AoE)

Ecco alcuni altri suggerimenti per scrivere un P2P RTS:

  • Per ovvie ragioni, questa configurazione può funzionare solo se il tuo gioco utilizza un tempo a passo fisso - non vuoi che i risultati di un calcolo dipendono dal framerate! La procedura fissa è più semplice da utilizzare per la maggior parte delle cose, quindi questo non dovrebbe essere un problema.
  • Affinché ciò funzioni, i risultati di ogni comando devono essere completamente deterministici .
    • Questo di solito è abbastanza semplice se ti limiti a un sistema (come Windows a 32 bit) e costringi tutti i client a usare lo stesso eseguibile: assicurati che tutti i generatori di numeri casuali abbiano lo stesso seed e siano sempre chiamati nello stesso ordine; fare molta attenzione quando si scorre su raccolte non ordinate ; eccetera.
    • Ciò è estremamente difficile se si prevede di rendere il gioco giocabile su piattaforme diverse o (come spesso accade con Linux) consentire ai client di compilare il codice da soli. Non solo le diverse librerie di sistema sono praticamente garantite per utilizzare diverse implementazioni di rand(), cos()ecc., Ma praticamente tutta la matematica in virgola mobile è fuori discussione (vedi qui , qui e qui ) ! In tal caso, potresti stare meglio usando client-server.
  • Si sta andando a voler inviare tutte le posizioni di unità ogni tanto un po ', almeno durante il debug, per individuare i bug desincronizzazione (che, credetemi, sarà avere). Se lo mantieni nel gioco finale dipende da te: sincronizzerei almeno alcune unità (o userei una sorta di checksum), per rilevare il tentativo di hacking.

Buon post. Piccola cosa da aggiungere, anche gli stessi compilatori ottimizzati, debug / release e altri flag possono cambiare il risultato. Stai attento!
Peter Ølsted,

14

Ho realizzato un RTS in rete TCP, in cui ho passato i comandi stessi, piuttosto che i risultati dei comandi . Ad esempio, un giocatore dà un ordine di mossa. Se l'ordine di spostamento è valido in base a quel client, viene inviato al server. Il server quindi lo restituisce a tutti i client, che lo convalidano e lo eseguono.

Quindi tutte le macchine client eseguono il gioco da sole, il codice del server accetta i messaggi e li rimanda a tutti i client. Se un client dà un ordine di spostamento, non inizierà a eseguirlo fino a quando non verrà ricevuto dal server.

Il server invia un numero 'tick' al quale eseguire anche il comando, che è qualche segno avanti rispetto al tick 'corrente'. In questo modo tutti i comandi possono essere eseguiti con lo stesso 'tick' su tutte le macchine.

Un vantaggio di questo metodo è che non dipende dal singolo computer client per convalidare il comando. Se avessi superato i risultati della mossa, potrei essere in grado di hackerarla per spostare le mie unità più velocemente. Tutti i client devono eseguire lo stesso comando e se una macchina lo esegue in modo diverso, sarà ovvio.

Convalidare il comando lato client prima di inviarlo al server non è necessario, ma in teoria salva il traffico di rete. Ho usato lo stesso codice di convalida per comunicare all'interfaccia utente che lo spostamento era possibile, quindi non è stato necessario scrivere codice aggiuntivo.

Per quanto riguarda l'aspetto dei messaggi. Non ero interessato all'ultra efficienza poiché era il mio primo gioco in rete. Ho passato i comandi come stringhe. I comandi sarebbero formattati in questo modo:"<player_id>:<command>:<parameters>"

Per un esempio forzato, un comando di movimento potrebbe essere simile a questo: "3:move:522:100:200". Questo significa che il giocatore 3vuole moveunità 522a ( 100, 200).

Il server passa il comando a tutti i clienti, compreso quello che lo ha inviato, con un numero di zecca attaccata in questo modo: "153238:3:move:522:100:200".

Quindi i client eseguiranno tutti questo comando quando viene eseguito il segno di spunta 153238.


Ho aggiunto un po 'più di informazioni alla domanda. La risposta di SO sembra essere contraria a ciò che hai detto e mi piacerebbe discutere i dettagli più fini.
Darthg8r,

Sì, questo è un altro modo di farlo, ma mi sembra che sarebbe più lavoro passare così tanto dello stato del gioco, piuttosto che solo i comandi. Il mio gioco era abbastanza semplice da poter eseguire l'intera cosa su ogni macchina client. Per un MMO o per qualcosa come Minecraft, non hai l'intera simulazione in esecuzione sul lato client, quindi passi solo le informazioni pertinenti a ciascun client individualmente.
Filippo,
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.