Estou criando meu primeiro jogo online usando o socket.io e gostaria que fosse um jogo multiplayer em tempo real como agar.io ou diep.io.
Mas me deparei com a questão de tentar descobrir como fazer com que todos os computadores funcionem na mesma velocidade.
Eu tenho três idéias para modelos, mas nenhuma delas parece certa, e me pergunto como os videogames normais fazem isso. (Você pode pular a leitura das minhas idéias; elas apenas fornecem uma maneira de ver os problemas que estou tendo.)
O servidor permite que os clientes executem por conta própria e transmitam atualizações ao servidor, que as transmite para o restante dos clientes. Isso tem o problema de que alguns computadores rodam mais rápido que outros, permitindo que eles sejam atualizados mais rapidamente e se movam pela tela mais rapidamente.
Peça ao servidor que informe aos clientes quando atualizar. Posso então esperar até o último cliente responder (uma péssima idéia no caso de uma pessoa ter um computador lento), esperar até o primeiro cliente responder (novamente, aguardando a comunicação antes de cada quadro) ou apenas enviá-lo o mais rápido possível (o que parece ter o mesmo problema que o número 1).
No início do jogo, peça ao servidor que informe aos clientes a velocidade de atualização. Isso significaria que o cliente seria responsável por restringir o movimento entre esse período. Por exemplo, se alguém conseguisse pressionar um botão duas vezes nesse período, enviaria apenas um evento de pressionamento de botão. Isso tem o problema de que algumas ações seriam ignoradas (como pressionar o botão duplo) e que a interação dependeria do relógio do cliente, que pode não corresponder ao relógio do servidor. O servidor precisará acompanhar cada cliente e garantir que suas atualizações sejam enviadas no momento correto.
Eu fiz algumas pesquisas , mas os artigos que li não parecem abordar especificamente o que fazer se um cliente enviar atualizações mais rapidamente do que outros clientes.
No meu caso particular, estou lidando com pessoas que possuem velocidades de teclado mais rápidas (o computador deles enviaria mais atualizações de teclado do que outros computadores).
Como os programadores geralmente lidam com isso?
fonte
Respostas:
Sua terceira ideia parece ser a mais próxima do que penso ser a solução da indústria para esse tipo de problema.
O que você está descrevendo é chamado de carrapatos . Em cada marca, um número fixo de ações seria processado para cada cliente em série. Muitas vezes, os servidores de jogos terão algumas ações paralelas quando capazes, mas esse é um problema muito mais complicado.
Um tick provavelmente terá a forma de 1 / N segundos, sendo N o número de ticks por segundo ou Tickrate. Esse tickrate pode ser muito frequente ou pouco frequente, dependendo do seu caso de uso. Minha sugestão pessoal seria evitar uma taxa de ticks acima de 60 ticks / segundo, a menos que você tenha certeza de que precisa de mais. Você provavelmente não :)
As ações devem ser atômicas. Por exemplo, no slither.io, uma ação como mover-se não deve processar imediatamente algo como quebrar sua corrente, a menos que o jogador que você acertar já tenha feito a jogada. Isso pode parecer trivial para algo no nível de pixels, mas se você estiver lidando com movimentos baseados em blocos, torna-se muito mais óbvio e garante justiça. Se o Jogador A se mover para o bloco X, Y e o Jogador B estiver nesse bloco, você deve garantir que, até o final do tique, o jogador B ainda esteja nesse bloco para que todas as ações ocorram entre eles.
Além disso, eu diria que evite fazer seus cálculos no lado do cliente, a menos que sejam feitos independentemente no lado do servidor. Isso fica complicado e caro com a física (muitos jogos optam por uma taxa de tick mais baixa para a física do que muitas outras ações e eventos por causa disso)
Para referência, aqui está um bom link para complementar seu próprio entendimento de servidores de jogos e redes multiplayer.
Por fim, eu diria que não deixe a justiça arruinar seu servidor. Se houver explorações que façam com que seu jogo seja injusto, conserte-as. Se é uma questão de um computador melhor ter uma pequena vantagem, eu diria que pode não ser tão importante assim.
fonte
O sistema a seguir garante que todos os clientes e o servidor compartilhem quase o mesmo estado do jogo a qualquer momento.
Tenha o estado do jogo no cliente e no servidor.
Quando um cliente tenta usar um comando (mouse, teclado, etc. outra entrada), verifique o estado do jogo, se for válido.
Se for, envie o comando para o servidor, sem executá-lo no cliente remetente.
Quando o servidor receber o comando, verifique o estado do jogo, se for válido.
Se for, envie o comando de volta para TODOS os clientes com a data exata do futuro após a execução no servidor, depois execute as ações solicitadas pelo comando após um atraso igual ao tempo mínimo para enviar o comando aos clientes . depois grave a data, isso ajuda a fazer previsões futuras. Se o tempo variar muito, torne seu sistema de jogo mais determinístico.
Quando um cliente recebe um comando do servidor, verifique seu estado do jogo, se for válido, execute imediatamente as ações solicitadas pelo comando, verifique a data atual e compare-a com a previsão de data recebida. Se não for válido, o cliente está fora de sincronia. (Todos os clientes com uma conexão semelhante recebem ao mesmo tempo)
Se a data for anterior, você teve um problema na etapa anterior, corrija-o. Se a data for um pouco depois, não faça nada. Se a data for muito depois, o cliente está fora de sincronia, ou seja, o cliente fica muito atrás.
Quando um cliente estiver fora de sincronia, solicite uma cópia de todo o estado do jogo do servidor e use esse. Se isso acontecer com muita freqüência, corrija isso porque é mais caro do que enviar comandos.
Nos clientes, renderize SOMENTE as coisas na tela quando não houver mais nada a fazer. Em cenários simples, a função de renderização leva apenas o estado atual do jogo como entrada.
Além disso, você pode otimizar muito, usando sistemas preditivos, comandos de agrupamento, renderização somente diffs, etc ...
A validação deve diferir, por exemplo, cabe ao servidor limitar as solicitações de comando / unidade de tempo.
fonte
Não sei se isso é problema de bibliotecas ou ambiente que você está usando, mas acho que você está abordando isso totalmente errado.
Na grande maioria dos jogos multiplayer, é apenas o servidor que está fazendo cálculos reais. Os clientes são apenas máquinas de IO idiotas, onde apenas um problema real de desempenho é desenhar gráficos 3D. E, nesse caso, não importa se o cliente pode executar a 20 ou 200 FPS, porque isso afeta apenas os recursos visuais. Isso significa que "atualização do cliente" não tem absolutamente nenhum significado. O cliente pode tentar "prever" o que o servidor pode calcular, mas isso é apenas para suavizar a sensação da jogabilidade e não tem nenhum impacto real na própria jogabilidade.
Eu nem sei o que isso significa. A maioria das pessoas nem consegue acompanhar a velocidade dos teclados de última geração, então como isso afetaria o desempenho dos jogadores?
Caso contrário, a questão parece muito ampla e você deve se concentrar em um único problema real, em vez de tentar inventar um problema "geral" que talvez nem tenha.
fonte