Como posso impedir que o reprodutor fique à deriva devido à previsão de entrada local quando ele para?

14

Estou trabalhando em um mecanismo de jogo multijogador servidor-cliente 2D (que você pode tentar aqui ). Ele usa o WebRTCDataChannel s. (As conexões são ponto a ponto, mas o host ainda atua como servidor.)

O maior problema (além da conectividade) é a previsão de entrada local. Fazemos o de sempre: Ao pressionar as teclas, os jogadores se movem instantaneamente, informam ao host quais teclas foram pressionadas, recebem dados do host e os comparam com a posição histórica. A posição é corrigida ao longo do tempo, se houver uma diferença. Isso funciona bem com baixa perda de pacotes ou PDV , mesmo que o ping seja alto.

Se houver perda ou PDV, o desvio pode ser maior. Eu acho que isso ocorre porque, se o primeiro pacote indicando uma mudança de entrada for atrasado ou descartado, o host descobrirá mais tarde e começará a mudar o player mais tarde do que mostra a previsão de entrada local.

Se o jogador estiver em movimento, aumentamos a quantidade de correção aplicada, pois é menos perceptível. Isso parece encobrir as lacunas ao começar a se mover e enquanto se move. No entanto, qualquer correção é mais perceptível se houver uma parada abrupta. Então, se o PDV ou perda significa que o host pensa que parou mais tarde, o host excede, envia dados informando que estão um pouco mais à frente e a correção faz com que o jogador se desvie um pouco. Em conexões esquisitas, os jogadores geralmente perdem notavelmente depois de parar.

Eu não notei isso em outros jogos. Como isso pode ser mitigado?

AshleysBrain
fonte
3
Um jogo P2P que possui um servidor? Há algo errado aqui.
API-Beast
Ops, com 'servidor' eu quero dizer 'o host par'.
AshleysBrain
2
Bem, isso também não parece um modelo ponto a ponto, apenas porque um dos jogadores está posando como o servidor não o torna ponto a ponto. A técnica que você está empregando é definitivamente uma técnica cliente-servidor. No P2P, você confia em todos os clientes completamente (por exemplo, cada colega pergunta um ao outro onde está o jogador) ou você não confia em nenhum (por exemplo, você adia a entrada até que todos os colegas a recebam).
API-Beast
Ah ... esse é um bom ponto, na verdade ... Eu me confundi: as conexões são ponto a ponto (o que o WebRTC faz), mas o mecanismo em si é servidor-cliente (um dos pares é apenas o servidor ) Bom ponto.
precisa saber é o seguinte
2
O que isto me faz pensar é nossa própria Andrew Russell 's Vara Ninjas registros dev no YouTube , especialmente este em corrigir erros de previsão . O desvio que você descreve soa muito semelhante ao que está acontecendo naquele vídeo e Andrew narra os detalhes. Estes estão relacionados, ou talvez até o mesmo problema?
Anko

Respostas:

8

A camada de rede precisa ter um relógio combinado. Eles podem concordar com um valor de relógio no início do jogo (e ressincronizá-lo periodicamente em caso de desvio) para que o host saiba quanto tempo um pacote específico levou para realmente chegar e quando o cliente fez a ação e vice-versa.

Consulte este artigo para uma maneira possível de sincronizar relógios em jogos. Há outros. Os meios específicos não importam.

A segunda metade do problema é que o servidor está aplicando entrada após o momento em que o cliente parou de aplicar entrada. Isso requer um buffer de movimentos passados ​​no servidor e alguma lógica no cliente para ignorar as entradas de movimento do servidor após o último movimento conhecido.

Primeiro, o buffer do servidor. O servidor precisa acompanhar o carimbo do relógio da última entrada recebida do player. Ele também precisa de todos os movimentos que se aplica a um jogador, o carimbo do relógio. Se uma entrada for recebida, todos os movimentos recentes aplicados com um carimbo de relógio serão mais recentes. que o pacote de entrada são descartados e todo movimento é reaplicado a partir do pacote de entrada. Portanto, se o servidor ultrapassar o jogador com base em alguma entrada, a entrada atualizada cancelará esses movimentos e a nova posição do jogador será baseada no conhecimento de entrada mais recente que o servidor possui.

No lado do cliente, o cliente sabe quando enviou a última entrada para o servidor. Como cada atualização do player do servidor deveria ter sido marcada com o relógio da última entrada que o servidor conhecia, o cliente pode ignorar as atualizações do servidor que possuem uma tag de entrada expirada e seguir a previsão do cliente. Eventualmente, novas atualizações do servidor chegarão com informações atualizadas e o cliente poderá corrigi-las.

O servidor precisa validar os relógios de entrada e garantir que eles não estejam se afastando muito das expectativas para evitar trapaças. O relógio de entrada não deve ser drasticamente maior que o tempo de ida e volta que você deve calcular. Prenda qualquer um que esteja dentro de um intervalo razoável ( [Now-2*RTT,Now]por exemplo).

Os clientes verão muitos avatares de outros jogadores se a latência for alta, pois receberão atualizações do servidor com base em entradas obsoletas, mas não terão como saber que é obsoleta e o servidor poderá começar a enviar locais bastante diferentes com base em a entrada atualizada que recebeu (e a remoção de parte de seu histórico e a reprodução com a nova entrada). Esta última edição com outros jogadores vendo o tremor do seu avatar não é realmente corrigível. A latência é péssima e os jogadores presos em conexões de alta latência vão ver muitos tremores de outros jogadores, mesmo que seu próprio jogador esteja se movendo sem problemas. A única correção é jogar em melhores conexões ou com pares / servidores com menos latência.

Sean Middleditch
fonte
1

Usei mensagens UDP confiáveis ​​para indicar alterações de estado dos botões e mensagens UDP não confiáveis ​​para correção de posição. Basicamente, os seguintes artigos me ajudaram bastante: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

Ele diz sobre a previsão de movimento, armazenando os estados dos jogadores em intervalos de tempo constantes, de acordo com a chegada das mensagens de correção de posição por cerca de 20 ou 30 economias de estado. Portanto, parece que seus players remotos viverão em um "passado" não tão distante atualmente, aplicando constantemente a técnica de previsão :) Com base na latência líquida de mensagens, você pode obter sua posição do objeto aproximadamente no tempo em que a mensagem foi enviada do host.

A posição atual "na tela" pode ser convertida suavemente na posição prevista usando a matemática Lerp (interpolação linear). A idéia é interpolar valores nos intervalos de tempo entre os pacotes de correção. Portanto, parece que o objeto exibido está sempre se movendo em direção a alguma posição prevista. Para o valor de interpolação, pego o 1 dividido por "latência média da mensagem" dividido pelo "tempo médio de renderização do quadro" para que o movimento pareça suave.

Nesse cenário, o jogo calcula todos os clientes e o servidor corrige os valores como velocidade e posição de tempos em tempos.

Mais uma coisa que ajuda muito nesse caso: otimize sua lógica de jogo para que você possa negar facilmente os efeitos de latência, garantindo que servidor e clientes possam emular um comportamento quase semelhante com base na entrada do jogador.

Eu descrevi todo o esquema que usei no meu projeto, então espero que você encontre a resposta para sua pergunta.

Alexander Smirnov
fonte