2010-06-22 36 views
37

Estoy pensando en crear un juego web multijugador en Node.js. Esto significa que usaré el mismo idioma en el backend y en la interfaz. Sería en tiempo real y cerca de 20 personas máximo en cada habitación ', así que tengo algunas ideas:Juego multijugador con backend y frontend JavaScript. ¿Cuáles son las mejores prácticas?

  1. ¿Cómo compensar el retardo entre todos los usuarios, de modo que todo el mundo ve la misma cosa al mismo tiempo ? Estoy pensando en rastrear el tiempo promedio de ping de cada jugador, encontrar el más lento e informar a los otros clientes del tiempo (en milisegundos) que deben retrasarse para que todos estén tan sincronizados como sea posible.

  2. Estoy pensando en ejecutar el código del juego tanto en el backend como en el frontend (ya que es JavaScript en ambos extremos) y tener un mecanismo de corrección de errores para sincronizar con el 'juego real' en el back-end . De esta forma, el juego debería funcionar sin problemas en la interfaz y con solo algunas fallas técnicas cuando ocurre la sincronización. También eso minimizaría el pirateo de JavaScript de frontend ya que los tramposos se sincronizarían hasta el juego de back-end.

  3. Debería recibir acciones de jugador a través del socket (presionar teclas), informar a todos los demás clientes de las acciones de los otros jugadores y mientras tanto 'jugar' el juego en el backend y enviar información de sincronización a todos los jugadores estado de vez en cuando para sincronizarlos?

¿Qué opinas? ¿Hay más cosas que debería considerar o prestar atención?

Por favor, publique sus pensamientos o enlaces a la documentación o artículos sobre juegos multijugador.


EDIT: Estos son útiles:

+0

Más sobre el modelo de redes sismo se puede encontrar aquí: http://www.bluesnews.com/abrash/chap70.shtml – jbochi

Respuesta

1
  1. Éste es muy difícil de hacer, y puedo ver muchos problemas al sincronizar con 'el más lento'. ¿Puedes relajar esto para que los clientes puedan ser 'finalmente consistentes'?

  2. Suena bien.

  3. Enviaría eventos de acción corta de la interfaz al servidor, modificaría el estado del juego y publicaría los eventos de modificación del estado del juego a los clientes, prestando mucha atención a solo enviar los eventos necesarios a los suscriptores correctos. En este punto, puedes descartar cualquier evento que no parezca coincidir o que parezca falso/piratear.

+0

¿Nos puedes contar 'consistencia eventual'? Tengo al menos 1 objeto que todos deberían ver en el lugar correcto al mismo tiempo, o el juego no funcionaría, realmente no me importa que todos vean a todos en el mismo lugar/momento, pero uno o dos objetos pueden No estarás sincronizado o el juego fallará. (¿Quién puede adivinar el juego primero? He dado algunos consejos: P) – stagas

+0

Lo que significa que los eventos enviados en 3) desde el backend no llegarán de forma síncrona a todos los clientes (absolutamente imposible). Tal vez podría hacer que los clientes se reporten al servidor cuando hayan recibido un objeto en particular, aunque esto podría dar paso a la trampa. – Santi

+0

@stagas: ¿habrá 22 personas en la habitación? :) – Amnon

27

1 - es imposible. No sabe exactamente cuánto tardará un mensaje en llegar a un cliente y ninguna medición que tome se aplicará necesariamente al próximo mensaje que envíe. Lo mejor que puede hacer es una aproximación, pero siempre debe suponer que la gente verá O BIEN cosas ligeramente diferentes O las mismas cosas en tiempos ligeramente diferentes. Recomiendo simplemente enviar el estado actual a todos y usar la interpolación/extrapolación para suavizar la jugabilidad, de modo que todos vean el juego unos milisegundos en el pasado, con un retraso que varía tanto entre los jugadores como a lo largo del tiempo.En general, esto rara vez es un gran problema. Si realmente quieres almacenar en el búfer algunos estados pasados ​​en el servidor, puedes interpolar entre ellos y enviar diferentes datos antiguos a diferentes personas en un intento de sincronizar lo que ven, pero combinado con la simulación del lado del cliente y la inestabilidad en los tiempos de transmisión. Todavía veré algunas diferencias entre las máquinas.

2 - la forma típica es ejecutar la simulación en el servidor y enviar actualizaciones de estado regulares (pequeñas) a los clientes. Los clientes normalmente ejecutan sus propias simulaciones y tienen una forma de combinar su propio estado predicho/interpolado y el estado autoritario que el servidor les está enviando. Todas las decisiones que no sean de entrada del usuario deben hacerse en el lado del servidor. En definitiva, la forma en que combinas estos es solo una compensación entre una apariencia suave y un estado preciso, por lo que es una decisión cosmética que tendrás que tomar.

3 - su cliente normalmente debe traducir una pulsación de tecla a una acción lógica. Su servidor no se preocupa por las claves. Envíe esa acción lógica al servidor y puede transmitirla a otros clientes si la necesitan. Aunque en general no necesitarás hacer nada aquí, cualquier cambio relevante causado por la acción generalmente cambiará el estado del juego y, por lo tanto, se enviará en la transmisión normal de ese estado.

5

