Como compensar objetos em movimento com previsão do lado do cliente?


11

Estou implementando um servidor de jogo que suporta corpo a corpo do Star Control . Então você tem naves voando e atirando, com física super simples de velocidade / aceleração / amortecimento para impulsionar o movimento.

insira a descrição da imagem aqui

Li Valve, Gafferon e Gambetta e implementei o algoritmo de Gambetta para previsão de clientes:

insira a descrição da imagem aqui

A previsão do cliente funciona no navio do jogador, atualizando sua posição a partir do servidor e reaplicando a entrada ainda não processada pelo servidor ao navio do jogador.

Infelizmente, não funciona bem para o meu jogo. Acredito que tenha a ver com o fato de que o exemplo de Gambetta não leva em conta objetos que já estão em movimento ou comandos que são atualizados passo a passo. (por "passo" quero dizer quadro). Portanto, no meu jogo, o jogador pressiona para acelerar a nave (que já está se movendo), que continua se movendo no cliente, envia o comando ao servidor e geralmente recebe o instantâneo mundial do servidor na próxima etapa. Eu recebo algo mais como:

insira a descrição da imagem aqui

O comando player é executado na etapa 3 do cliente , mas no servidor é executado apenas na etapa 5 do servidor . No momento em que o instantâneo mundial é recebido pelo cliente na etapa 6 do cliente , a previsão está muito distante, especialmente em velocidades mais rápidas.

O ponto crucial do problema é que o cliente executa o comando na etapa 5 , mas o servidor executa na etapa 6 . Pensei em talvez enviar a etapa do cliente com o comando e fazer com que o servidor reverta e execute novamente o comando com a etapa de tempo do cliente. Isso pode levar a uma série de outros problemas - como o que acontece com os comandos recebidos desde a reversão ou como os clientes trapaceiros podem explorar, alterando a etapa enviada.

Ler e assistir a vídeos como este no Google menciona uma abordagem diferente, na qual você muda gradualmente a posição do jogador para corresponder à do instantâneo em algumas etapas.

Minhas perguntas:

  • Você pode fazer o algoritmo de Gambetta funcionar com movimentos constantes de passos? Ou é conceitualmente incompatível com o meu jogo?

  • A interpolação gradual em etapas é o caminho correto a seguir? Nesse caso, como você interpola um objeto já em movimento da posição do cliente para corresponder ao que acabou de ser recebido do servidor?

  • Esses métodos, a interpolação gradual e o algoritmo de Gambetta podem funcionar em conjunto, ou são mutuamente exclusivos?


Eu tenho feito o mesmo e encontrei exatamente o mesmo problema. Assim que adicionei velocidades aplicando o estado do servidor e reaplicando as entradas, eliminamos as alterações de velocidade já tratadas. Estou tentando reaplicar todas as atualizações desde a última mensagem recebida, mas ainda não está muito tranquilo. Você já encontrou uma solução para isso?
MakuraYami

@ MakuraYami Sim - comecei a escrever um artigo descrevendo a solução. Será atualizado em breve!
OpherV 12/09/16

Eu trabalhei mais no meu projeto e encontrei uma solução utilizável e mais alguns bons recursos falando sobre esse problema. Estou interessado em discutir soluções ainda, comparar, etc. Deixe-me saber onde eu posso contatá-lo :)
MakuraYami

@makurayami meu nome de usuário no Gmail
OpherV 15/09/16

Respostas:


5

Durante os 6 meses desde que fiz essa pergunta, acabei desenvolvendo um servidor de jogos de código aberto completo para lidar com esse problema exato (e muitos outros!): Http://lance.gg

insira a descrição da imagem aqui

O P&D envolvido agora me permite responder minhas próprias perguntas:

  • Você pode fazer o algoritmo de Gambetta funcionar com movimentos constantes de passos? Ou é conceitualmente incompatível com o meu jogo?

    O algoritmo de Gambetta não funcionará quando o movimento da entidade não for determinístico (do ponto de vista do cliente). Se uma entidade pode ser afetada sem a participação da física ou de outros atores, por exemplo, é necessário adotar uma abordagem mais elaborada.

  • A interpolação gradual em etapas é o caminho correto a seguir? Nesse caso, como você interpola um objeto já em movimento da posição do cliente para corresponder ao que acabou de ser recebido do servidor?

    Isso aborda um tópico diferente, que é a reconciliação do cliente das atualizações do servidor. A interpolação gradual funciona, mas para jogos de ritmo muito rápido, como o da pergunta, é melhor implementar a extrapolação

  • Esses métodos, a interpolação gradual e o algoritmo de Gambetta podem funcionar em conjunto, ou são mutuamente exclusivos?

    Eles podem trabalhar juntos, mas somente se o movimento da entidade for determinístico do POV do cliente. Portanto, não funcionará se a entidade for afetada pela física ou psuedo-física, como inserção, arraste etc.


1

Seu jogo parece ser "em tempo real" demais para pensar em termos de etapas do tempo. Eu só pensaria em termos de "turnos" se o jogo pudesse ser considerado "baseado em turnos". Caso contrário, apenas abandone a ideia de voltas ou etapas. Tudo fica mais fácil, então :)

Observe que você prevê localmente para o seu player e interpola apenas para outras entidades (conforme explicado no terceiro artigo da série). A maneira de lidar com as atualizações do servidor para objetos que já estavam em movimento é a reconciliação do servidor, explicada na metade inferior do 2º artigo (aquele ao qual você vinculou).

Espero que isto ajude :)


Só para esclarecer - por "passo" quero dizer "quadro", que é executado 60 vezes por segundo. Eu chamo de etapa (e não de quadro) para diferenciar a progressão real do jogo da renderização e, idealmente, elas são sincronizadas a 60 por segundo. Eu já implementei sua versão da reconciliação no servidor, que funciona de maneira brilhante. Esta pergunta refere-se apenas à nave do jogador - que está em constante movimento, independentemente do comando do jogador (devido à inércia). É aí que está minha dificuldade. Alguma idéia sobre isso? :)
OpherV

Os quadros são diferentes das etapas. As etapas se movem em uma ordem constante e previsível. Os quadros movem uma quantidade variável de tempo, portanto, qualquer progressão deve ser multiplicada pelo tempo delta para esse quadro.
Tealr

@Tealr, é por isso que eu usei o termo "etapa" para começar - eu só queria deixar mais claro que o uso de "etapa" não se limita a jogos baseados em turnos e, no meu jogo, uma etapa leva exatamente 1 / 60 de segundo, independentemente da renderização.
OpherV

Apenas algo que anoto para minhas próprias experiências: 1 / 60s. é extraordinariamente rápido e aposto que a maioria dos jogos on-line com mais de 1x1 participação funciona a 1 / 10s. atualizações ou afins.
Patrick Hughes
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.