Foros del Web » Programación para mayores de 30 ;) » C/C++ »

[SFML] Colisión rebota

Estas en el tema de [SFML] Colisión rebota en el foro de C/C++ en Foros del Web. Buenas, Tengo un problema al intentar colisionar dos figuras en sfml, la cosa es que colisiona pero en vez de chocar y estarse quieto sin ...
  #1 (permalink)  
Antiguo 24/06/2015, 14:01
Avatar de Tropy  
Fecha de Ingreso: diciembre-2013
Mensajes: 62
Antigüedad: 10 años, 11 meses
Puntos: 1
[SFML] Colisión rebota

Buenas,

Tengo un problema al intentar colisionar dos figuras en sfml, la cosa es que colisiona pero en vez de chocar y estarse quieto sin poder avanzar se coloca en la otra parte de la otra figura y así consecutivamente.

Aquí un vídeo previo del error:
El vídeo es capturado por mi, dura 30 seg. Para mostrar el error.
https://www.youtube.com/watch?v=i8TFZbfo7EE

Código:

Código C++:
Ver original
  1. sf::FloatRect rect = rec.getGlobalBounds();
  2.         sf::FloatRect rect2 = rec2.getGlobalBounds();
  3.  
  4.         if(rect.intersects(rect2)){
  5.  
  6.             if(rec.getPosition().x<400){
  7.                 std::cout << rec.getPosition().x << std::endl;
  8.                 rec.setPosition(350, rec.getPosition().y);
  9.             }
  10.             if(rec.getPosition().x>400){
  11.                 rec.setPosition(450, rec.getPosition().y);
  12.             }
  13.             if(rec.getPosition().y<400){
  14.                 rec.setPosition(rec.getPosition().x, 350);
  15.             }
  16.             if(rec.getPosition().y>400){
  17.                 rec.setPosition(rec.getPosition().x, 450);
  18.             }
  19.  
  20.         }

rec -> es el rectángulo que manejo con el keyboard.
rec2 -> es el rectángulo que está situado fijamente en el centro de la ventana.



Si supiesen a que debe deberse dicho error agradecería alguna respuesta.
Gracias.


Saludos!
  #2 (permalink)  
Antiguo 25/06/2015, 02:12
 
Fecha de Ingreso: julio-2012
Mensajes: 375
Antigüedad: 12 años, 4 meses
Puntos: 28
Respuesta: [SFML] Colisión rebota

Cambia la mentalidad, en vez de hacer que retroceda cuando se choca, haz que no pueda avanzar si hay colisión.

Código C++:
Ver original
  1. if (!rect.intersects(rect2)){
  2.     // mover
  3. }
  #3 (permalink)  
Antiguo 25/06/2015, 03:01
Avatar de Tropy  
Fecha de Ingreso: diciembre-2013
Mensajes: 62
Antigüedad: 10 años, 11 meses
Puntos: 1
Respuesta: [SFML] Colisión rebota

Acabo de probar como según usted me ha indicado:

Código C++:
Ver original
  1. if(!rect.intersects(rect2)){
  2.  
  3.             if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
  4.                 rec.move(0, -1);
  5.             }
  6.             if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
  7.                 rec.move(0, 1);
  8.             }
  9.             if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
  10.                 rec.move(-1, 0);
  11.             }
  12.             if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
  13.                 rec.move(1, 0);
  14.             }
  15.  
  16.         }

Choca con la figura sí, pero una vez que choca no puedo moverme, me quedo pegado a la otra figura.

Gracias por la respuesta.

Saludos!
  #4 (permalink)  
Antiguo 25/06/2015, 04:03
Avatar de iblancasa  
Fecha de Ingreso: diciembre-2012
Ubicación: España
Mensajes: 143
Antigüedad: 11 años, 11 meses
Puntos: 16
Respuesta: [SFML] Colisión rebota

Guarda en alguna variable el sitio por el que ha chocado y, en función de eso, permite los movimientos en todos los sentidos menos en el que ha chocado.

Algo así:

Código:
bool chocar [4] = {false,false,false,false}; //Norte, sur, este y oeste

