Respuesta de rectángulo de colisión


10

Tengo dificultades para hacer que un rectángulo móvil choque con más de un rectángulo.

Estoy usando SFML y tiene una función útil llamada intersectsque toma 2 rectángulos y devuelve las intersecciones. Tengo un vector lleno de rectángulos con los que quiero que choque mi rectángulo móvil. Estoy recorriendo esto usando el siguiente código (p es el rectángulo móvil).

IsCollidingWithdevuelve un bool pero también usa SFML intersectspara resolver las intersecciones.

while(unsigned i = 0; i!= testRects.size(); i++){
   if(p.IsCollidingWith(testRects[i]){
        p.Collide(testRects[i]);
   }
}

y el Collide()código real :

void gameObj::collide( gameObj collidingObject ){

 printf("%f %f\n", this->colliderResult.width, this->colliderResult.height);

if (this->colliderResult.width < this->colliderResult.height) {
    // collided on X
    if (this->getCollider().left < collidingObject.getCollider().left ) {
        this->move( -this->colliderResult.width , 0);
    }else {
        this->move( this->colliderResult.width, 0 );
    }

}

if(this->colliderResult.width > this->colliderResult.height){
    if (this->getCollider().top < collidingObject.getCollider().top ) {
        this->move( 0, -this->colliderResult.height);
    }else {     
        this->move( 0, this->colliderResult.height );
    }

}

y el IsCollidingWith()código es:

bool gameObj::isCollidingWith( gameObj testObject ){
if (this->getCollider().intersects( testObject.getCollider(), this->colliderResult )) {
    return true;
}else {
    return false;
}

Esto funciona bien cuando solo hay 1 Recten la escena. Sin embargo, cuando hay más de uno Rect, causa un problema al resolver 2 colisiones a la vez.

¿Alguna idea de cómo lidiar con esto correctamente? He subido un video a youtube para mostrar mi problema. La consola en el extremo derecho muestra el ancho y la altura de las intersecciones. Puede ver en la consola que está tratando de calcular 2 colisiones a la vez, creo que aquí es donde se está causando el problema.

Finalmente, la imagen a continuación parece ilustrar muy bien mi problema:

rectángulo colisionando con varios otros rectángulos


El enlace del video está roto.
XiaoChuan Yu

¿Los colliderobjetos devueltos por this->getCollider()actualizados por this->move()??
XiaoChuan Yu

¿Podría agregar más información por favor? ¿Cuál es el problema exactamente? El video de YouTube parece mostrar un comportamiento predecible, y solo hay otro rectángulo en la escena.
Wackidev

Respuestas:


3

Su imagen ilustra uno de los muchos problemas al tratar de usar formas convexas, particularmente rectángulos, para simular una superficie plana como un piso. El algoritmo hace que los personajes se atasquen en los bordes internos de las formas que componen el piso.

Una solución simple para eso es verificar solo la colisión vertical, corregir eso y luego verificar nuevamente la colisión horizontal. A menos que se caiga y trate de deslizarse por una pared, en cuyo caso primero desea verificar las colisiones horizontales. ¿Cómo sabes cuándo comprobar cuál primero? Podría hacerlo en función de qué componente de su velocidad es mayor (si el movimiento horizontal es mayor, verifique primero las colisiones verticales; de lo contrario, verifique las colisiones horizontales).

Lo que puede ser aún más simple, y más eficiente, es generar una lista de aristas para su mundo. Es decir, para sus cajas que componen el piso, coloque una bandera que indique que solo su borde superior es realmente colisionable, y luego ignore las colisiones con los otros bordes. No podrá usar la rutina de colisión de SFML para eso, pero honestamente, las colisiones de cajas son posiblemente el código más fácil que jamás escriba en un juego. Esta técnica funciona particularmente bien si su mundo está alineado a una cuadrícula. Verificaría los excelentes tutoriales de Metanet (http://www.metanetsoftware.com/technique.html/) para esa técnica.

Te encontrarás con muchos otros problemas al tratar de construir un juego de plataformas 2D simple como tú. De lejos, el mejor recurso que he visto tarde para eso es el siguiente, que debes leer y luego leer de nuevo:

http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/


1

Tal vez una solución simple sería verificar las colisiones con cada rectángulo y retroceder, en la dirección opuesta del movimiento, hasta que no se detecten colisiones. Si eso resuelve el problema, la implementación también debería ser bastante simple.


+1, en realidad escribí sobre eso aquí: gamedev.stackexchange.com/questions/38252/…
Markus von Broady

0

No creo que tener 2 colisiones calculadas sea un problema, solo un problema de rendimiento. Para que la colisión se maneje correctamente, es posible que deba probarse dos veces. Usando su diagrama, piense si A se prueba primero contra B, entonces también tendrá que ser probado contra las otras casillas, y puede chocar con otra.

Espero que sea útil?


0

Este no es realmente un método óptimo, debe intentar determinar en el momento más temprano cuándo o el primer punto a lo largo del camino de los objetos en movimiento donde ocurren las colisiones y mover los objetos a esa posición (o la posición en el momento calculado), intentando corregir en función de las posiciones de penetración después del movimiento es muy problemático, pero puede utilizar su proceso actual con un pequeño cambio. Solo sigue buscando colisiones hasta que no haya ninguna.

bool collided = true;
while(collided) {
   collided = false
   while(unsigned i = 0; i!= testRects.size(); i++){
      if(p.IsCollidingWith(testRects[i]){
         collided = true
         p.Collide(testRects[i]);
      }
   }
}

Tenga en cuenta que hay situaciones en las que esto conducirá a un bucle infinito (piense en una situación en la que sacar la caja de una colisión da como resultado otra colección, y mover la caja fuera de esa colisión la mueve de nuevo a la misma posición de colisión que antes)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.