Cómo lidiar con computadoras más rápidas en un videojuego de cliente / servidor en tiempo real

15

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).

  1. 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.

  2. 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).

  3. 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?

Pro Q
fuente
1
En mi experiencia, no lo hacen. Es por eso que existen máquinas de juego; los que pagan 5 mil dólares por un lanzallamas de última generación tienen automáticamente una ventaja de los que todavía usan un Commodore 64.
Robert Harvey
1
Entonces, ¿mi juego parecerá lento porque tenemos que jugar con el mínimo común denominador? Parece que el servidor del juego debe establecer el tempo y depende de los clientes mantener el ritmo o simplemente tendrá que retrasarse.
JeffO
33
Puede que esté malinterpretando la pregunta, pero lo que buscas es probablemente usar un modelo de cliente y servidor basado en tick. gamedev.stackexchange.com/questions/81608/... Básicamente solo procesas la entrada y la lógica cada X cantidad de tiempo (generalmente 1 / N segundos, como 1/60 para la lógica de 60Hz)
Christopher Wirt
44
Después de leer la pregunta un poco más, parece que estás demasiado concentrado en los aspectos del juego para el cliente. Si quieres un juego multijugador "justo", tu servidor tendrá que tener autoridad. Lo que significa que todo lo que le sucede a los clientes es verificado o hecho por el servidor. Luego restringe las cosas desde aquí, probablemente a través de un sistema basado en ticks como el anterior.
Christopher Wirt
1
Ah, código de red en tiempo real. El lugar más profundo y oscuro del desarrollo del juego. ¡Bienvenido a la nave, amigo!
T. Sar - Restablece a Monica el

Respuestas:

8

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.

Christopher Wirt
fuente
33
@ProQ vale la pena señalar que escribir un buen código de red no es trivial. Si su aplicación no funciona bien desde el principio y su código de red parece apestar, no se rinda. Incluso las personas que hacen eso para ganarse la vida todos los días tienen problemas con él. es sólo que dura!
T. Sar - Restablece a Monica el
0

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.

Walle Cyril
fuente
0

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í.

velocidades de teclado más rápidas

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.

Eufórico
fuente
las velocidades más altas del teclado no se trata de escribir, se trata de cuántos comandos se pueden enviar si mantiene presionada la tecla "avanzar" o la tecla "disparar".
gbjbaanb
@gbjbaanb ¿Y cómo es eso un problema? Solo debe preocuparse por los comandos presionados y liberados. No debería importarle lo rápido que lo actualice.
Eufórico
Le importa si estaba manejando todos los eventos como lo esperaba el OP: en el cliente Entonces, si presiona w, avanza un poco más lejos, y su teclado es más rápido que el de otra persona, iría más rápido que ellos. ¡Lo último que quieres es hacer un juego de carreras en el que tengas que seguir presionando una tecla para avanzar!
gbjbaanb
@gbjbaanb No. Eso está mal. El servidor sabe que "el jugador está avanzando" y luego cada 1/60 del segundo actualiza las posiciones de TODOS los jugadores en función de si están avanzando. Así es como funcionan TODOS los juegos. El ciclo de actualización es el mismo para todas las entidades en el juego y las actualizaciones NO ESTÁN basadas en eventos de la IU.
Eufórico
1
No, eso no fue lo que el OP entendió, por eso lo preguntó y por qué dijo "Ni siquiera sé lo que eso significa". Si comprende la posición de los OP, entonces su pregunta tiene sentido. Si el OP ha codificado su juego para que funcione con un bucle de juego basado completamente en la rapidez con la que se entregan los eventos del cliente, entonces eso es lo que está preguntando: está equivocado al aplicar un diseño de juego hipotético a lo que realmente está preguntando el OP, independientemente de si su diseño es incorrecto para la mayoría de los estándares.
gbjbaanb