if(rect.intersects(rect2)){
  comprobarIntersecta(); //Una función que compruebe dónde está intersectando y lo meta en el array chocar
}

  if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
              if(!chocar[0])  
                 rec.move(0, -1);
   }
   
  else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
                 if(!chocar[1])  
                rec.move(0, 1);
  }
  else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
                if(!chocar[2])  
                   rec.move(-1, 0);
   }
   else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
                if(!chocar[3])  
                     rec.move(1, 0);
   }
Para la función comprobarIntersecta() deberás restar las posiciones. Imagina que tienes la figura A y la B.

Supongo que cuanto más abajo y a la derecha de la pantalla vayas, mayor es el valor de las coordenadas (no sé que sistema de coordenadas usa SFML).

Si restas las posiciones de A y B tienes:
X == positiva >> A está más a la derecha que B
X == negativa >> B está más a la derecha que A

Y == positiva >> A está más abajo que B
Y == negativa >> B está más bajo que A

Como te digo, he supuesto que cuanto más abajo y a la derecha vayas, mayor es el valor de las coordenadas.


Suerte
  #5 (permalink)  
Antiguo 25/06/2015, 07:39
Avatar de Tropy  
Fecha de Ingreso: diciembre-2013
Mensajes: 62
Antigüedad: 10 años, 11 meses
Puntos: 1
Respuesta: [SFML] Colisión rebota

Estuve probando y tal pero a vece me da distintos resultados que intento buscar,
Tal vez pueda ser un error de concepto ¿no?

Código completo:

Código C++:
Ver original
  1. #include <SFML/Graphics.hpp>
  2. #include <iostream>
  3.  
  4. void comprobarIntersecta();
  5.  
  6. int main(){
  7.     //Creamos la ventana
  8.     sf::RenderWindow window(sf::VideoMode(800, 600), "Colision");
  9.  
  10.     //Rectangualo
  11.     sf::RectangleShape rec(sf::Vector2f(50, 50));
  12.     rec.setFillColor(sf::Color::Cyan);
  13.  
  14.     //Otro rectangulo
  15.     sf::RectangleShape rec2(sf::Vector2f(50, 50));
  16.     rec2.setFillColor(sf::Color::Magenta);
  17.     rec2.setPosition(400, 300);
  18.  
  19.     window.setFramerateLimit(200);
  20.  
  21.     //Si la ventana está abierta
  22.     while(window.isOpen()){
  23.         //Creamos un evento
  24.         sf::Event ventana;
  25.         //Llamamos a los eventos
  26.         while(window.pollEvent(ventana)){
  27.             //Cerramos la ventana cuando se solicite
  28.             if(ventana.type == sf::Event::Closed){
  29.                 window.close();
  30.             }
  31.         }
  32.  
  33.         //Colisiones ventana bordes
  34.         if(rec.getPosition().x<0){
  35.             rec.setPosition(0, rec.getPosition().y);
  36.         }
  37.         if(rec.getPosition().x>750){
  38.             rec.setPosition(750, rec.getPosition().y);
  39.         }
  40.         if(rec.getPosition().y<0){
  41.             rec.setPosition(rec.getPosition().x, 0);
  42.         }
  43.         if(rec.getPosition().y>550){
  44.             rec.setPosition(rec.getPosition().x, 550);
  45.         }
  46.  
  47.         sf::FloatRect rect = rec.getGlobalBounds();
  48.         sf::FloatRect rect2 = rec2.getGlobalBounds();
  49.  
  50.         bool chocar [4] = {false,false,false,false}; //Norte, sur, este y oeste
  51.  
  52.         if(rect.intersects(rect2)){
  53.                 comprobarIntersecta();
  54.         }
  55.  
  56.         if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
  57.             if(!chocar[0])
  58.                 rec.move(0, -1);
  59.         }
  60.         else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
  61.             if(!chocar[1])
  62.                 rec.move(0, 1);
  63.         }
  64.         else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
  65.             if(!chocar[2])
  66.                 rec.move(-1, 0);
  67.         }
  68.         else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
  69.             if(!chocar[3])
  70.                 rec.move(1, 0);
  71.         }
  72.  
  73.         //Limpiamos ventana
  74.         window.clear();
  75.  
  76.         //Dibujamos el rectangulo
  77.         window.draw(rec);
  78.         window.draw(rec2);
  79.  
  80.         //Actualizamos ventana
  81.         window.display();
  82.  
  83.     }
  84. }
  85.  
  86. void comprobarIntersecta(){
  87.     sf::RectangleShape rec(sf::Vector2f(50, 50));
  88.     rec.setFillColor(sf::Color::Cyan);
  89.     if(rec.getPosition().x<400){
  90.         chocar[0] = true;
  91.     }
  92. }

