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.
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).
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!
fonte
+-*/
" é completamente falsa. Todas essas operações no IEEE-754 podem variar com base na implementação. Veja aqui e aqui para mais informações.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.
Há 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. :)
fonte
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.
fonte
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).
fonte