Sincronización de movimiento basada en fichas multijugador

8

Tengo que sincronizar el movimiento de varios jugadores a través de Internet, y estoy tratando de encontrar la forma más segura de hacerlo.

El juego está basado en fichas, solo puedes moverte en 4 direcciones, y cada movimiento mueve el sprite 32px (con el tiempo, por supuesto). Ahora, si simplemente enviara esta acción de movimiento al servidor, que la transmitiría a todos los jugadores, mientras la tecla de caminar se mantiene presionada, para seguir caminando, tengo que tomar el siguiente comando, enviarlo al servidor, y para todos los clientes, a tiempo, o el movimiento ya no será fluido. Vi esto en otros juegos, y puede ponerse feo bastante rápido, incluso sin retraso. Así que me pregunto si esta es incluso una opción viable. Sin embargo, este parece ser un método muy bueno para un solo jugador, ya que es fácil y directo (solo toma la siguiente acción de movimiento a tiempo y agrégalo a una lista), y puedes agregar fácilmente el movimiento del mouse (haciendo clic en un mosaico), para agregar un camino a una cola, eso se camina.

Lo otro que me vino a la mente fue enviar la información de que alguien comenzó a moverse en alguna dirección, y nuevamente una vez que se detuvo o cambió la dirección, junto con la posición, para que el sprite aparezca en la posición correcta, o más bien para que la posición se puede arreglar si está mal. Esto (con suerte) solo debería causar problemas si alguien realmente está rezagado, en cuyo caso es de esperar. Sin embargo, para que esto funcione, necesitaría algún tipo de cola, donde los cambios de dirección entrante y las cosas se guardan, para que el sprite sepa a dónde ir, después de que el movimiento actual al siguiente mosaico haya terminado. En realidad, esto podría funcionar, pero suena un poco complicado. Aunque podría ser la única forma de hacerlo, sin riesgo de tartamudeo. Si se recibe una parada o cambio de dirección en el lado del cliente, ' s se guarda en una cola y el personaje sigue moviéndose a las coordenadas especificadas, antes de detenerse o cambiar de dirección. Si el nuevo comando llega demasiado tarde, también habrá tartamudeos, por supuesto ...

Me está costando decidirse por un método, y todavía no pude encontrar ningún ejemplo para esto. Mi principal problema es mantener el movimiento del mosaico suave, por lo que otros temas relacionados con la sincronización del movimiento basado en píxeles no están ayudando demasiado.

¿Cuál es la forma "estándar" de hacer esto?

Marte
fuente

Respuestas:

4

Supongo que estás hablando de mudarte en tiempo real. Intentar interpolar la posición es probablemente una causa perdida; a través de una conexión lenta, su estado de juego podría estar cada vez más atrás del estado real del juego. A diferencia del otro comentario, recomendaría no poner mucha lógica de juego en el lado del servidor. Cuando implementé este tipo de soluciones, el cliente tiene un socket TCP para el servidor constantemente. Cuando el estado del juego cambia, envía un mensaje al servidor, como 'el cliente está en x = 10, y = 20'. El servidor envía el mensaje a los otros clientes, que intentan manejarlo en función de su propia lógica interna. El uso de TCP garantiza que sus mensajes lleguen en orden.

Desafortunadamente, incluso los juegos AAA no pueden manejar un retraso extremo; los jugadores ocasionalmente se moverán muy rápido, porque sus estados locales y de red están muy fuera de control. Monitorear el ping de ida y vuelta y patear a los usuarios que están demasiado lejos / lentos ayudará con esto.

Alan Gardner
fuente
1
+1 para "incluso los juegos AAA no pueden soportar un retraso extremo"; En realidad, nadie puede manejar incluso retrasos pequeños perfectamente. Sin embargo, podemos hacer que parezca que podemos.
Valmond el
3

Básicamente, así es como puede hacerlo de una manera simple y segura (advertencia, pseudocódigo extremo):

A) El cliente (playerid = 5) le pide al servidor que se mueva 'a la derecha' (o mejor, al mosaico 73,18)

B) El servidor verifica su gran mapa 2D que contiene jugadores (o ID de jugadores, por ejemplo):

 if(map[73][18] == occupied)
     Send back ('Not OK') to client (the case is blocked by another player)
else
    Set the new position as blocked: map[73][18]=5
    Release the old position: map[72][18]=0;
    Send a 'new position: 5, 73,18' message to all players who are nearby (moving client included)

C) Los clientes reciben un mensaje de 'nueva posición' (bueno, o el jugador 5 recibe el mensaje 'No está bien')

D) los clientes mueven lentamente el elemento que tiene playerid = 5 hacia su nueva posición (o lo crean si no tiene un elemento con playerid = 5)

Valmond
fuente
Bueno, gracias, pero mi problema es mantenerlo suave con los otros clientes durante varios movimientos continuos de mosaicos, no el movimiento de mosaicos en general ^^
Marte
Establezca la velocidad correctamente y compense el retraso con, por ejemplo, un cálculo muerto o simplemente un 'estúpido' 'movimiento hacia el objetivo a velocidad constante' (o velocidad proporcional sobre un cierto tesoro si envía marcas de tiempo a lo largo de las posiciones) y debería estar bien.
Valmond
1

Creo que el método que describiste es bastante bueno, especialmente en un juego simplista donde solo se permiten 4 movimientos. Así es como lo implementé.

No conozco ningún estándar, pero lo primero que me vino a la mente fue transmitir solo "cambios de entrada", cambios en la entrada de un jugador, de un jugador a los demás. Por ejemplo, puede transmitir solo mensajes en la línea de [tecla presionada, ID de tecla, hora] o [tecla liberada, ID de tecla, hora], y dejar que el juego de los jugadores actúe sobre estos cambios de entrada. Incluir el tiempo ayudará con la corrección de la ruta (si el jugador ha cambiado de dirección en el tiempo t, entonces el "avance" en el tiempo t + 1 deberá ser reparado).

Sin embargo, con esta solución puede encontrar el problema de mensajes perdidos; supongamos que nunca se envió el mensaje "clave liberada"? Algo que puede ayudar a esto es sondear periódicamente el estado del juego de un jugador y devolver la posición actual del jugador, así como cualquier tecla que se presione, o incluso devolver todo el estado del juego. Dependiendo del número de jugadores y comandos, puede ajustar esto para equilibrar el mensaje que pasa entre clientes / servidor para un buen equilibrio.

Otra cosa que puede considerar es la planificación de rutas. Por ejemplo, si el jugador ha estado avanzando durante 5 segundos, en los próximos milisegundos es probable que el jugador siga avanzando. En ese caso, puede crear una apariencia de predicción de ruta para evitar retrasos. Esto es esencialmente lo que está haciendo el método anterior, aunque esto puede tener en cuenta las rutas circulares.

¡Espero que esto haya ayudado!

Jonathan Pitre
fuente
1
El problema con solo enviar entradas es que si se pierde una sola o, a veces, simplemente las interpreta en el orden incorrecto, su estado de juego ya no estará bien, es decir. dos clientes mostrarán diferentes 'pantallas'.
Valmond
@Valmond muy buen punto ... de hecho, tengo ganas de eliminar mi respuesta, ya que, en ese sentido, se siente incorrecto.
Jonathan Pitre
1
Puede enviar las entradas al servidor (hasta que esté bien), pero el servidor debe (IMO) enviar datos exactos o al menos verificar los datos o tal vez enviar todo el estado del juego (esto se ha hecho en juegos reales, por ejemplo, Blood Bowl ), tal vez pueda modificar su respuesta en lugar de eliminarla :-)
Valmond