Hay está todo para verificar si tal vez es de concepto.
Gracias por las respuestas aportadas.


Saludos!
  #6 (permalink)  
Antiguo 25/06/2015, 07:51
Avatar de iblancasa  
Fecha de Ingreso: diciembre-2012
Ubicación: España
Mensajes: 143
Antigüedad: 11 años, 11 meses
Puntos: 16
Respuesta: [SFML] Colisión rebota

El problema está en el comprobarIntersecta().


Código HTML:
void comprobarIntersecta(){
    sf::RectangleShape rec(sf::Vector2f(50, 50));
    rec.setFillColor(sf::Color::Cyan);
    if(rec.getPosition().x<400){
        chocar[0] = true;
    }
}
No hace lo que te he dicho. Simplemente compruebas la posición y si no pasa de 400 en el eje X, es que está chocando arriba... No tiene sentido.


Tienes dos figuras. Quieres saber POR DONDE intersecta la figura A con la B. Es por eso que el vector chocar tiene cuatro posiciones (si choca arriba, abajo, derecha o izquierda). Cuando se mueva, deberás de poner de nuevo el valor del vector a false (por que ya no estará tocando)
  #7 (permalink)  
Antiguo 25/06/2015, 15:58
Avatar de Tropy  
Fecha de Ingreso: diciembre-2013
Mensajes: 62
Antigüedad: 10 años, 11 meses
Puntos: 1
Respuesta: [SFML] Colisión rebota

Buenas,

Intenté hacer la función más o menos como me guiaste y por parte funciona pero no del todo me quedé un poco atrapado, al igual al intentar hacerlo probé otra cosa que me da el mismo resultado.

Aquí un previo vídeo:
https://www.youtube.com/watch?v=KOVwKT6rf54

Sería aquí las modificaciones:

Código C++:
Ver original
  1. sf::FloatRect rect = rec.getGlobalBounds();
  2.         sf::FloatRect rect2 = rec2.getGlobalBounds();
  3.  
  4.         if(rect.intersects(rect2)){
  5.  
  6.             if(rec.getPosition().x<=rect2.left){
  7.                 rec.setPosition(rec.getPosition().x-1, rec.getPosition().y);
  8.             }
  9.             if(rec.getPosition().x>=rect2.left){
  10.                 rec.setPosition(rec.getPosition().x+1, rec.getPosition().y);
  11.             }
  12.             if(rec.getPosition().y<=rect2.left){
  13.                 rec.setPosition(rec.getPosition().x, rec.getPosition().y-1);
  14.             }
  15.             if(rec.getPosition().y>=rect2.left){
  16.                 rec.setPosition(rec.getPosition().x, rec.getPosition().y+1);
  17.             }
  18.  
  19.         }

De tu forma me da un resultado similar, pero me quede un poco atrapado y no se como seguirla, y pues para no darte más trabajo pues probé algo así que me dio dicho resultado, pero como se ve en el vídeo solo responde a 'x' a la 'y' no responde y si se intenta pues al colisionar se va moviendo la figura en vez de quedarse quieta sin poder avanzar más ya que colisionó.

Gracias.


Saludos!

-------------------------------------------------------------------------------------------------
#ACTUALIZACIÓN
-------------------------------------------------------------------------------------------------

Probé a cambiar .left por .top pero igual el mismo problema.

