Clase de colisión de arriba hacia abajo reutilizable

8

Recientemente aprendí monogame y estoy trabajando en un juego simple de arriba hacia abajo para comenzar y aprender los conceptos básicos.
Tengo el movimiento y la rotación para seguir el mouse, pero estoy atrapado en las colisiones.
Lo que quiero saber, básicamente, son dos cosas:

  1. ¿Cuál sería la mejor manera de manejar las colisiones? Sé que Rectangle.Intersects(Rectangle1, Rectangle2)devuelve el rectángulo superpuesto, pero, como el movimiento de arriba hacia abajo está en el eje x / y, me gustaría saber dónde está ocurriendo la colisión para poder crear una especie de "deslizamiento de la pared" donde el jugador no consigue pegado a la pared.
    ¿Verificación de las coordenadas x / y de los jugadores contra las coordenadas de objetos sólidos, luego lanzar al jugador a su posición anterior si entra en los límites de un objeto sólido realmente el mejor enfoque? ¿Qué sugieres?
  2. ¿Cuál sería la mejor manera de aplicar colisiones a todos los sólidos, npc, etc.? Actualmente estoy pensando en crear una gameObjectclase de la que todos los objetos heredarán y solo manejarán las colisiones allí.

Gracias por leer y espero que alguien pueda darme algunos consejos.

Eliah John
fuente
Para reflexionar sobre su segunda pregunta, eche un vistazo a esta respuesta sobre la arquitectura del juego .
Andrew Russell

Respuestas:

9

En general, la forma en que la mayoría de los motores de física manejan este problema es separando los objetos que se cruzan .


Entonces, si sus objetos están representados por rectángulos (también conocidos como "Cajas delimitadas por ejes alineados"), y colisionan en un marco dado de la siguiente manera:

Colisión


Luego mediría la cantidad de interpenetración en cada eje. Luego seleccione el eje con la menor cantidad de interpenetración y separe los objetos a lo largo de ese eje.

Separar


Luego registraría esto como una "colisión" y aplicaría la dinámica apropiada.

Por ejemplo, si desea deslizarse a lo largo de la pared, simplemente reduciría a cero la velocidad en el eje en el que se separó (el eje X, en la ilustración de arriba), dejando solo la velocidad en el otro eje.

Pero también podrías aplicar fricción o hacer que los objetos reboten.


Aquí hay un excelente tutorial interactivo que muestra cómo hacer esto con mucho más detalle.

Sin embargo, si va a ir por este camino (algo más que simples colisiones AABB), es posible que desee considerar el uso de un motor existente como Farseer Physics .


Finalmente, una nota sobre la implementación (si no sigue la ruta Farseer): Rectangleutiliza intvalores, que en la mayoría de los casos no son realmente apropiados para hacer física. Considere hacer su propia AABBclase que use en su floatlugar.

Su segunda pregunta está bastante bien respondida por mi antigua respuesta sobre la arquitectura del juego aquí , así que no la repetiré aquí.

Andrew Russell
fuente
Tal vez hay algo que no entiendo, pero ¿no es defectuoso este enfoque? He ilustrado el problema aquí: jmp.sh/jEW2lvR A veces daría lugar a un comportamiento extraño.
BjarkeCK
@BjarkeCK: Sí, necesitas hacer un trabajo extra para manejar casos como ese. No estoy lo suficientemente versado como para explicar completamente cómo manejarlos adecuadamente (solo uso Farseer y lo llamo un día). Posiblemente eche un vistazo a la "Sección 5" de este enlace .
Andrew Russell
1

1: También he estado trabajando en un juego de acción de arriba hacia abajo relativamente simple, y después de una semana (-s?) De lucha, terminé usando una especie de enfoque paso a paso para la detección y respuesta de colisiones. La razón principal es que el uso de la menor cantidad de interpenetración resultaría en algunos casos en "teletransportación" a una nueva posición en la que el objeto en movimiento no estaba previamente.

entonces, cuando un objeto quiere moverse,

  1. Creo un cuadro delimitador del objeto en la posición del objeto + vector moveAmount, creando una especie de cuadro delimitador objetivo
  2. luego verifico este cuadro delimitador objetivo para ver si se cruza con los objetos del juego, fichas, etc., si los hay, los agrego a una nueva lista, que contiene todas las posibles colisiones para el cuadro actual
  3. Si no hay intersecciones, el objeto se mueve. pero si hay una intersección,
  4. Dividí el movimiento deseado en "pasos". luego ejecuto un ciclo para la cantidad de pasos que tengo. cada paso mueve el objeto solo por 1 píxel en dirección x e y.
  5. para cada paso verifico cada nueva posición proyectada para colisiones, si nada, agrego el vector de movimiento del paso al vector de movimiento final.
  6. si hay una colisión (las intersecciones devuelven verdaderas), comparo la posición anterior (posición en el paso anterior) del objeto en movimiento con la cosa con la que está colisionando.
  7. dependiendo de esta posición anterior, detengo el movimiento a lo largo del eje en conflicto (por ejemplo, si el objeto en movimiento llega al objeto en colisión desde arriba, establezco el valor y del vector de movimiento en 0, etc.).
  8. Repito esto para cada paso consecutivo, agregando los vectores de pasos ajustados juntos para hacer un vector de movimiento ajustado final que puedo usar con seguridad para mover el objeto sin que ocurra ninguna colisión.

Este enfoque garantiza que el objeto "rebote" para corregir la posición anterior y permite deslizarse contra las paredes, los objetos, lo que sea.

2: Yo mismo uso una clase de colisión estática que puede ser utilizada por lo que sea. contiene métodos de detección de colisión y ajuste de vectores, que pueden ser llamados por casi cualquier cosa. si estos métodos se llaman desde una clase de juego "maestra" o por alguna subclase de objeto no importa realmente en mi caso, porque la clase de colisión crea una nueva lista en cada cuadro para todos los rectángulos con los que se cruza el objeto en movimiento. Estos rectángulos pueden ser de azulejos, decoraciones, NPC, lo que sea que tenga límites y sea colisionable, básicamente. Esto significa que la necesidad de todos los objetos del juego que son colisionables es tener límites rectangulares. si tienen eso, la clase de colisión se encargará del resto.

Espero que esto sea comprensible.

AV
fuente
0

1: Utilicé con éxito una técnica para resolver esto: usando la velocidad y la posición puedes descubrir la colisión e iterar hacia atrás hasta que la posición esté muy cerca del punto de colisión exacto.

No es parte de la respuesta a su primera pregunta, pero si tiene muchos objetos que pueden chocar entre sí, debe usar cuadrúpedos para mejorar el rendimiento. Hay un muy buen tutorial con muchos ejemplos aquí .

2: siempre recomiendo Entity-Systems .

Filipe Borges
fuente