¿Cómo sincronizo el estado del juego multijugador de manera más eficiente que las actualizaciones de estado completo?

10

He hecho una pequeña codificación de red de juegos antes, pero principalmente con TCP para juegos sin necesidades en tiempo real. Estoy trabajando en un juego Java 2D con multijugador en red. Para aprender, quiero hacerlo yo mismo, sin una API de red existente.

¿Cómo represento eficientemente el estado del juego enviado a los clientes desde un servidor? Existe la forma más obvia pero probablemente menos eficiente, que sería crear algún tipo de objeto de contexto de estado del juego con la ubicación de cada jugador, estado de animación, etc., y enviarlo a cada jugador cada actualización . Eso no parece terriblemente difícil de implementar, pero probablemente sería demasiado grande para lograr algo cercano a la interacción en tiempo real (por supuesto, mi experiencia con esto es limitada, por lo que puedo ser incorrecto).

¿Hay alguna forma sólida de que alguno de ustedes haya usado antes solo para transmitir cambios de estado, y hay incluso una disparidad lo suficientemente grande como para que valga la pena el trabajo extra?

Haz
fuente
2
Pruebe el estado completo en cada fotograma y si es demasiado lento (para un juego 2D algo simple, probablemente sea lo suficientemente eficiente), intente optimizar. Si funciona bien, entonces funciona bien y no tiene que cambiarlo a menos que note que su red es un cuello de botella más tarde.
Robert Rouhani

Respuestas:

10

Transmitir el estado del juego completo con regularidad es por lo general no es factible, aunque no depende mucho de la complejidad de que juego. Para un juego simple con un modelo de mundo pequeño, puede funcionar.

Personalmente he tenido mucho más éxito con el siguiente modelo:

  • Estado del juego almacenado en un modelo de objeto bien definido en una estructura de datos espaciales (por ejemplo, un octree)
  • Todos los cambios en el estado del juego (ya sea en el cliente o en el servidor) se describen como eventos. Un evento puede ser un cambio de propiedad en un objeto de juego, un cambio en un mosaico de mapa, el movimiento de un objeto de juego, etc.
  • El motor del juego en el servidor produce una secuencia de eventos a medida que avanza el juego. Estos se aplican directamente al estado del juego del servidor.
  • Los eventos también se envían a los jugadores, pero solo si el evento es relevante para ese jugador (por ejemplo, ¿el evento es visible desde la posición actual?)
  • Los cambios en la visibilidad del jugador también pueden dar lugar a eventos para "revelar" nuevas partes del mapa, etc. cuando el jugador se mueve. Esto también se puede utilizar para garantizar que el jugador obtenga una vista inicial precisa del estado del juego relevante cuando se une por primera vez al juego.
  • El estado del juego para el jugador se actualiza con los eventos que recibe. Como tal, solo tiene un modelo parcial del estado del juego, pero debe permanecer sincronizado con el servidor, suponiendo que todos los eventos se procesen correctamente

Esto me ha proporcionado un buen rendimiento incluso con mundos de juego bastante grandes.

Otro consejo, deje que el cliente se encargue de la animación, los efectos de partículas, etc., sin referencia al servidor. No tiene sentido transmitirlos, solo necesitan ser "activados" por los eventos del juego apropiados.

mikera
fuente
6

La sincronización generalmente se divide en dos partes: incremental y absoluta.

A veces debe transmitir todo, es grande, pero si lo empaqueta de la manera correcta, puede hacerlo una vez cada pocos segundos. Es bueno poner todo en su lugar, corrigiendo las fallas de las actualizaciones incrementales.

Para lograr una experiencia en tiempo real, debe transmitir algunos cambios rápidamente, pero solo los atributos que pueden cambiar. Por ejemplo, si un cohete vuela en línea recta, no necesita actualizar la posición, cada cliente puede calcularlo desde el punto de partida. Pero cuando golpea, puede generar un mensaje al respecto, para que cada cliente pueda explotar el cohete en el lugar correcto. Los pequeños fallos pueden ser ignorados.

¡Por supuesto que solo actualiza cosas, cuando pueden influir en el cliente! Algo alejado de la pantalla no vale la pena. Algunos valores se pueden actualizar con menos frecuencia. Por ejemplo, las posiciones son importantes para ser más o menos precisos, los eventos (muerte, disparo, explosión, etc.) deben enviarse instantáneamente, mientras que los valores no directamente importantes pueden tener períodos de actualización más bajos, por ejemplo, el marcador, el chat.

El embalaje de datos también es importante. Puede transmitir aproximadamente 1400 bytes (dependiendo de la configuración, este es el valor predeterminado) en un paquete UDP, generalmente hay unos pocos bytes de encabezado. Por lo tanto, puede actualizar fácilmente 50-100 unidades de posición en un paquete.

Matzi
fuente
Gracias por el consejo Matzi. Todavía estoy trabajando en la implementación del servidor y el cliente, pero volveré a consultar en un par de días y probablemente acepte su respuesta.
Haz
¡Buena suerte para ti! ;)
Matzi
1

Dependiendo de su juego, puede considerar un modelo de "ejecución sincronizada" donde cada cliente juega el mismo juego simplemente compartiendo entradas no deterministas como entradas de teclado / joystick y eventos de temporizador. (En comparación con un modelo donde cada cliente ejecuta simulaciones locales y espera integrar resultados de simulaciones remotas). Su motor de juego generalmente necesita ser completamente determinista para que esto funcione, lo que puede ser una carga pesada dependiendo del juego. Pero si el juego ya es determinista, este puede ser un enfoque más fácil.

Esta publicación #AltDevBlogADay cubre algunos aspectos de este enfoque en un RTS moderno (específicamente cómo detectar cuándo sus clientes comienzan a ejecutar juegos "diferentes").

Sin embargo, recuerde mantenerlo simple hasta que se demuestre lo contrario. :)

PT
fuente
1
Estas son buenas lecturas del desarrollador de Factorio que usa este enfoque, y apuntan a la complejidad de este enfoque, pero también muestran que es viable: factorio.com/blog/post/fff-76 factorio.com/blog/post/fff -147 factorio.com/blog/post/fff-188
AaronLS