Código C++:
Ver original
  1. sf::FloatRect rect = rec.getGlobalBounds();
  2.         sf::FloatRect rect2 = rec2.getGlobalBounds();
  3.  
  4.         if(rect.intersects(rect2)){
  5.  
  6.             if(rec.getPosition().x<=rect2.left){
  7.                 rec.setPosition(rec.getPosition().x-1, rec.getPosition().y);
  8.             }
  9.             if(rec.getPosition().x>=rect2.left){
  10.                 rec.setPosition(rec.getPosition().x+1, rec.getPosition().y);
  11.             }
  12.             if(rec.getPosition().y<=rect2.top){
  13.                 rec.setPosition(rec.getPosition().x, rec.getPosition().y-1);
  14.             }
  15.             if(rec.getPosition().y>=rect2.top){
  16.                 rec.setPosition(rec.getPosition().x, rec.getPosition().y+1);
  17.             }
  18.  
  19.         }


- Tal vez sea mejor de tu forma con la función pero me quedé un poco pillado a la hora de cambiar el valor del array.

Gracias.


Saludos!

Última edición por Tropy; 25/06/2015 a las 18:11
  #8 (permalink)  
Antiguo 25/06/2015, 19:40
Avatar de iblancasa  
Fecha de Ingreso: diciembre-2012
Ubicación: España
Mensajes: 143
Antigüedad: 11 años, 11 meses
Puntos: 16
Respuesta: [SFML] Colisión rebota

Lo que has hecho tiene la misma lógica de lo que yo te comentaba.

Te hago un código que probablemente no compile, pero te transmitirá la idea. No sé si los tipos están bien. Investiga un poco sobre eso (el compilador te lo dirá).


Supongo que cuanto más abajo a la derecha vayas, mayor es el valor de las coordenadas, pero no estoy seguro.



Código HTML:
void comprobarIntersecta(sf::FloatRect A, sf::FloatRect B){
//A es el que se mueve. B el que está quieto

if(A.top-(B.top+B.height)==0){//Choca con la parte de arriba por abajo del que está quieto
   chocar[0]=true;
}

if((A.top+B.height)-B.top)==0){//Choca con la parte de abajo por arriba del que está quieto
   chocar[1]=true;
}

if((A.left+A.width)-B.left>0){//Choca con la derecha por la izquierda del que está quieto
   chocar[2]=true;
}

if(A.left-(B.left+B.width)>0){//Choca con la izquierda por la derecha del que está quieto
   chocar[2]=true;
}


}


Ahora volvemos al resto del código:

Código:
bool chocar [4] = {false,false,false,false}; //Norte, sur, este y oeste
 
        if(rect.intersects(rect2)){
                comprobarIntersecta(rec.getGlobalBounds(),rect2..getGlobalBounds());
        }
 
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
            if(!chocar[0])
                 rec.setPosition(rec.getPosition().x, rec.getPosition().y-1);
           else{
            chocar[0]=false;
            rec.setPosition(rec.getPosition().x, rec.getPosition().y+1);
           }

        }
        else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
           if(!chocar[1])
                 rec.setPosition(rec.getPosition().x, rec.getPosition().y+1);
           else{
            chocar[1]=false;
            rec.setPosition(rec.getPosition().x, rec.getPosition().y-1);
           }
        }
        else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
           if(!chocar[3])
                 rec.setPosition(rec.getPosition().x-1, rec.getPosition().y);
           else{
            chocar[3]=false;
            rec.setPosition(rec.getPosition().x+1, rec.getPosition().y);
           }

        }
        else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
            if(!chocar[2])
                 rec.setPosition(rec.getPosition().x+1, rec.getPosition().y);
           else{
            chocar[2]=false;
            rec.setPosition(rec.getPosition().x-1, rec.getPosition().y);
           }
        }

Sería algo así:
Si intersecta:
Comprobamos por dónde intersecta

Si mueves hacia arriba y está intersectando
Lo echamos uno para abajo
Si no, mueve hacia arriba
(y así con todos: si se puede mover se mueve y, sino, se mueve en sentido contrario uno)





No te preocupes por lo del tiempo. Aquí estamos para aprender y ayudarnos.
  #9 (permalink)  
