Sincronizando clientes com um servidor e entre si


9

Qual é a melhor maneira de manter todos os clientes sincronizados com um servidor e entre si?

Atualmente, temos duas abordagens em mente:

  1. Quando um cliente envia algo ao servidor, ele envia imediatamente mensagens para todos os clientes, que reagem imediatamente.
  2. A introdução de algum atraso de tempo, pelo qual o servidor envia mensagens para todos os clientes, com a diretiva ", age de acordo com isso no momento t.

A segunda abordagem parece que provavelmente manteria todos os clientes em melhor sincronização (já que ela atende a algum grau de atraso); mas me pergunto se a capacidade de resposta seria perdida em um grau muito alto (ou seja, o usuário clica em "pular" e há uma lacuna visível entre pressionar o botão e realmente pular).

Também há a possibilidade de os clientes calcularem sua própria posição (e não esperar que os servidores digam "você pulou"); mas, devido ao inevitável atraso, os clientes ficariam muito fora de sincronia.

Depois, há toda a questão TCP vs. UDP; porque queremos rápido, mas também detestaria que o servidor dissesse que você está em um local completamente diferente do que você pensava.

Com todas essas demandas concorrentes, tudo fica muito incerto sobre como devemos abordar esse problema. Qual dessas abordagens (ou qualquer outra) seria melhor para manter os clientes e o servidor sincronizados? Quais são realmente usados ​​na indústria?

Respostas:


7

A resposta rápida é: não há melhor abordagem.

Todos os jogos contêm arquitetura diferente; todo jogo escolhe diferentes conjuntos de dados a serem enviados para sincronizar-se com outras máquinas, o que afetará as escolhas que você poderá fazer ao escolher como lidar com o atraso.

O que você especifica na opção 2 - que os clientes enviam mensagens para serem executadas em um momento futuro - é definitivamente uma abordagem. De fato, o mecanismo Source usa uma variante dessa abordagem , na qual a renderização está sempre 100ms atrás das ações do cliente local; todas as máquinas tentam operar nas mesmas ações ao mesmo tempo. Isso adiciona um atraso artificial imperceptível ao jogo para ocultar a latência real da rede.

Se você não puder adotar essa abordagem, também poderá escolher a opção 1, enviando os dados mais atualizados e, após o recebimento, use a interpolação e extrapolação (previsão do lado do cliente) para tentar ocultar a latência. Eu usei essa abordagem em pelo menos um jogo de remessa - mas, novamente, tudo depende do seu jogo; pode haver outras abordagens que você pode adotar.

Finalmente, ao escolher entre TCP e UDP - você provavelmente deseja UDP. Existem cenários em que o TCP é uma opção viável para conectar seu jogo em rede, mas quando você está criando um jogo de ação, deseja os dados mais recentes o mais rápido possível. Se você pode lidar com pacotes descartados, o UDP é a melhor escolha. (Existem bibliotecas, como ENet , que fornecem um invólucro em torno do UDP para substituir a funcionalidade do TCP, como pacotes confiáveis.)


Você realmente não quer usar o UDP. A sobrecarga de uma conexão TCP configurada corretamente é mínima e o inferno de entrega com defeito é algo que ninguém deveria ter que viver.
Coderanger

2
Não é uma questão de sobrecarga, embora o TCP adicione um pouco - a maneira como o TCP lida com pacotes descartados não é fundamentalmente boa em jogos onde uma grande latência entre ação e reação pode fazer uma enorme diferença na jogabilidade. Para um jogo como o WoW, em que as ações são relativamente pouco frequentes, o TCP funciona, mas ele cai demais em um jogo como o CounterStrike, pois um único pacote descartado limita sua conexão e potencialmente faz com que você fique "atrasado" por um segundo ou mais.
Blair Holloway

Se você vai usar o UDP, é realmente melhor não escrever por conta própria; use um invólucro como o ENet que faça o trabalho duro para você. Mas minha resposta original ainda permanece: o UDP é o melhor caminho a percorrer se você estiver criando um jogo com qualquer tipo de ação em ritmo acelerado.
Blair Holloway

Para mim, a RakNet tornou extremamente fácil rodar uma conexão UDP para o meu mecanismo de jogo. Tem muitas opções de como você deseja enviar seu pacote, isto é. como requisitá-los, caso o pacote seja reenviado se descartado etc.
BarakatX2

3

Aqui estão alguns bons links que cobrem uma enorme quantidade de redes de jogos.

E esta é a primeira parte das mais mãos na série de redes. http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/

Pela história. 'desculpe, mas como mecanismo de prevenção de spam, os novos usuários podem postar apenas um máximo de um hiperlink. Ganhe 10 reputação para postar mais hiperlinks. ' Basta olhar em seu site, de qualquer maneira.


1

Como você menciona clientes e servidores, vou assumir que você está falando de uma arquitetura cliente / servidor em que o servidor é a autoridade no estado de todos os objetos.

Nota: A alternativa é uma arquitetura ponto a ponto em que o proprietário de um objeto é a autoridade para esse objeto.

Já existe um método comprovado para sincronizar objetos em movimento usando a arquitetura Cliente-Servidor. Chama-se Dead Reckoning. .

Uma boa maneira de implementar isso em um jogo seria assim:

  1. Clientes enviam entradas para o servidor.
  2. O servidor atualiza os objetos do jogo (acelerações e direções) e os envia de volta aos Clientes.
  3. Os clientes usam esses valores atualizados para simular o movimento dos objetos localmente.
  4. Ocasionalmente, o servidor envia uma correção de posição para evitar desvios.
  5. Enxágüe; repetir.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.