Estoy creando mi primer juego en línea usando socket.io, y me gustaría que fuera un juego multijugador en tiempo real como agar.io o diep.io.
Pero me he topado con el problema de tratar de descubrir cómo hacer que todas las computadoras funcionen a la misma velocidad.
Tengo tres ideas para modelos, pero ninguna parece correcta, y me pregunto cómo lo hacen los videojuegos normales. (Puedes saltarte la lectura de mis ideas; solo te dan una forma de ver los problemas que estoy teniendo).
El servidor permite que los clientes se ejecuten solos y pasen actualizaciones al servidor, que luego los transmite al resto de los clientes. Esto tiene el problema de que algunas computadoras funcionan más rápido que otras, lo que les permite actualizarse más rápido y moverse por la pantalla más rápido.
Haga que el servidor les diga a los clientes cuándo actualizar. Entonces puedo esperar hasta que el último cliente responda (una idea terrible en caso de que una persona tenga una computadora lenta), esperar hasta que el primer cliente responda (nuevamente, esperando la comunicación antes de cada trama), o simplemente enviarlos lo más rápido posible (que parece encontrarse con el mismo problema que el número 1).
Al comienzo del juego, haga que el servidor les diga a los clientes qué tan rápido deben actualizarse. Esto significaría que el cliente sería responsable de restringir el movimiento entre ese período de tiempo. Por ejemplo, si alguien de alguna manera logra presionar un botón dos veces dentro de ese período de tiempo, solo enviaría un evento de presión de botón. Esto tiene el problema de que algunas acciones serían ignoradas (como presionar dos veces el botón), y que la interacción dependería del reloj del cliente, que podría no coincidir con el reloj del servidor. El servidor tendría que hacer un seguimiento de cada cliente y asegurarse de que sus actualizaciones se envíen en el momento correcto.
He investigado un poco , pero los artículos que leo no parecen abordar específicamente qué hacer si un cliente envía actualizaciones más rápido que otros clientes.
En mi caso particular, estoy tratando con personas que tienen velocidades de teclado más rápidas (su computadora enviaría más actualizaciones de teclado que otras computadoras).
¿Cómo suelen lidiar los programadores con esto?
fuente
Respuestas:
Su tercera idea parece ser la más cercana a lo que considero como la solución de la industria a este tipo de problema.
Lo que estás describiendo se conoce comúnmente como Ticks . En cada marca, se procesaría un número fijo de acciones para cada cliente en serie. Muchas veces, los servidores de juegos tendrán algunas acciones paralelas cuando sean capaces, pero este es un problema mucho más complicado.
Un tic probablemente tendrá la forma de 1 / N segundos, siendo N el número de ticks por segundo o Tickrate. Este tickrate puede ser muy frecuente o muy poco frecuente, dependiendo de su caso de uso. Mi sugerencia personal sería evitar un tickrate superior a 60 tics / segundo a menos que esté seguro de que necesita más. Probablemente no :)
Las acciones deben ser atómicas. Por ejemplo, en slither.io, una acción como moverse no debe procesar de inmediato algo como romper la cadena, a menos que el jugador que golpeó ya haya tomado su movimiento. Esto puede parecer trivial para algo en el nivel de píxeles, pero si se trata de un movimiento basado en mosaicos, se vuelve mucho más obvio y garantiza la equidad. Si el jugador A se mueve a la casilla X, Y y el jugador B se encuentra actualmente en esa casilla, debes asegurarte de que al final de la marca, el jugador B todavía estará en esa casilla para que cualquier acción tenga lugar entre ellos.
Además, diría que evite que cualquiera de sus cálculos se realice en el lado del cliente a menos que se realicen de forma independiente en el lado del servidor. Esto se vuelve complicado y costoso con la física (muchos juegos optan por una tasa de tics más baja para la física que muchas otras acciones y eventos debido a esto)
Como referencia, aquí hay un buen enlace para complementar su propia comprensión de los servidores de juegos y las redes multijugador.
Por último, diría que no dejes que la justicia arruine tu servidor. Si hay exploits que hacen que tu juego sea injusto, arréglalos. Si se trata de que una computadora mejor tenga una ligera ventaja, diría que puede que no sea tan importante.
fuente
El siguiente sistema se asegura de que todos los clientes y el servidor compartan casi el mismo estado de juego en cualquier momento.
Tener el estado del juego tanto en el cliente como en el servidor.
Cuando un cliente intenta usar un comando (mouse, teclado, etc. otra entrada), mire su estado del juego si es válido.
Si es así, envíe el comando al servidor, sin ejecutarlo en el cliente emisor.
Cuando el servidor recibe el comando, observe su estado del juego si es válido.
Si es así, envíe el comando de regreso a TODOS los clientes con la fecha futura exacta después de lo que debería haber terminado de ejecutarse en el servidor, luego ejecute las acciones solicitadas por el comando después de un retraso igual al tiempo mínimo para enviar el comando a los clientes . luego registre la fecha, esto ayuda a hacer predicciones futuras. Si el tiempo varía demasiado, haga que su sistema de juego sea más determinista.
Cuando un cliente recibe un comando del servidor, mire su estado del juego si es válido, ejecute inmediatamente las acciones solicitadas por el comando, luego mire la fecha actual y compárela con la predicción de fecha recibida. Si no es válido, el cliente no está sincronizado. (Todos los clientes con una conexión similar reciben al mismo tiempo)
Si la fecha es anterior, tiene un problema en el paso anterior, corríjalo. Si la fecha es un poco después de no hacer nada, si la fecha es mucho después, el cliente no está sincronizado, es decir, el cliente se retrasa demasiado.
Cuando un cliente no esté sincronizado, solicite una copia del estado del juego completo del servidor y utilícelo. Si eso sucede con demasiada frecuencia, corríjalo porque es más costoso que enviar comandos.
En los clientes, renderice cosas en la pantalla SOLAMENTE cuando no quede nada más que hacer. En escenarios simples, la función de procesamiento solo toma el estado actual del juego como entrada.
Además de eso, puede optimizar mucho, utilizando sistemas predictivos, agrupando comandos, renderizando solo diferencias, etc.
La validación debe diferir, por ejemplo, depende del servidor limitar las solicitudes de comando / unidad de tiempo.
fuente
No sé si este es un problema de las bibliotecas o el entorno que está utilizando, pero creo que lo está abordando totalmente mal.
En la gran mayoría de los juegos multijugador, solo el servidor está haciendo cálculos reales. Los clientes son solo máquinas tontas de E / S donde el único problema de rendimiento real es dibujar gráficos en 3D. Y en ese caso, no importa si el cliente puede ejecutarse a 20 o 200 FPS, porque eso solo afecta a las imágenes. Eso significa que "actualización del cliente" no tiene absolutamente ningún significado. El cliente podría intentar "predecir" qué servidor podría calcular, pero eso es solo para suavizar la sensación de juego y no tiene un impacto real en el juego en sí.
Ni siquiera sé lo que eso significa. La mayoría de las personas ni siquiera pueden mantenerse al día con la velocidad de los teclados de gama baja, entonces, ¿cómo afectaría eso al rendimiento de los jugadores?
De lo contrario, la pregunta parece demasiado amplia y, en cambio, debería centrarse en un solo problema real, en lugar de tratar de inventar un problema "general" que ni siquiera podría tener.
fuente