Executar uma simulação de física no cliente e no servidor?


13

Estou implementando um clone de asteróides multiplayer para aprender sobre a arquitetura de rede cliente / servidor em jogos. Passei um tempo lendo as publicações da GafferOnGames e da Valve em sua tecnologia de cliente / servidor. Estou tendo problemas com dois conceitos.

  1. Atualmente, tenho um servidor de jogos autoritário simulando física com box2d e enviando o estado do mundo para clientes cerca de 20 vezes por segundo. Cada cliente monitora os últimos instantâneos recebidos e lê entre dois estados para suavizar o movimento dos sprites. No entanto, não é tão suave. Pode ser suave por um tempo, depois brusco, depois voltar a suavizar etc. Tentei o TCP e o UDP, ambos são praticamente iguais. Alguma idéia de qual possa ser meu problema? (Nota: eu implementei isso para um único jogador primeiro, e o movimento do sprite é perfeitamente suave a 60fps ao atualizar o mundo da física apenas 20 vezes por segundo).

  2. Para resolver o primeiro problema, pensei que talvez o cliente também devesse executar uma simulação box2d e apenas atualizar as posições de seus sprites para corresponder aos instantâneos do servidor quando eles não coincidem. Eu pensei que isso poderia ser mais suave, pois a minha implementação single player é suave. isso é uma boa ideia?

    Mesmo se não resolver o problema acima, é necessário fazer previsões do lado do cliente? Por exemplo, se um jogador tentar mover sua nave, como saberá se atingir um asteróide, muro ou nave inimiga sem uma simulação de física? Parece que a nave deles parece passar pelo objeto com o qual deve colidir antes de receber um instantâneo do servidor que diz que atingiu o objeto.

Obrigado!

Respostas:


10

Definitivamente, execute a simulação nos clientes e no servidor. Qualquer outra coisa tem latência muito longa. Você deve ter certeza de que as simulações correspondem inserindo objetos na mesma ordem, usando uma etapa de tempo fixa e evitando a comparação de ponteiros. Eu não tentei isso com o Box2D, mas geralmente é possível obter o mesmo comportamento em todas as máquinas em uma simulação de física. Toda a matemática é geralmente baseada em IEEE 754 binary32 floats e seu comportamento é estritamente definido para operações como, por exemplo, +-*/algumas. Você precisa ter cuidado com sin,cose os gostos difíceis, pois eles podem diferir entre os tempos de execução (isso é especialmente importante no desenvolvimento para várias plataformas). Verifique também se você usa uma configuração estrita para otimizações de flutuação em seu compilador. Você ainda pode sincronizar objetos enviando periodicamente o estado dos objetos do servidor. Não atualize a menos que a diferença seja maior que um limite para evitar a gagueira desnecessária.

Uma questão que vem à mente é a criação de novos objetos e como isso mudará a simulação entre os clientes. Uma maneira de corrigir isso é permitir que o servidor crie todos os objetos. Se a etapa de tempo atual for t, o servidor agendará um objeto para ser adicionado t+d. Assim, uma lista de novos objetos, com objetos a serem adicionados e quando adicioná-los, pode ser mantida em todos os clientes e atualizada com antecedência pelo servidor. Se dfor grande o suficiente, você minimiza o risco de resultados diferentes. Se você realmente não consegue lidar com a diferença, pode forçar um cliente a aguardar informações sobre novos objetos por um determinado período de tempo antes de simular esse período.


Obrigado pela sua resposta. Não acho que o box2d gere os mesmos resultados em diferentes CPUs, o que seria o cenário para nós, já que estamos escrevendo um jogo para desktop. Espero que as diferenças sejam mínimas e facilmente corrigíveis com atualizações periódicas de um servidor autorizado, mas nunca tentei.
Venesectrix

Erin Catto pensa, que tenta manter todo o estado de múltiplos mundos Box2D em sincronia é uma batalha perdida ( box2d.org/forum/viewtopic.php?f=3&t=8462 )
Pavel

A declaração "O comportamento do flutuador IEEE 754 binary32 [..] é estritamente definida para operações como +-*/" é completamente falsa. Todas essas operações no IEEE-754 podem variar com base na implementação. Veja aqui e aqui para mais informações.
BlueRaja - Danny Pflughoeft 21/02

1
Não. É completamente verdade. O problema que o seu link descreve está relacionado a diferentes modos do x87 fpu e a implementações de transcendentais. O IEEE 754 binary32 é estritamente definido para as operações básicas. Cabe a você definir os modos corretos e usar as instruções corretas para que o padrão seja seguido. Simplesmente usar as instruções SSE e não o x87 fpu ajuda muito.
rasmus

4

Provavelmente não parece tão bom, pois a interpolação entre eles depende sempre de ter o próximo conjunto de dados para interpolar. Isso significa que, se houver um pequeno pico de atraso, tudo terá que esperar para recuperar o atraso.

