Timestep no jogo multiplayer

8

Estou tentando entender o conceito de criar uma experiência multijogador servidor / cliente.

Meu problema está principalmente relacionado ao timestep. Considere o seguinte cenário:

Um cliente se conecta a um servidor. O cliente envia suas entradas para o servidor para indicar que deseja mover. O servidor simula a entrada e determina a posição desse cliente no mundo do jogo.

Como o cliente e o servidor estão sendo executados em diferentes intervalos de tempo, como você simula com precisão para que todos os clientes estejam sincronizados com o servidor? No momento, meu servidor está definido em 30 ms. Quando eu processo movimentos de clientes, há potencialmente centenas de solicitações aguardando para serem processadas, mas não há maneira de indicar quanto tempo levou entre cada uma delas.

Eu realmente não estou entendendo como simular corretamente no servidor com base no tempo, para que tudo seja sincronizado.

jgallant
fonte

Respostas:

3

Simplificando, você precisa enviar um carimbo de data / hora com cada instantâneo do servidor e com cada entrada do cliente.

Nas duas extremidades, é necessário um processo para "preencher" os quadros em que os pacotes não são recebidos.

No meu jogo (um jogo de ação em ritmo acelerado - o seu pode ser diferente), no servidor, descarto qualquer entrada "mais antiga" (fora de ordem) e acho que, se nenhum novo pacote de entrada chegar, os mesmos botões continue sendo pressionado (há um pouco mais de material para garantir que os pressionamentos / liberações curtos de botões sejam tratados, mas essa é a premissa básica).

No cliente, mantenho um "buffer de atraso" (descrito neste artigo que o Tetrad vinculou). Eu uso uma média rotativa dos tempos de chegada para garantir que o buffer de atraso permaneça o comprimento certo - tornando o jogo do cliente um pouco mais lento ou mais rápido. Se os instantâneos não chegarem a tempo, eu faço extrapolação no cliente. Caso contrário, eu interpolo entre os instantâneos no buffer.

O cliente também é responsável por rastrear o tempo de ida e volta de entradas e usá-lo para previsão (o servidor envia de volta o registro de data e hora da entrada que ele usou ao calcular um determinado quadro). Ele armazena em buffer as entradas por esse período de tempo, reproduzindo-as para assumir a posição do jogador da posição "antiga" (na captura instantânea do servidor) para a posição "presente" prevista.

Basicamente, o servidor continua funcionando a uma taxa de quadros fixa. Depende dos clientes permanecerem sincronizados com o servidor.

Obviamente, esta é apenas uma visão geral de alto nível. Há muitos detalhes minuciosos que você precisa descobrir ao implementá-lo.

Andrew Russell
fonte
Se o servidor receber 10 comandos de entrada de um cliente entre uma etapa do servidor. O servidor executa os 10 comandos de entrada. Como sabemos quanto tempo simular cada comando de entrada? E se você receber apenas um comando de entrada, você simula o comando durante todo o período de tempo da etapa de tempo?
jgallant
11
@ Jon A maioria dos jogos de "ação" envia entrada como botão para cima / para baixo em cada quadro. O servidor usa apenas o estado recebido mais recente como o estado para esse tick de atualização. Pacotes descartados, atrasados ​​e fora de ordem são ignorados. (Pelo menos no nível básico - você pode, por exemplo, adicionar informações adicionais de seqüenciamento para que um estado muito breve para cima ou para baixo não seja ignorado, mesmo se descartado.) Isso é provavelmente o que você deve fazer para todas as entradas que tenham tempo associado . As ações baseadas em comando (por exemplo: "mover aqui" em um RTS) geralmente não têm uma duração associada - portanto, você simplesmente as executa em ordem.
Andrew Russell