Estoy trabajando en un tirador 2D de arriba hacia abajo y estoy haciendo todo lo posible para copiar conceptos utilizados en juegos en red como Quake 3.
- Tengo un servidor autorizado.
- El servidor envía instantáneas a los clientes.
- Las instantáneas contienen una marca de tiempo y posiciones de entidad.
- Las entidades se interpolan entre las posiciones de las instantáneas para que el movimiento se vea suave.
- Por necesidad, la interpolación de entidades ocurre levemente "en el pasado" para que tengamos múltiples instantáneas en las que interpolar.
El problema al que me enfrento es la "sincronización del reloj".
- En aras de la simplicidad, imaginemos por un momento que no hay latencia al transferir paquetes desde y hacia el servidor.
- Si el reloj del servidor está 60 segundos por delante del reloj del cliente, entonces una marca de tiempo de la instantánea estará 60000ms por delante de la marca de tiempo local del cliente.
- Por lo tanto, las instantáneas de la entidad se recopilarán y se sentarán durante unos 60 segundos antes de que el cliente vea que una entidad determinada realiza sus movimientos, ya que el reloj del cliente tarda tanto en ponerse al día.
Logré superar esto calculando la diferencia entre el servidor y el reloj del cliente cada vez que se recibe una instantánea.
// For simplicity, don't worry about latency for now...
client_server_clock_delta = snapshot.server_timestamp - client_timestamp;
Al determinar qué tan avanzada está la entidad en la interpolación, simplemente agrego la diferencia a la hora actual del cliente. Sin embargo, el problema con esto es que causará sacudidas porque la diferencia entre los dos relojes fluctuará abruptamente debido a que las instantáneas llegan más rápido / más lento que otros.
¿Cómo puedo sincronizar los relojes lo suficientemente cerca como para que el único retraso perceptible sea el codificado para la interpolación y el causado por la latencia de red ordinaria?
En otras palabras, ¿cómo puedo evitar que la interpolación comience demasiado tarde o demasiado pronto cuando los relojes se desincronizan significativamente, sin introducir sacudidas?
Editar: según Wikipedia , NTP se puede utilizar para sincronizar relojes a través de Internet en cuestión de unos pocos milisegundos. Sin embargo, el protocolo parece complicado, ¿y quizás excesivo para usar en juegos?
Respuestas:
Después de buscar, parece que sincronizar los relojes de 2 o más computadoras no es una tarea trivial. Un protocolo como NTP hace un buen trabajo, pero supuestamente es lento y demasiado complejo para ser práctico en los juegos. Además, utiliza UDP, que no funcionará para mí porque estoy trabajando con sockets web, que no admiten UDP.
Sin embargo, encontré un método aquí , que parece relativamente simple:
Afirma sincronizar relojes a menos de 150 ms (o mejor) entre sí.
No sé si eso será lo suficientemente bueno para mis propósitos, pero no he podido encontrar una alternativa más precisa.
Aquí está el algoritmo que proporciona:
Esta solución parece responder a mi pregunta satisfactoriamente bien, porque sincroniza el reloj y luego se detiene, permitiendo que el tiempo fluya linealmente. Mientras que mi método inicial actualizaba el reloj constantemente, haciendo que el tiempo saltara un poco a medida que se reciben instantáneas.
fuente
Básicamente, no puedes arreglar el mundo [entero] y, eventualmente, tendrás que dibujar la línea.
Si el servidor y todos los clientes comparten la misma velocidad de fotogramas, solo necesitan sincronizarse al conectarse, y ocasionalmente, a partir de entonces, especialmente después de un evento de latencia. La latencia no afecta el flujo de tiempo o la capacidad de la PC para medirlo, por lo que, en muchos casos, en lugar de interpolar, debe extrapolar. Esto crea efectos igualmente no deseados pero, de nuevo, es lo que es y debes elegir el menor de todos los males disponibles.
Considere que en muchos MMO populares, los jugadores rezagados son visualmente obvios. Si los ve corriendo en su lugar, directamente en una pared, su cliente está extrapolando. Cuando su cliente recibe los nuevos datos, el jugador (en su cliente) puede haberse movido una distancia considerable y se "teletransportará" o se teletransportará a una nueva ubicación (¿la "sacudida" que mencionó?). Esto sucede incluso en los principales juegos de marca.
Técnicamente, este es un problema con la infraestructura de red del jugador, no con su juego. El punto en el que va de uno a otro es la línea que tienes que dibujar. Su código, en 3 computadoras separadas, debería registrar más o menos la misma cantidad de tiempo transcurrido. Si no recibe una actualización, no debería afectar su velocidad de fotogramas Update (); en todo caso, debería ser más rápido ya que probablemente haya menos para actualizar.
"Si tienes Internet horrible, no puedes jugar este juego de manera competitiva".
Eso no es pasar el dinero o un error.
fuente