En un juego de plataformas en 2D, ¿cómo garantizar que el jugador se mueva suavemente sobre terreno inclinado?

18

Estoy desarrollando un motor de física para un juego de plataformas en 2D. Estoy usando el teorema del eje de separación para la detección de colisiones. La superficie del suelo se construye a partir de cuadros delimitadores orientados, con el jugador como un cuadro delimitador alineado con el eje. (Específicamente, estoy usando el algoritmo del libro "Detección de colisión en tiempo real" que realiza la detección de colisión barrida para OBBs usando SAT). Estoy usando un coeficiente de restitución bastante pequeño (cercano a cero) en la respuesta de colisión, para asegurar que los objetos dinámicos no penetren en el entorno.

El motor en su mayoría funciona bien, es solo que me preocupan algunos casos extremos que podrían ocurrir. Por ejemplo, en el diagrama, A, B y C son la superficie del suelo. El jugador se dirige hacia la izquierda a lo largo de B hacia A. Me parece que debido a la inexactitud, la casilla del jugador podría estar ligeramente debajo de la casilla B a medida que continúa hacia arriba y hacia la izquierda. Cuando llega a A, por lo tanto, la esquina inferior izquierda del jugador podría colisionar con el lado derecho de A, lo que sería indeseable (ya que la intención es que el jugador se mueva suavemente sobre la parte superior de A). Parece que podría ocurrir un problema similar cuando el jugador está en la parte superior de la casilla C, moviéndose a la izquierda hacia B: el punto más extremo de B podría chocar con el lado izquierdo del jugador, en lugar de que la esquina inferior izquierda del jugador se deslice hacia arriba y hacia la izquierda por encima de B.

Box2D parece manejar este problema almacenando información de conectividad para sus formas de borde, pero no estoy realmente seguro de cómo usa esta información para resolver el problema, y ​​después de mirar el código, realmente no entiendo lo que está haciendo.

Cualquier sugerencia sería muy apreciada.

Nick Kovac
fuente
Un motor de física general es ideal para efectos y cuadros que caen y todo eso, pero no para la física de los personajes, como se establece en la sección de respuestas. Considera escribir física "estática" para tu personaje, de modo que puedas tener el 100% de control y utilizar dinámicas simuladas adecuadamente para el resto.
Domi

Respuestas:

14

Plataformas y Física

Estos casos extremos son numerosos. Los juegos de plataformas buenos y divertidos no se comportan de ninguna manera físicamente precisa, y el control y el comportamiento que los jugadores esperan después de años de juegos de plataformas "perfectos" como Mario son increíblemente difíciles de implementar con técnicas generales como las que obtienes con Box2D u otros motores de física. La mayoría de los buenos plataformas no usan ningún tipo de física genérica o respuesta de colisión en sus controladores de jugador.

Generar cascos

Con respecto a su pregunta específica, la mejor solución es dejar de usar cajas como base. Use una serie de segmentos de línea conectados (un casco). Eso permite que el motor de detección de colisión se enfoque solo en las superficies realmente transitables y no mire el borde "falso" que existe entre AB y BC. Eso es lo que hace Box2D, de hecho. Las formas se utilizan para generar las superficies exteriores, que se unen para formar un casco.

Necesitas esto incluso en juegos basados ​​en fichas, o en situaciones en las que tienes dos objetos AABB junto a otros que actúan como piso. El motor de colisión recogerá esos bordes verticales y hará que el jugador los atrape. Hay hacks que pueden ayudar, pero no eliminan el problema. La solución es tener un solo segmento de línea que represente la superficie en lugar de un cuadro 2D completo.

Puede generar los cascos en el caso genérico recortando los polígonos entre sí y uniendo los puntos de recorte en una lista de bordes.

Superficies inclinadas

Dado que su ejemplo incluye una pendiente y está mencionando la restitución y otras propiedades físicas, señalaré algunos otros problemas que notará pronto, lo que ilustra aún más por qué la detección y respuesta de colisión genérica no funciona bien para los juegos de plataformas. Primero, intenta pararte en la plataforma en ángulo, salta y luego aterriza. Probablemente notarás que el personaje se "deslizará" un poco al aterrizar. El problema es que el contacto normal que está generando generalmente estará señalando desde la superficie en ángulo. Luego, al resolver la colisión, el jugador es empujado en esa dirección. A pesar de que el personaje cayó hacia abajo, lo empujarán hacia arriba y un poco hacia la derecha al aterrizar, lo que provocará el deslizamiento. Esto puede ser pirateado teniendo en cuenta las velocidades relativas,

El segundo problema que notará, que es mucho más difícil de solucionar, es lo que sucede cuando intenta correr rápidamente por una rampa. El jugador va a "saltar" por la rampa. Esto es muy visible incluso en la mayoría de los juegos AAA de hoy. No solo parece una tontería, sino que si tu juego requiere que el jugador esté parado en el suelo para saltar, hace que sea difícil correr por una rampa y saltar a mitad de camino, porque el jugador solo está en contacto con la rampa durante una pequeña porción del tiempo dedicado a bajarlo. Una solución más simple es simplemente hacer algunos lanzamientos de rayos cuando el jugador se mueve, y ajustar la posición del jugador hacia la superficie más cercana (si está muy cerca del jugador) si el jugador no está saltando y estaba previamente en el suelo.

También puede encontrar que el jugador se lanza al aire cuando corre por una rampa si intenta modelar la velocidad, la fricción y la restitución en el jugador como si fuera un cuerpo rígido normal. El movimiento del jugador debe limitarse al movimiento horizontal a menos que caiga / salte. Por supuesto, si juegas plataformas de edad dorada más antiguas, puedes notar que la velocidad horizontal del jugador a menudo es constante entre las superficies horizontales e inclinadas. Esto también debe tenerse en cuenta al subir / bajar pendientes.

