Para economizar largura de banda no meu jogo multiplayer , não atualizo todos os objetos a cada tick de servidor, mas cada objeto possui um updateRate que informa ao jogo que se espera que esse objeto seja atualizado a cada tick de servidor X.
Quando recebo uma mensagem de atualização para um objeto, calculo o tempo que espero que a próxima atualização chegue:
origin = serverCurrentPosition
diff = serverNextPosition - origin
arriveTime = now + timeBetweenTicks * updateRate
Ao desenhar o objeto, calculo o tempo restante até a próxima atualização e interpolo a posição de acordo:
step = 100 / timeBetweenTicks * updateRate
delta = 1 - step * ((arriveTime - now) / 100)
position = origin + diff * delta
Funciona ... mas ainda há um pouco de instabilidade no desenho, embora, na minha teoria, tudo deva dar certo, pois a escala deve cuidar de certa quantidade de atraso, deveria?
Portanto, a questão aqui é: essa é a melhor abordagem? Devo colocar o atraso real no cálculo? Se sim, como eu faria isso? Fiz algumas experiências, mas o tremor só piorou.
fonte
Respostas:
Você está nervoso, porque o atraso está mudando constantemente. Isso significa que, enquanto o servidor envia atualizações exatamente a cada
timeBetweenTicks
tick, o cliente as recebe após algum tempo variável. Esse tempo provavelmente está próximo detimeBetweenTicks
uma boa conexão, mas não exatamente igual (além disso, você pode ter um atraso no servidor e velocidades de clock diferentes no servidor e no cliente).Portanto, quando você depende de receber a atualização exatamente no tempo especificado, você chega constantemente ao destino um pouco antes / depois da atualização real. Portanto, jitter.
A abordagem simples para reduzir a instabilidade é usar "elásticos", que é o que Martin sugere em outra resposta. Basicamente, quando você recebe atualização, não altera imediatamente a posição do objeto. Em vez disso, se a posição do cliente e a do servidor diferirem apenas um pouco, você começa a interpolar a posição do cliente, para que, após algum tempo especificado (por exemplo, na metade da próxima atualização), as posições do cliente e do servidor converjam.
Outra idéia para reduzir a tremulação na sua configuração: como você transmite as coordenadas "atual" e "próxima", é possível calcular a velocidade do objeto. Então, quando a atualização fica atrasada, você não para o objeto em seu destino (por exemplo, na "próxima posição"), mas continua a movê-lo com a mesma velocidade. Se seus objetos não mudarem de velocidade abruptamente, isso realmente melhorará a suavidade do movimento no cliente.
fonte
Eu já resolvi esse problema com algum sucesso com uma abordagem que chamo de "sombras da rede". Não sei se isso é algo que outras pessoas fazem, mas sempre funcionou para mim.
Cada entidade que está sendo sincronizada na rede possui uma entidade sombra de rede invisível. Quando uma atualização chega da rede, você teleporta a sombra diretamente para a posição em que a rede diz que deve estar e interpola lentamente a entidade visível local em direção à sombra ao longo do tempo.
Incluí muitos detalhes sobre essa abordagem na minha resposta anterior aqui
fonte
Eu escrevi um artigo detalhando uma abordagem ligeiramente diferente, que produz resultados muito suaves: http://www.gabrielgambetta.com/fpm3.html
fonte