Estoy trabajando en un motor de juego multijugador servidor-cliente 2D (que puedes probar aquí ). Utiliza WebRTC DataChannel
s. (Las conexiones son de igual a igual, pero el igual de host todavía actúa como un servidor).
El mayor problema (aparte de la conectividad) es la predicción de entrada local. Hacemos lo habitual: al presionar las teclas, los jugadores se mueven instantáneamente, le dicen al host qué teclas se presionan, reciben los datos del host y los comparan con la posición histórica. La posición se corrige con el tiempo si hay una diferencia. Esto funciona bien con una baja pérdida de paquetes o PDV , incluso si el ping es alto.
Si hay pérdida o PDV, la desviación puede ser mayor. Creo que esto se debe a que si el primer paquete que indica un cambio de entrada se retrasa o se cae, el host se entera más tarde y comienza a cambiar ese jugador más tarde de lo que muestra su predicción de entrada local.
Si el jugador se está moviendo, aumentamos la cantidad de corrección aplicada, ya que es menos notable. Esto parece tapar huecos cuando comienza a moverse y mientras se mueve. Sin embargo, cualquier corrección es más notable si se detienen abruptamente. Luego, si el PDV o la pérdida significa que el host piensa que se detuvo más tarde, el host se sobrepasa, envía datos que dicen que están un poco más adelante, y la corrección hace que el jugador se desplace un poco. En conexiones escamosas, los jugadores a menudo se desvían notablemente después de detenerse.
No he notado esto en otros juegos. ¿Cómo se puede mitigar esto?
fuente
Respuestas:
La capa de red debe tener un reloj acordado. Pueden acordar un valor de reloj temprano en el juego (y volver a sincronizarlo periódicamente en caso de deriva) para que el host sepa cuánto tiempo tardó en llegar un paquete en particular y cuándo el cliente realizó la acción, y viceversa.
Consulte este artículo para conocer una posible forma de sincronizar relojes en juegos. Hay otros. Los medios específicos no importan.
La segunda mitad del problema es que el servidor está aplicando entradas más allá del tiempo que el cliente dejó de aplicar entradas. Esto requiere un búfer de movimientos pasados en el servidor y algo de lógica en el cliente para ignorar las entradas de movimiento del servidor más allá del último movimiento conocido.
Primero, el búfer del servidor. El servidor debe realizar un seguimiento del sello del reloj de la última entrada recibida del reproductor. También necesita todos los movimientos que aplica a un jugador, el sello del reloj del movimiento. Si se recibe una entrada, todos los movimientos recientes aplicados con un sello de reloj más nuevo que el paquete de entrada se descartan y todos los movimientos se vuelven a aplicar desde el paquete de entrada. Por lo tanto, si el servidor sobre mueve al jugador en base a alguna entrada, la entrada actualizada cancelará esos movimientos y la nueva posición del jugador se basará en el conocimiento de entrada más reciente que tenga el servidor.
En el lado del cliente, el cliente sabe cuándo envió la última entrada al servidor. Dado que la actualización de cada jugador del servidor debería haber sido etiquetada con el reloj de la última entrada que el servidor conocía, el cliente puede ignorar las actualizaciones del servidor que tienen una etiqueta de entrada vencida y simplemente seguir la predicción del cliente. Eventualmente, las nuevas actualizaciones del servidor llegarán con información actualizada y el cliente puede corregirlas.
El servidor necesita validar los relojes de entrada y asegurarse de que no se desvíen demasiado de las expectativas para evitar trampas. El reloj de entrada no debe ser drásticamente más grande que el tiempo de media vuelta que debe calcular. Sujete cualquiera que esté dentro de un rango razonable (
[Now-2*RTT,Now]
por ejemplo).Los clientes verán mucha inquietud de los avatares de otros jugadores si la latencia es alta, ya que recibirán actualizaciones del servidor basadas en la entrada obsoleta, pero no tienen forma de saber que está obsoleta y luego el servidor podría comenzar a enviar ubicaciones bastante diferentes según la entrada actualizada que recibió (y su eliminación de una parte de su historial y su reproducción con la nueva entrada). Este último problema con otros jugadores que ven su jitter de avatar no es realmente reparable. La latencia apesta y los jugadores atrapados en conexiones de alta latencia verán mucha inquietud de otros jugadores, incluso si su propio jugador se mueve sin problemas. La única corrección es jugar con mejores conexiones o con pares / servidores con menos latencia.
fuente
He usado mensajes UDP confiables para indicar cambios en el estado de los botones y mensajes UDP poco confiables para la corrección de posición. Básicamente, los siguientes artículos me ayudaron mucho: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
Dice sobre la predicción de movimiento almacenando estados de jugador en intervalos de tiempo constantes de acuerdo con la llegada de mensajes de corrección de posición para aproximadamente 20 o 30 salvaciones de estado. Por lo tanto, parece que sus jugadores remotos vivirán en un "pasado" no muy lejano aplicando constantemente la técnica de predicción :) En función de la latencia del mensaje neto, puede obtener la posición de su objeto aproximadamente a tiempo cuando el mensaje se acaba de enviar desde el host.
La posición actual "en pantalla" se puede traducir sin problemas a la posición predicha utilizando las matemáticas de Lerp (interpolación lineal). La idea es interpolar valores en los intervalos de tiempo entre los paquetes de corrección. Por lo tanto, parece que ese objeto mostrado siempre se mueve hacia alguna posición predicha. Para el valor de interpolación, tomo el 1 dividido por "latencia de mensaje medio" dividido por "tiempo de representación de trama medio" para que el movimiento se vea suave.
En este escenario, el juego calcula en todos los clientes y el servidor corrige los valores tales como la velocidad y la posición de vez en cuando.
Una cosa más que ayuda mucho en este caso: optimiza la lógica de tu juego para que puedas negar fácilmente los efectos de latencia asegurando que el servidor y los clientes puedan emular un comportamiento similar en función de la entrada del jugador.
Describí todo el esquema que utilicé en mi proyecto, así que espero que encuentres la respuesta a tu pregunta.
fuente