Habrá una serie de otros casos de esquina extraños con los que eventualmente también se encontrará. Si está tratando de hacer un buen juego de plataformas, realmente es mejor implementar un controlador de jugador de plataformas separado de la física y codificar el comportamiento de movimiento y control que desea, en lugar de confiar en la física genérica y el algoritmo de respuesta a colisiones.

Sean Middleditch
fuente
Gracias por su respuesta. Había considerado reducir las cajas que representan el suelo en líneas, pero en realidad no creo que eso solucione el problema. Por ejemplo, si los cuadros de tierra ahora son líneas, y si el jugador está parado en la línea C y viaja hacia la izquierda hacia B, debido a la inexactitud, es posible que el cuadro de jugador esté ligeramente por debajo de la línea C. Luego, el borde izquierdo del cuadro de jugador todavía podría chocar con la línea B y causar esa colisión indeseable,
Nick Kovac
a menos que haya algún otro mecanismo para evitar que esto suceda. No es el hecho de que Box2D usa líneas en lugar de cuadros lo que soluciona el problema, es que Box2D usa una forma de cadena, que usa información de conectividad entre los segmentos de línea para evitar que ocurran algunas colisiones. El principal problema en este momento es que no entiendo los detalles de cómo exactamente hace esto.
Nick Kovac
Planteaste algunos otros puntos realmente buenos sobre los problemas con tomar ideas de motores de física genéricos y aplicarlos a juegos de plataformas. He visto motores similares que implementan las ideas que discutiste (modificando la colisión normal para pendientes y chupando al jugador en la pendiente), por lo que al menos esos problemas son bastante fáciles de resolver. El principal problema para mí son los casos extremos complicados relacionados con los errores numéricos.
Nick Kovac
@Kovsa: de nuevo, esos errores particulares desaparecen cuando se eliminan los bordes que no deberían ser parte de la colisión en primer lugar. Encadena los bordes para formar una forma ininterrumpida. Al diseñar su nivel, también recomendaría juntar los vértices para que no tenga pequeñas grietas en las superficies. No es realmente diferente de cómo diseñas el nivel en un editor de malla 3D.
Sean Middleditch
Hmm ... no creo que te siga. En mi diagrama, si encadena los bordes para formar una forma ininterrumpida, obtendría una forma compuesta de tres segmentos de línea: la parte superior de los cuadros A, B y C, ¿verdad? A pesar de que es una sola forma, todavía necesitaría realizar la detección de colisión por separado contra la línea A, luego B, luego C, ¿no? ¿A menos que haya querido decir un algoritmo que pueda detectar una colisión entre la caja y esta forma combinada? ¿Asumo que no sería SAT entonces, ya que una serie de bordes podrían ser cóncavos?
Nick Kovac
5

Creo que ambos problemas podrían resolverse tratando sus cajas, con fines de respuesta de colisión, como si tuvieran esquinas redondeadas (de un radio similar a su error numérico). Esto hará que la superficie combinada efectiva de las esquinas de reunión entre A y B, y B y C, sea más suave.

Por lo tanto, si el JUGADOR que se mueve hacia la izquierda golpea la esquina de A, la colisión normal sería diagonal en lugar de puramente hacia la derecha, permitiendo así la continuación del movimiento hacia la izquierda y hacia arriba.


Sin embargo, una solución más típica, al revisar lo que sé de física de plataformas, es hacer que el jugador tenga una forma más redondeada y dejar el terreno solo. En particular, considere hacer que la forma del jugador sea una cápsula (círculo estirado en el medio (2D) / esfera (3D)), entonces sus normales de colisión serán naturalmente verticales, eliminando cualquier problema de captura.

Dice que está utilizando un algoritmo de colisión específicamente para OBB, pero aún así debería poder, después de encontrar una colisión OBB-OBB, usar una prueba adicional contra una forma que esté completamente dentro del OBB.

Kevin Reid
fuente
Mmm, idea interesante ... ¿cómo harías para implementarlo? Sin embargo, va un poco en contra de la simplicidad de usar cajas: (Estoy de acuerdo en que parece que debería ser un problema común con una solución definitiva, pero realmente no puedo encontrar ninguna cobertura al respecto ... aparte de lo que se está haciendo en Box2D. Publiqué una pregunta similar en su foro para obtener más información.
Nick Kovac
No tengo detalles de implementación, lo siento, no soy un experto en este tipo de código de motor de física. Sin embargo, tuve una mejor idea para una solución que no se basa en factores falsos: vea mi edición.
Kevin Reid
1
Tenga en cuenta que si bien el uso de formas redondeadas funciona, es matemáticamente más complejo y puede dar lugar a un comportamiento subóptimo para los juegos de plataformas. Los jugadores esperan tener un control casi perfecto de píxeles sobre los personajes que se encuentran en las repisas, por ejemplo, qué formas redondeadas harán más o menos imposible, y los personajes se deslizarán de las repisas inesperadamente.
Sean Middleditch
Repisas: D'oh! OK, no tan simple como estaba pensando.
Kevin Reid
Sí, después de pensarlo, el enfoque de cápsula parece quizás más adecuado para un juego en 3D que para un juego de plataformas en 2D. Tener un control perfecto de píxeles es definitivamente una prioridad para mí (como lo era en todos esos viejos juegos de plataformas 2D). ¡Pero debe haber una solución que permita el uso de cajas!
Nick Kovac