Estou trabalhando em um shooter 2D de cima para baixo e fazendo o possível para copiar conceitos usados em jogos em rede como o Quake 3.
- Eu tenho um servidor autorizado.
- O servidor envia instantâneos para os clientes.
- Os instantâneos contêm um registro de data e hora e posições da entidade.
- As entidades são interpoladas entre as posições do instantâneo, para que o movimento pareça suave.
- Por necessidade, a interpolação de entidade ocorre um pouco "no passado", de modo que temos vários instantâneos nos quais podemos interpolar.
O problema que estou enfrentando é "sincronização do relógio".
- Por uma questão de simplicidade, vamos fingir por um momento que não há latência ao transferir pacotes de e para o servidor.
- Se o relógio do servidor estiver 60 segundos antes do relógio do cliente, o registro de data e hora da captura instantânea será 60000ms antes do registro de data e hora local do cliente.
- Portanto, os instantâneos da entidade serão coletados e permanecerão em repouso por cerca de 60 segundos antes que o cliente veja qualquer entidade fazer seus movimentos, porque leva muito tempo para o relógio do cliente recuperar o atraso.
Consegui superar isso calculando a diferença entre o servidor e o relógio do cliente cada vez que um instantâneo é recebido.
// For simplicity, don't worry about latency for now...
client_server_clock_delta = snapshot.server_timestamp - client_timestamp;
Ao determinar até que ponto a interpolação está na entidade, simplesmente adiciono a diferença ao horário atual do cliente. O problema com isso, no entanto, é que ele causará instabilidade, pois a diferença entre os dois relógios flutuará abruptamente devido aos instantâneos que chegam mais rápido / mais lentamente que os outros.
Como sincronizar os relógios com a precisão necessária para que o único atraso perceptível seja o codificado para interpolação e o causado pela latência comum da rede?
Em outras palavras, como posso impedir que a interpolação seja iniciada muito tarde ou muito cedo quando os relógios são dessincronizados significativamente, sem introduzir instabilidade?
Edit: De acordo com a Wikipedia , o NTP pode ser usado para sincronizar relógios pela Internet em questão de alguns milissegundos. No entanto, o protocolo parece complicado e talvez exagerado para uso em jogos?
Respostas:
Depois de pesquisar, parece que sincronizar os relógios de 2 ou mais computadores não é uma tarefa trivial. Um protocolo como o NTP faz um bom trabalho, mas é supostamente lento e muito complexo para ser prático nos jogos. Além disso, ele usa UDP, que não funcionará para mim porque estou trabalhando com soquetes da Web, que não suportam UDP.
Eu encontrei um método aqui , no entanto, que parece relativamente simples:
Ele afirma sincronizar os relógios a 150ms (ou melhor) um do outro.
Não sei se isso será bom o suficiente para meus propósitos, mas não consegui encontrar uma alternativa mais precisa.
Aqui está o algoritmo que ele fornece:
Essa solução parece responder bem à minha pergunta porque sincroniza o relógio e depois para, permitindo que o tempo flua linearmente. Enquanto meu método inicial atualizava o relógio constantemente, causando tempo para pular um pouco à medida que os instantâneos eram recebidos.
fonte
Basicamente, você não pode consertar o mundo [inteiro] e, eventualmente, terá que traçar a linha.
Se o servidor e todos os clientes compartilharem a mesma taxa de quadros, eles só precisarão sincronizar na conexão e, ocasionalmente, depois disso, especialmente após um evento de latência. A latência não afeta o fluxo de tempo ou a capacidade do PC para medi-lo, portanto, em muitos casos, em vez de interpolar, você deve extrapolar. Isso cria efeitos igualmente indesejados, mas, novamente, é o que é e você deve escolher o menor de todos os males disponíveis.
Considere que, em muitos MMO populares, os jogadores atrasados são visualmente óbvios. Se você vê-los funcionando no lugar, diretamente em uma parede, seu cliente está extrapolando. Quando o cliente recebe os novos dados, o reprodutor (no cliente) pode ter se deslocado uma distância considerável e irá "elástico" ou se teletransportar para um novo local (o "jerkiness" que você mencionou?). Isso acontece mesmo nos principais jogos de marca.
Tecnicamente, isso é um problema com a infraestrutura de rede do jogador, não com o seu jogo. O ponto em que ele vai de um para o outro é a própria linha que você deve desenhar. Seu código, em 3 computadores separados, deve registrar mais ou menos a mesma quantidade de tempo decorrido. Se você não receber uma atualização, isso não afetará sua taxa de quadros Update (); se houver, deve ser mais rápido, pois provavelmente há menos para atualizar.
"Se você tem internet ruim, não pode jogar este jogo de forma competitiva."
Isso não é uma farsa ou um bug.
fonte