Jogos multijogador. Parte 4: Demonstração

> May 3, 2021 |  Categorias:  Multiplayer   Multijogador  

Vamos a prática!

Temos aqui um demo que implementa os conceitos de Predição no Cliente, Reconciliação com o Servidor e Interpolação de Entidades. Este projeto foi desenvolvido usando a engine Godot (godotengine.org).

Os conceitos aqui implementados são universais e servem para qualquer engine, salvo diferenças de sintaxe e API que devem variar conforme a desenvolvedora da engine.

O código fonte deste projeto pode ser acessado neste repositório.

Para interagir com o demo, aguarde o carregamento e clique nele.

Use W,A,S,D para controlar o jogador azul e ↑, ← , ↓, → para controlar o jogador amarelo. A tecla F coloca o demo em tela cheia.

Para melhor performance, é recomendado o uso do navegador Google Chrome.



Funções do Cliente

Para começar, preencha o campo "latência" com algum valor. Pode ser alguma valor bem exagerado, como por exemplo, 1000 ms. Em seguida, teste a movimentação de um dos clientes.

Com a Predição desligada, observe que há um grande atraso entre o pressionar da tecla e a resposta do personagem desenhado na tela de um dos clientes. Sem a predição, o comando viaja até o servidor, é resolvido por lá e só depois volta para o cliente, onde finalmente o jogador observa o desenrolar de seus atos.

Ligando a predição, as coisas melhoram um pouco. O personagem começa a se mover na direção requisitada antes de receber a resposta do servidor. No entanto, logo ele é empurrado de volta para a posição anterior.

Para resolver isso, basta ligar a reconciliação. Agora, o movimento do personagem local é imediatamente aplicado através dos processos explicados nos artigos anteriores.

Observe também a diferença na movimentação do personagem remoto ao ligar função Interpolação. Com essa função desligada, o personagem remoto se move da mesma maneira em que se move no servidor. Isto é, em intervalos de 20hz se estiver usando o valor padrão.

Taxa de atualização do servidor

Se você já brincou o suficiente com o demo, verá que a colisão entre os personagens, principalmente se a latência estiver muito alta, tende a apresentar problemas.

Isso ocorre por três motivos. O primeiro é a taxa de atualização do servidor. Ao aumentá-la para um valor mais alto, como por exemplo 60hz (o máximo permitido nesse demo), observa-se que há maior qualidade na detecção de colisões entre entidades.

O segundo motivo é a latência. Quanto menor o valor de latência, menos esses problemas são visíveis.

O terceiro motivo é a maneira como esse projeto implementa as taxas de atualização. A função Atualizar() no script Servidor.gd não leva em conta as possíveis flutuações em seu tempo de execução. Isto é, nem todo intervalo entre as execuções desta função é de 20hz. Existem algumas maneiras de resolver isso:

Uma delas é implementar um loop que seja capaz de integralizar as diferenças no tempo de execução usando interpolação. Há uma boa explicação desta técnica no artigo publicado por Glenn Fiedler, Fix Your Timestep! Note que essa técnica exige que a engine seja capaz de separar os loops responsáveis pela física e pela renderização do jogo;

Outra maneira de resolver esse problema é utilizar as opções de sua engine. No Godot, podemos fixar os intervalos de atualização em uma taxa específica acessando o menu Project > Project Settings, aba General, item Physics, subitem Common. Nesta tela, os intervalos de atualização podem ser ajustados na opção Physics Fps. No Unity, o mesmo pode ser feito usando as funções Time.fixedDeltaTime e Time.maximumDeltaTime.

Referências

Não deixe de checar as referências que usei para escrever esta série de artigos!

Obrigado por ler!