Lazo del juego del lado del servidor

8

Muchos juegos de Java usan thread.sleep () para controlar fps. Dado que el servidor no muestra gráficos, ¿el ciclo del juego del servidor debe seguir ejecutándose solo calculando el tiempo delta? Como este ejemplo:

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
fuente
11
"Muchos juegos de Java usan thread.sleep () para controlar fps" Hombre, espero que no.
MichaelHouse
1
@ Byte56 No diría muchos, pero algunos podrían hacer tal cosa. Aunque sleepig es algo común, su mecanismo no está predefinido. Thread.Sleepes la forma más simple, algunos podrían esperar interrupciones del sistema operativo. Incluso puede contar vSync como un mecanismo de suspensión.
Ali1S232

Respuestas:

6

Hay muchas razones por las que no sugeriría que:

  1. Los recursos informáticos son valiosos. incluso si son gratis, no debes desperdiciarlos. considere el caso en el que dos o más servidores se ejecutan simultáneamente en una computadora. Si una sola instancia del servidor consume todos los ciclos de la CPU, otras instancias simplemente fallarán. Surly OS intentará manejar este comportamiento un poco codicioso, pero tendrá un costo. No sabrá dónde detendrá el sistema operativo su proceso y le dará ciclos de CPU al otro. También es posible que desee lanzar su servidor junto con el juego real, para que los jugadores puedan iniciar sus propios juegos de LAN. ¡Es un poco molesto si he dedicado uno de mis núcleos de CPU solo para ejecutar un servidor de juegos!

  2. La mayoría de los juegos, especialmente los juegos sincronizados en red, usan un paso de tiempo fijo. simplemente porque quieren poder predecir lo que sucederá del lado del cliente. El paso de tiempo dinámico es excelente por muchas razones, siempre que esté ejecutando una sola instancia de su juego y no se sincronice con ningún otro lugar. Te otorgará el poder del sistema que ejecuta el juego en toda su extensión. Pero de nuevo hay un precio por ello. No podrás predecir lo que sucederá si vuelves a ejecutar el juego. considere una colisión física simple, donde una caja golpea a otra caja. Incluso el más mínimo cambio en el paso del tiempo dará como resultado grandes diferencias en la resolución de colisión resultante.

  3. Hay una razón simple por la cual la gente usa Thread.Sleep como sugirió, porque agregar más precisión no dará como resultado un mejor juego. Cuando estás jugando un juego, generalmente no notarás si un objeto tiene uno o dos píxeles de distancia. Por lo tanto, no ganará nada al aumentar la precisión. También hay un límite de ancho de banda de red, tanto del lado del servidor como del lado del cliente. Lo que significa que generalmente no podrá enviar más de 30-60 actualizaciones por segundo. Entonces, puedo preguntar ¿por qué deberías calcular los estados que simplemente vas a tirar?

  4. Hay muchos casos en los que aumentar la precisión puede causar problemas. Por ejemplo, las personas tienden a usar "Sincronización vertical" para que el búfer de gráficos no se actualice mientras envía datos al monitor (lo que podría provocar una rotura). Además, la mayoría de los juegos usan flotadores como contenedor de números primarios, pero no son precisos. Es posible que no note cuando los números están entre 2 ^ -20 y 2 ^ 20, pero fuera de ese rango verá comportamientos inexactos. Por ejemplo, si intenta agregar 10 ^ -5 a 10 ^ 5, simplemente ignora su adición. Estos errores no suelen ser visibles, pero cuando no tienes un control total sobre tu paso de tiempo, las cosas pueden ponerse feas. En su caso, dado que no hay representación involucrada, supondré que su tiempo de actualización debería ser de alrededor de 10 ^ -4 como máximo, lo que significa que todos los cambios para los números superiores a 100 estarán en mal estado.

  5. En algunos juegos, son solo los comandos del jugador los que marcarán diferencias impredecibles. por lo que es posible que solo desee utilizar su servidor para transmitir los comandos de cada jugador a los otros jugadores. En estos casos, simplemente puede esperar hasta que alguno de los clientes envíe una actualización al servidor. No hay nada que calcular entre esas actualizaciones, lo que significa que los clientes pueden hacer todo (además de la transmisión amplia), así que deje que el servidor solo haga su trabajo y deje cualquier otra cosa a los clientes.

Ali1S232
fuente
Gracias, hiciste buenos puntos allí. Creo que no necesito tiempos variables. Solo una cosa más, ¿qué sugieres como mecanismo para dormir?
Wolfrevo Kcats
@WlofrevoKcast Se basa completamente en las necesidades de su juego, pero para la mayoría de los juegos, los temporizadores de idioma interno (o las interrupciones de tiempo del sistema operativo) son una opción lo suficientemente buena.
Ali1S232
4

Debería leer esto (¿Semi-fijo o Completamente fijo?) Y esto (Gaffer en Juegos - Repare su Timestep) .

No estoy seguro de por qué está incluyendo un FPS objetivo en la lógica de su servidor. Encuentre un paso de tiempo fijo que funcione para usted y actualícelo de acuerdo con eso.

Básicamente, tendrá otro ciclo while dentro de su while (gameRunning)ciclo que acumulará tiempo hasta que esté listo para realizar una actualización. Entonces estás haciendo actualizaciones a intervalos fijos.

MichaelHouse
fuente