Interpolar posições em um jogo multiplayer

14

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.

Ivo Wetzel
fonte
Oi Ivo. Acho que esse é um bom tópico, mas não está claro o que seu código está fazendo - por exemplo, de onde vêm serverCurrentPosition, serverNextPosition, timeBetweenTicks?
CiscoIPPhone
Isso envia os dados de atualização provenientes do servidor.
Ivo Wetzel #

Respostas:

11

Você está nervoso, porque o atraso está mudando constantemente. Isso significa que, enquanto o servidor envia atualizações exatamente a cada timeBetweenTickstick, o cliente as recebe após algum tempo variável. Esse tempo provavelmente está próximo de timeBetweenTicksuma 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.

deixa pra lá
fonte
Já é assim, que os objetos não param, continuam seguindo em frente até receber a próxima atualização. Além disso, o uso da aceleração de hardware na tela HTML parece reduzir bastante o efeito de tremulação. Talvez eu tenha ficado louco depois de trabalhar nessa coisa por tanto tempo.
Ivo Wetzel #
Isso é bem possível. Se ativar a aceleração aumenta a taxa de quadros, aumenta a probabilidade de lidar com as informações de atualização exatamente no momento certo.
Nevermind
9

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

Martin
fonte
Hm, eu fiz algo parecido em uma versão anterior, a imprecisão de ponto flutuante tornava muito ruim às vezes, eu tenho intervalos de tempo muito grandes entre as atualizações, até 300ms para alguns objetos, mas talvez eu tenha feito errado, eu vou dar um tiro quando eu encontrar algum tempo livre :)
Ivo Wetzel
a precisão do ponto flutuante realmente não deve entrar nisso! Você leu minha resposta vinculada no stackoverflow? Ele cobre todos os detalhes da implementação desse tipo de coisa.
Martin