Loop do jogo do lado do servidor

8

Muitos jogos java usam thread.sleep () para controlar fps. Como o servidor não exibe gráficos, o loop do jogo do servidor deve continuar em execução apenas calculando o tempo delta? Como este exemplo:

long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;   

while (gameRunning)
{
   long now = System.nanoTime();
   long updateLength = now - lastLoopTime;
   lastLoopTime = now;
   double delta = updateLength / ((double)OPTIMAL_TIME);

   doGameUpdates(delta);
}
Wolfrevo Kcats
fonte
11
"Muitos jogos java usam thread.sleep () para controlar fps" Cara, espero que não.
MichaelHouse
11
@ Byte56 Eu não diria muitos, mas alguns podem fazer uma coisa dessas. Embora sleepig seja algo comum, seu mecanismo não é predefinido. Thread.Sleepé a maneira mais simples, alguns podem esperar por interrupções do sistema operacional. Você pode até contar o vSync como um mecanismo de suspensão.
precisa saber é o seguinte

Respostas:

6

Há muitas razões pelas quais eu não sugeriria que:

  1. Os recursos do computador são valiosos. mesmo que sejam gratuitos, você não deve desperdiçá-los. considere o caso em que dois ou mais servidores estão sendo executados simultaneamente em um computador. Se uma única instância do servidor consumir todos os ciclos da CPU, outras instâncias simplesmente falharão. O sistema operacional certamente tentará lidar com esse tipo de comportamento ganancioso, mas terá um custo. Você não saberá onde o SO fará uma pausa no processo e dará ciclos de CPU para o outro. Além disso, você pode querer liberar seu servidor ao lado do jogo real, para que os jogadores possam iniciar seus próprios jogos de LAN. É meio chato se eu dediquei um dos meus núcleos de CPU apenas para rodar um servidor de jogos!

  2. A maioria dos jogos, especialmente jogos sincronizados em rede, usa um intervalo de tempo fixo. simplesmente porque eles querem ser capazes de prever o que vai acontecer no lado do cliente. A etapa de tempo dinâmico é ótima por vários motivos, desde que você esteja executando uma única instância do seu jogo e não seja sincronizada com nenhum outro lugar. Isso lhe concederá o poder do sistema executando o jogo em sua extensão máxima. Mas, novamente, há um preço por isso. Você não será capaz de prever o que acontecerá se executar o jogo novamente. considere a simples colisão física, em que uma caixa está atingindo outra. Mesmo a menor mudança no intervalo de tempo resultará em grandes diferenças na resolução de colisão resultante.

  3. Há uma razão simples para as pessoas usarem o Thread.Sleep como você sugeriu, porque adicionar mais precisão não resultará em um jogo melhor. Quando você está jogando, normalmente não notará se um objeto está a um ou dois pixels de distância. Portanto, você não ganhará nada aumentando a precisão. Também há um limite de largura de banda da rede, do lado do servidor e do cliente. Isso significa que você normalmente não poderá enviar mais de 30 a 60 atualizações por segundo. Então, eu posso perguntar por que você deveria calcular os estados que simplesmente jogará fora?

  4. Existem muitos casos em que o aumento da precisão pode causar problemas. Por exemplo, as pessoas tendem a usar "Sincronização vertical" para que o buffer gráfico não seja atualizado enquanto envia dados ao monitor (o que pode resultar em quebra). Além disso, a maioria dos jogos usa carros alegóricos como seu número principal, mas eles não são precisos. Você pode não perceber quando os números estão entre 2 ^ -20 e 2 ^ 20, mas fora desse intervalo, você verá comportamentos imprecisos. Por exemplo, se você tentar adicionar 10 ^ -5 a 10 ^ 5, simplesmente ignorará sua adição. Esses erros geralmente não são visíveis, mas quando você não tem controle total sobre o seu passo de tempo, as coisas podem ficar feias. No seu caso, como não há renderização, assumirei que o tempo de atualização deve ser algo em torno de 10 ^ -4, no máximo, o que significa que todas as alterações para números acima de 100 serão alteradas!

  5. Em alguns jogos, são apenas os comandos dos jogadores que fazem diferenças imprevisíveis. portanto, você pode querer usar apenas o servidor para transmitir os comandos de cada jogador para os outros jogadores. Nesses casos, você pode simplesmente esperar até que um dos clientes envie ao servidor uma atualização. Não há nada a ser calculado entre essas atualizações, o que significa que os clientes podem fazer tudo (além da transmissão ampla); portanto, deixe o servidor apenas fazer seu trabalho e deixar qualquer coisa para os clientes.

Ali1S232
fonte
Obrigado, você fez bons comentários lá. Eu acho que não preciso de timestep variável. Só mais uma coisa, o que você sugere como mecanismo de dormir?
Wolfrevo Kcats
@WlofrevoKcast É completamente baseado nas necessidades do seu jogo, mas para a maioria dos jogos, os temporizadores de idioma interno (ou interrupções no tempo do SO) são uma boa escolha.
Ali1S232
4

Você deve ler isso (timestep semi-fixo ou totalmente fixo?) E isso (Gaffer on Games - Fix your Timestep) .

Não sei por que você está incluindo um FPS de destino na lógica do servidor. Encontre uma etapa de tempo fixo que funcione para você e atualize de acordo com isso.

Basicamente, você terá outro loop while dentro do while (gameRunning)loop que acumulará tempo até que esteja pronto para fazer uma atualização. Então você está fazendo atualizações em intervalos fixos.

MichaelHouse
fonte