¿Estás creando un nivel multijugador 2D de bucle continuo?

15

Recientemente surgió una discusión acerca de cómo crear un juego multijugador de desplazamiento lateral en 2D que pueda tener un diseño de nivel de bucle (Piense en Starbound y cómo están girando sus mundos).

Pensé que la forma más simple sería tener un mapa rectangular con zonas de activación que pudieran teletransportar a los jugadores de un lado a otro. Sin embargo, el problema obvio con este enfoque es el caso de tener varios jugadores en el borde del mapa a la vez. No solo quieres teletransportar a los jugadores uno frente al otro y necesitarías una forma de transportar jugadores sin que otros jugadores desaparezcan.

Para agregar esta idea y solucionar el problema, se me ocurrió lo siguiente: tener una zona de activación (cuadro rojo en la imagen) donde los jugadores podrán ver una "zona de clonación" (cuadro verde). En este cuadrado verde, los objetos del lado opuesto de la zona de activación se copiarían en su zona de clonación correspondiente (se puede ver con las formas A y B). Cuando un jugador llega al borde inicial de la "zona de clonación", se teletransporta al otro lado del mapa.

imagen

En este ejemplo, el Jugador 2 pensaría que están viendo al Jugador 1, sin embargo, en realidad estarían viendo su clon y viceversa.

Esto parecía un poco extremo y complejo para el problema en cuestión. Mi pregunta ahora es saber si esta solución es un buen enfoque para abordar el problema, ¿o hay una forma más sencilla de resolver este problema?

KenQueso
fuente
¿Se les permite a los jugadores moverse hacia atrás a un área anterior?
XiaoChuan Yu
Sí, de ida y vuelta, por lo que da una especie de efecto de "caminar alrededor del mundo". Similar a cómo es un mundo en Starbound
KenQueso
2
¿Has considerado simplemente hacer del mundo un gran círculo? o tratando el nivel como un gran círculo y traduciéndolo a una etapa 2D plana?
Nzall
¿No puedes alinear siempre la posición de la cámara con el jugador que estás controlando?
Ali1S232

Respuestas:

16

Este sistema con todos estos disparadores suena demasiado complicado y propenso a errores.

Podrías envolver la posición del jugador usando el módulo con algo como playerPositionX = playerPositionX % mapWidth

De esta manera, cuando su jugador llegue playerPosition == mapWidthal playerPositionreiniciará a 0.

Esta solución podría ampliarse con todo el sistema de renderizado.

Exaila
fuente
1
¿No tendría esto el problema del cierre por parte de los jugadores al ver jugadores cuya posición restablece el teletransporte?
KenQueso
¿Cómo extenderías esto al sistema de renderizado?
Mikael Högström
Podrías tener un jugador siempre en el centro de la cámara y tener el mapa envuelto. Como un mapa en civilización en modo tierra. Otro enfoque podría ser representar la parte visible de un jugador a ambos lados del mapa.
Exaila
44
@ MikaelHögström Simplemente renderice como de costumbre, pero las cosas cercanas al borde derecho deben representarse por segunda vez a la izquierda (es decir, en pos - map_width).
Mario
1
En cualquier parte de su código que esté buscando 'qué objeto está en esta coordenada' o 'cuáles son las coordenadas de este objeto', lo haría xcoord% mapWidth. Es difícil de decir sin su código, pero eso probablemente haría que se procese correctamente.
Tin Man
13

La solución canónica es usar portales . En su ejemplo, solo hay un nivel, excepto que hay un portal que conecta los extremos izquierdo y derecho.

Cualquier cosa que se mueva a través de ese portal tendrá sus coordenadas traducidas al otro extremo del portal, de modo que si algo se mueve a la izquierda a través del portal, reaparecerá en el lado derecho del nivel y viceversa.

Tu cámara también necesita soportar los portales; Si el portal está dentro de la cámara, debe representar partes del nivel a cada lado del portal. Si está familiarizado con los editores de imágenes para gráficos de mosaico sin costura, aquí es el mismo trato.

La parte tediosa es que todo lo relacionado con la distancia o la ruta también tendrá que soportar portales. Esto incluye IA, algos de línea de visión, atenuación de sonido, etc.

Sin embargo, lo bueno de los portales es que es muy poderoso. El motor de compilación lo usó para simular niveles de varios pisos, a pesar de que no es un "verdadero" motor 3D. Algunos motores modernos también usan portales para crear espacios no euclidianos; Portal y Antichamber son ejemplos notables en 3D.