No abordaré sus puntos directamente porque las otras respuestas lo hacen tan bien. Pero, sugiero buscar en HTML5, WebSockets y Comet, que prometen mejorar significativamente el rendimiento en tiempo real. Estas tecnologías le permiten tener solicitudes HTTP de larga ejecución, lo que permite que el servidor envíe datos al cliente en lugar de que el cliente interrogue al servidor. Esto puede acelerar sustancialmente las cosas.

Éstos son algunos de los recursos que deben ser útiles:

+0

Gracias, agregué Socket.io también que es una implementación de WebSockets con un servidor y un cliente que se basa en otras tecnologías si no hay uno disponible. Muy útil. – stagas

0

Un enfoque típico no es tratar de forzar a todos los clientes a ejecutar en el mismo framerate bloqueado en el servidor ... simplemente se pone feo. En su lugar, envíe actualizaciones frecuentes para que los clientes puedan actualizar cada vez que reciban una nueva actualización.

Normalmente, un cliente predecirá cómo van las cosas durante períodos cortos, y luego se corregirá con una actualización del servidor. Puede aplicar correcciones de tiempo también. Por ejemplo, si el servidor le dice que "el jugador 2 está en P viajando a velocidad V", puede intentar conocer la antigüedad de ese mensaje en función de un ping reciente y corregir la posición desde P hasta P + x*D.

1

La mejor manera es realizar un seguimiento de todos los objetos en un solo lugar, es decir, el servidor. Todos verán la información de los servidores un tiempo de viaje más tarde de lo que realmente sucede y los comandos de las personas tomarán un viaje para registrarse en el servidor. Realmente no hay forma de evitar esto. Para algunas aplicaciones, puede ser práctico simular su propio movimiento de inmediato sin esperar una respuesta del servidor, pero esto indudablemente dará lugar a una pesadilla con la programación de temporización y las personas típicamente se verán "retrasadas". La detección de colisiones es casi imposible.

El efecto neto de esto es que habrá una lentitud desde que ingrese sus comandos hasta que los vea realmente sucediendo, pero ojalá las personas aprendan a lidiar con esto e intenten ingresar sus comandos un poco antes para compensar. Con conexiones lentas, los juegos rápidos en tiempo real son simplemente imposibles.

+0

Por lo que he visto hasta ahora, esto es lo que todos están tratando de evitar. Enviar el mensaje al servidor y esperar a que el servidor lo confirme dará lugar a un movimiento muy lento. La solución consiste en renderizar el movimiento instantáneamente, enviar el mensaje al servidor y dejar que el servidor "avance" para compensar el retraso. El único problema es cuando cambias constantemente de dirección y haces muchas acciones en poco tiempo, pero la respuesta local debe ser instantánea y aplicar correcciones solo cuando el servidor no está de acuerdo, de lo contrario no es bueno. – stagas

+0

Ese es exactamente mi punto, no funcionará en absoluto para un juego rápido basado en colisiones. Si cambias de dirección, los otros jugadores aún verán que te mueves durante ~ 1 ida y vuelta antes de combarte hacia la nueva ubicación. Pero supongo que ES cómo funcionan los juegos como Counterstrike. Todavía duda que funcionará en un juego como el fútbol. – MatsT

+0

Está bien, sugirió que el servidor tiene control del movimiento local, lo que no es un efecto deseado. Los mensajes pueden ser prioritarios, por ejemplo, para el fútbol, ​​la persona que sostiene el balón, debe ser quien tome las decisiones, y hacer que sea difícil para los defensores obtener el tackle correcto es lo que probablemente me funcione. No puedes tener todo, solo haz que sea lo menos doloroso posible. Sería desagradable si estuvieras a punto de disparar y tuvieras que esperar a que el zócalo de ida y vuelta realmente disparara.Debería ser instantáneo, y el servidor debería obedecer porque sostienes la pelota. Es un problema de defensor, así que está bien;) – stagas

1

Si usted está buscando un código de ejemplo para aprender de, no es un juego multijugador en línea de Pongdone in ActionScript, con la física del lado del servidor interpolados por los clientes.

Ese ejemplo de Pong se basa en el Union platform, que está disponible de forma gratuita para hasta 1000 conexiones de cliente simultáneas.

Union tiene un marco de cliente de JavaScript, OrbiterMicro (JavaScript Client).

Y usted puede escribir su lógica del lado del servidor en JavaScript también, vea Creating Room Modules with JavaScript.

(La revelación completa:. Soy el co-fundador de la Unión)

+0

Pasé algún tiempo revisando Union ... Esto se ve increíble, pero tengo miedo de empezar a usarlo ... ¿Por qué la API JS muestra los métodos que podemos usar, pero no describe cualquiera de los argumentos que necesitamos pasar? Por ejemplo, Room.sendMessage muestra tres argumentos: (messageName, includeSelf, filters), pero no hay forma de saber cuáles son ni cómo usarlos. Ni siquiera parece haber un argumento para especificar realmente el mensaje. ? – hanamj

+0

Orbiter (framework JS de Union) y Reactor (framework Flash de Union) comparten una API idéntica. Para obtener descripciones de las clases en la API de Orbiter, consulte la Referencia de la API de Reactor: http://www.unionplatform.com/?page_id=41 –

0

me contestó otra pregunta que era similar a esto en relación con los problemas de latencia que será una lectura vale la pena, la sincronización con el cliente más lento podría no ser la mejor solución según el juego.

Otra pregunta StackOverflow: Multiplayer game movement synchronization

Cuestiones relacionadas