um artigo antigo no GameDev sobre o uso de splines cúbicos para prever a posição de um objeto além do ponto em que você teve dados pela última vez. O que você faz é usar essa posição e ajustar o spline quando você receber novos dados para dar conta da nova posição. Também é provavelmente muito mais barato do que executar uma segunda simulação de física, e isso significa que você não precisa decidir sobre quem confia, pois implementou explicitamente o cliente que o compõe à medida que avança. :)


Este poderia ser o caso. O que estou tentando fazer é atrasar até receber três instantâneos do servidor. No ponto em que eu ligo do tiro 1 ao tiro 2. Em seguida, do tiro 2 ao tiro 3. Se a qualquer momento eu perder um pacote, eu posso ler de 1 a 3, em vez de 1 a 2, se isso fizer sentido. Talvez eu ainda não esteja implementando isso corretamente. Obrigado pelo link para o artigo!
Venesectrix

1

Eu mesmo fiz algumas coisas semelhantes e executei o Box2D apenas nos clientes. A maneira como fiz isso foi deixar o cliente executar sua própria simulação praticamente por conta própria, enviando a velocidade atual (e a rotação) de todos os pacotes de sincronização para o servidor. O servidor envia essas informações para outros jogadores, que definem as velocidades recém-recebidas para as entidades replicadas. Foi muito suave, sem diferenças visíveis entre os clientes.

Obviamente, o problema aqui é que não há controle centralizado sobre as entidades, mas acho que isso também poderia ser feito no lado do servidor, através da simulação da física no lado do servidor.


Obrigado pela sua contribuição. Exigiremos controle centralizado para evitar trapaças; portanto, precisamos ter o servidor executando uma simulação no mínimo para saber se o que os clientes dizem que estão fazendo é possível ou não.
Venesectrix

1

Pessoalmente, eu preferiria executar as simulações apenas no servidor e transmitir quaisquer alterações nas velocidades lineares / angulares / acelerações dos objetos envolvidos sempre que eles acontecessem. Quando um determinado objeto, por qualquer motivo, altera alguma de suas propriedades físicas (como as velocidades e acelerações acima mencionadas), essa alteração específica é enviada do servidor para o cliente e o cliente muda de lado. dados do objeto de acordo.

A vantagem disso em relação à sua implementação atual é que isso anulará a necessidade de interpolações no lado do cliente e gerará um comportamento muito fiel aos objetos. O problema é que esse método é bastante vulnerável a latências, que se tornam um grande problema quando os jogadores estão geograficamente muito distantes um do outro.

Quanto à pergunta 1, digo que o problema seria flutuações na latência, porque não há garantia absoluta de que haverá um intervalo exatamente perfeito de 20 segundos entre cada recebimento do instantâneo. Deixe-me ilustrar (sendo "t" o tempo medido em milissegundos):

1) Em t = 20 desde o início do jogo, o cliente recebeu um instantâneo e fez a interpolação com êxito e sem problemas.

2) Em t = 40, havia uma latência entre o servidor e o cliente, e o instantâneo chegou a realmente chegar a t = 41.

3) Em t = 60, o servidor enviou outro instantâneo, mas um segundo da simulação foi desperdiçado no lado do cliente devido à latência. Se o instantâneo chegar a t = 60, o cliente não fará uma interpolação dos 40 e 60 instantes, mas, na verdade, dos instantes 41 a 60, gerando um comportamento diferente. Essa inexatidão pode ser a causa do eventual "empurrão".

Quanto à pergunta 2, sua ideia pode funcionar se você implementar algo que rastreie com eficiência se cada objeto é realmente sincronizado entre cliente e servidor, sem precisar enviar pacotes a cada quadro, informando a posição dos objetos. Mesmo que você faça isso em intervalos discretos, você não apenas executará o mesmo problema da pergunta 1, mas também terá grandes quantidades de dados para serem transferidos (o que é uma coisa ruim).


Não sei se sigo o que você está dizendo no seu primeiro parágrafo. Se a simulação é executada apenas no servidor e você transmite apenas alterações de velocidade / aceleração, como o cliente sabe onde os sprites devem ser desenhados? Os clientes teriam que simular os objetos com base na velocidade / aceleração recebida para desenhá-los adequadamente. Eu acho que você pode estar certo em receber instantâneos em intervalos diferentes do que exatamente o que eu espero. Alguma idéia de como lidar com isso?
Venesectrix

Os clientes conhecem as posições iniciais e atuais, velocidades e acelerações dos objetos e atualizarão a posição que eles acham que os objetos são (independentemente do servidor) de acordo. O servidor acabará alterando essas propriedades nos clientes por meio de mensagens, porque é o servidor que está realizando a detecção de física e colisão (que deve mudar a velocidade / aceleração e a direção de um determinado objeto, mais cedo ou mais tarde)
UBSophung
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.