Antiguo 26/06/2015, 06:42
Avatar de Tropy  
Fecha de Ingreso: diciembre-2013
Mensajes: 62
Antigüedad: 10 años, 11 meses
Puntos: 1
Respuesta: [SFML] Colisión rebota

Estoy probando según como me estás indicando,
Por el momento todo funciona bien sin darme error, pero a la hora de definir la función dentro del intersets me salta un error:

Código C++:
Ver original
  1. if(rect.intersects(rect2)){
  2.             comprobarIntersecta(sf::FloatRect rec, sf::FloatRect rec2);
  3.         }

He probado tu forma, más otras que intenté pero nada, al parecer es problema al definir el valor de la función.

Gracias por las respuestas aportadas.

Saludos!
  #10 (permalink)  
Antiguo 26/06/2015, 08:10
Avatar de iblancasa  
Fecha de Ingreso: diciembre-2012
Ubicación: España
Mensajes: 143
Antigüedad: 11 años, 11 meses
Puntos: 16
Respuesta: [SFML] Colisión rebota

Pero... ¿qué error te da? Sin verlo, no puedo ayudarte.
  #11 (permalink)  
Antiguo 26/06/2015, 17:33
Avatar de Tropy  
Fecha de Ingreso: diciembre-2013
Mensajes: 62
Antigüedad: 10 años, 11 meses
Puntos: 1
Respuesta: [SFML] Colisión rebota

Disculpa, error mío al parecer al crear la respuesta me salté dicha información.

Probé con:

Código C++:
Ver original
  1. if(rect.intersects(rect2)){
  2.             comprobarIntersecta(rec.getGlobalBounds(),rec2.getGlobalBounds());
  3.         }

Y me da este error:

Código:
error: too many arguments to function 'void comprobarIntersecta()'|
-----------------------------------------------------------------------------------------------------------

Probé con:

Código C++:
Ver original
  1. if(rect.intersects(rect2)){
  2.             comprobarIntersecta(rect.getGlobalBounds(),rect2.getGlobalBounds());
  3.         }

Y me da este error:

Código:
error: 'sf::FloatRect' has no member named 'getGlobalBounds'|
-----------------------------------------------------------------------------------------------------------

Lo que hice es cambiar en esta línea:

Código C++:
Ver original
  1. comprobarIntersecta(rec.getGlobalBounds(),rec2.getGlobalBounds());

Las variables 'rec', 'rec2' y 'rect', 'rect2'.

Gracias.


Saludos!
  #12 (permalink)  
Antiguo 26/06/2015, 19:19
Avatar de iblancasa  
Fecha de Ingreso: diciembre-2012
Ubicación: España
Mensajes: 143
Antigüedad: 11 años, 11 meses
Puntos: 16
Respuesta: [SFML] Colisión rebota

Perdona pero no veo la diferencia en el código cuando te da los distintos errores.

Mira el primer caso:

Código:
if(rect.intersects(rect2)){
            comprobarIntersecta(rec.getGlobalBounds(),rec2.getGlobalBounds());
        }
Estás pasando 2 argumentos.


Código:
error: too many arguments to function 'void comprobarIntersecta()'|
"Demasiados argumentos en la función comprobarIntersecta()". Esa función no tiene argumentos, está mal declarada...

Si ves el mensaje que escribí que empezaba
Cita:
Lo que has hecho tiene la misma lógica de lo que yo te comentaba.
Te escribí esta función


Código:
void comprobarIntersecta(sf::FloatRect A, sf::FloatRect B){
//A es el que se mueve. B el que está quieto

if(A.top-(B.top+B.height)==0){//Choca con la parte de arriba por abajo del que está quieto
   chocar[0]=true;
}

if((A.top+B.height)-B.top)==0){//Choca con la parte de abajo por arriba del que está quieto
   chocar[1]=true;
}

if((A.left+A.width)-B.left>0){//Choca con la derecha por la izquierda del que está quieto
   chocar[2]=true;
}

if(A.left-(B.left+B.width)>0){//Choca con la izquierda por la derecha del que está quieto
   chocar[2]=true;
}


}
Esa función tiene los dos argumentos. Revisa tu código... estás haciendo una mezcla de todo...

Etiquetas: int
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 22:30.