congusbongus
fuente
2
Si escuchas los comentarios del juego del portal, parte de la forma en que funcionan los portales se implementa clonando lo que se ve a través del agujero. (pero por razones físicas en lugar de renderizar)
Mooing Duck
6

Recuerde que lo que muestra en la pantalla y lo que hay en la memoria son dos cosas totalmente diferentes. Imagine que tiene una ventana que necesita llenar con datos sobre el mundo. Rellena la ventana de izquierda a derecha. Mientras analiza sus datos para llenar el mundo, si llega al fin del mundo, simplemente regrese al comienzo de sus datos. Usar una operación de módulo es ideal. Recuerda que debes hacer esto para todo . Proyectiles, rayos, jugadores, física; todos necesitan tener sus posiciones envueltas al cruzar los límites del mundo.

Cada jugador comparte datos, pero tiene su propia perspectiva de los datos. Sus ventanas están pobladas de manera diferente dependiendo de dónde se encuentren en el mundo.

Esto significa que no hay necesidad de crear clones o teletransportarse a nadie. Básicamente, está creando clones, simplemente representando caracteres en las pantallas de los demás.

MichaelHouse
fuente
3

Desconecte el renderizado del mundo y puede hacer un renderizado envolvente y correcto sin recurrir a ningún artefacto de clonación o teletransportación.

Primero, en tu mundo tienes un mundo de tamaño fijo, desde 0hasta Width. Cada vez que un objeto cae por debajo de 0, lo envuelve hasta el final, y cada vez que un objeto se sobrepasa Widthal inicio. Esto significa que todos los objetos lógicos en su mundo siempre están dentro del rango 0...Width.

Segundo, para renderizar harás un módulo en la posición. Entonces, el lado izquierdo de la pantalla es "Base" y el lado derecho es "Base + Tamaño". Entonces buscas en tu mundo cualquier cosa dentro de ese rango. En realidad, buscará el rango del módulo, que lo asigna nuevamente 0...Width.

El truco durante la búsqueda es devolver la posición del objeto en relación con el Baselado izquierdo. Esto se convierte en coordenadas locales de la pantalla para que el renderizador en sí no tenga que preocuparse por el módulo, solo lo hace la búsqueda.

No necesita clonar nada, ya que cada renderizador solo trata con el objeto en una ubicación.

Si su mundo se produce en segmentos, o usando estructuras 3D, tendrá que segmentarlo. Por lo tanto, no es un bloque constante, pero se puede mover para acomodar esta representación. No necesita muchos bloques, como mínimo 2.

edA-qa mort-ora-y
fuente
1

Creo que el único enfoque razonable sería implementar su mundo envuelto en una estructura de datos subyacente completamente transparente para el juego y el usuario. Entonces, en algunos de bajo nivel, tiene una función mapCoordinate () que ajusta sus coordenadas reales a su recurso de mapa subyacente ...

Entonces, si tu mundo real tiene solo 10 unidades de ancho, el jugador y el juego no lo sabrán. Para el jugador, el mundo es infinito, y si el juego pregunta qué está en la posición 15, la función subyacente traducirá esta solicitud, módulo 10 y le dará al paquete el artículo en la posición 5.

Entonces, para toda la lógica del juego y todo lo demás, es como si tuvieras un mundo infinito y grande, donde solo hay copias de todo.

Falco
fuente
1

No es lo mismo, pero implementé algo similar en un atasco de juego. El juego tenía jugadores moviéndose en un pequeño nivel circular, envuelto cuando el jugador alcanzaba una posición 'x' de pi. Renderizar fue fácil porque acabamos de renderizar todo y luego giramos una cámara offset para rastrear lo que estaba sucediendo. Podría implementar algo similar, como se ha sugerido anteriormente:

  • Al dibujar, verifique la posición de la cámara y determine qué necesita dibujarse, teniendo en cuenta la posición de la cámara y su rango de visión.
  • En los casos en que la cámara ve más allá del 'borde' del mapa, seleccione una cantidad adecuada de contenido del otro lado del mundo para dibujar sobre ese borde, generalmente simplemente agregando o restando el ancho del nivel a su posición.
  • La lógica del juego debe ser consciente de esta costura y ajustarla como se menciona en otras respuestas. Los casos particulares a tener en cuenta son las colisiones en las que un objeto está en un lado, pero choca con un objeto en el otro lado.
Chris
fuente