[ayuda palib] colisiones

hola de nuevo :P

esta vez mi duda es sobre las colisiones,
estoy tratando de crear un space invader y la verdad, no se que metodo de colision usar (y en muchos casos como usarla)

este es el codigo, y esta vez si que esta mas ordenadito (aunque hay declaradas u32 que no estoy usando por el momento)
// Includes
#include <PA9.h>       // Include for PA_Lib
#include "gfx/all_gfx.h"
#include "gfx/all_gfx.c"
   u32 x=100;
   u32 y=191-32;
   u32 balay=383;
   u32 velocidadbalay=0;
   u32 noesta=0;
u32 marx=0;
u32 mary=0;
u32 movx=1;
u32 movy=0;

// Function: main()


int main(int argc, char ** argv)
{
   PA_Init();    // Initializes PA_Lib
   PA_InitVBL(); // Initializes a standard VBL
   PA_InitText(1,1);
   PA_SetScreenSpace(0);
   
   
PA_LoadSpritePal(0, // Pantalla
         0, // Numero de paleta
         (void*)nave_Pal);   // Nombre de paleta
PA_DualLoadSpritePal(1,(void*)bala_Pal);      
PA_DualLoadSpritePal(2,(void*)malo_Pal);

   PA_DualCreateSprite(1,(void*)malo_Sprite,OBJ_SIZE_32X32,1,2,0,0);
   PA_DualCreateSprite(2,(void*)malo_Sprite,OBJ_SIZE_32X32,1,2,32,0);
   PA_DualCreateSprite(3,(void*)malo_Sprite,OBJ_SIZE_32X32,1,2,64,0);
   PA_DualCreateSprite(4,(void*)malo_Sprite,OBJ_SIZE_32X32,1,2,96,0);
   PA_DualCreateSprite(5,(void*)malo_Sprite,OBJ_SIZE_32X32,1,2,128,0);
   PA_DualCreateSprite(6,(void*)malo_Sprite,OBJ_SIZE_32X32,1,2,160,0);
   PA_DualCreateSprite(7,(void*)malo_Sprite,OBJ_SIZE_32X32,1,2,192,0);       
         
         
               
PA_CreateSprite(0, // Pantalla
         0, // Numero de sprite
         (void*)nave_Sprite, // Nombre de sprite
         OBJ_SIZE_32X32, // Tamaño de sprite
         1, // Modo de 256 colores
         0, // Numero de paleta
         100, 100); // Posicion X e Y en la pantalla
         


   






   while (1)
   {
      //movimiento nave
      if(Pad.Held.Left) {PA_SetSpriteAnim(0,0,1); x-=1; };
      if(Pad.Held.Right){PA_SetSpriteAnim(0,0,2); x+=1; };
    
      if(x==220) x-=1;
      if(x==0) x+=1;
   
      PA_SetSpriteXY(0,0,x,y);
      
      //movimiento bala          
      PA_DualSetSpriteY(10,balay);
      balay+= velocidadbalay;
       
      if(Pad.Newpress.A&&noesta==0){
         PA_DualCreateSprite(10,(void*)bala_Sprite,OBJ_SIZE_8X8,1,1,x+16,y);
         velocidadbalay = -2;
         noesta=1;}
          
      if(balay==1){ PA_DualDeleteSprite(10); velocidadbalay=0; balay=383; noesta=0;  }
     PA_OutputText(1,2,2,"%d", balay);
     
      //malos
marx+= movx;
PA_DualSetSpriteXY(1,(marx>>8),mary);
PA_DualSetSpriteXY(2,(marx>>8)+32,mary);
PA_DualSetSpriteXY(3,(marx>>8)+64,mary);
PA_DualSetSpriteXY(4,(marx>>8)+96,mary);
PA_DualSetSpriteXY(5,(marx>>8)+128,mary);
PA_DualSetSpriteXY(6,(marx>>8)+160,mary);
PA_DualSetSpriteXY(7,(marx>>8)+192,mary);


        if (marx >= 10000){
        movx = -64;
        mary =mary+5;} // Volvemos la velocidad negativa para que vuelva para atras
        if (marx <= 1){
        movx = +64;
        mary =mary+5; } // Volvemos la velocidad positiva para que vuelva para adelante

      //colision
     
     

      
      
      
      PA_WaitForVBL();
   }
   
   
   
   
   return 0;
} // End of main()


edit: lo que quiero hacer colisionar el la bala y el marciano malo, por supuesto
yo uso algo como esto en mi proyecto:
if (borrardisparo==0 && dispx>zombi[nzom].x-32 && dispx<zombi[nzom].x+32 && dispy>zombi[nzom].y-64 && dispy < zombi[nzom].y + 64){
zombi[nzom].vida -=25; // le quito vida al zombi (en tu caso una nave)
PA_DeleteSprite(0, 127); //borro es sprite del disparo
borrardisparo=1; //borro el disparo
}


Claro que hay estan las estructuras de mi proyecto, cambias las variables mias por las tuyas (el zombi es el enemigo, el personaje el que dispara xD) y a mi me va de maravilla.

salu2
Plata escribió:yo uso algo como esto en mi proyecto:
if (borrardisparo==0 && dispx>zombi[nzom].x-32 && dispx<zombi[nzom].x+32 && dispy>zombi[nzom].y-64 && dispy < zombi[nzom].y + 64){
zombi[nzom].vida -=25; // le quito vida al zombi (en tu caso una nave)
PA_DeleteSprite(0, 127); //borro es sprite del disparo
borrardisparo=1; //borro el disparo
}


Claro que hay estan las estructuras de mi proyecto, cambias las variables mias por las tuyas (el zombi es el enemigo, el personaje el que dispara xD) y a mi me va de maravilla.

salu2


que es nzom??
comenta un poco el codigo del "if" xfa, no se que he de sustituir
ademas, como haria para eliminar una nave en concreto? tendria que repetir eso tantas veces como naves tenga? (con sus correspondientes cambios de coordenadas)
highfredo escribió:que es nzom??

aprende un poco sobre arrays de estructuras y formaciones, un poco de C siempre es util. se refiere al id del enemigo (los ordeno por numeros, el zombi 0, el zombi 1, etc...) para poder manejarlos facilmente.

highfredo escribió:comenta un poco el codigo del "if" xfa, no se que he de sustituir


te comento un poco el code(el source esta hecho para disparar a un sprite de 32x64, eso tu lo modificas luego):
// si borrardisparo==0 (no se esta disparando, vamos), y la x del disparo es mayor que la x del zombi menos 32 y la x del desparo es menor que la x del zombi mas 32 y lo mismo pero con la y...
if (borrardisparo==0 && dispx>zombi[nzom].x-32 && dispx<zombi[nzom].x+32 && dispy>zombi[nzom].y-64 && dispy < zombi[nzom].y + 64){
zombi[nzom].vida -=25; // le quito vida al zombi (en tu caso una nave)
PA_DeleteSprite(0, 127); //borro es sprite del disparo
borrardisparo=1; //borro el disparo
}



highfredo escribió:ademas, como haria para eliminar una nave en concreto? tendria que repetir eso tantas veces como naves tenga? (con sus correspondientes cambios de coordenadas)

pues si supieras la respuesta a la primera pregunta, es muy obio, si quieres borrar la nave 10 por ejemplo(en mi caso el zombi 10 xD):

if(zombi[nzom].vida >0){
//aqui metes todo lo relacionado con la nave enemiga (IA, funciones, etc...)
}

else
{
//haces el efectillo de que explota si quieres
PA_DeleteSprite(10);
}


salu2
gracias plata

a ver si sigo con este juego (el Visteme EMO me tiene enganchado :P)
Hay tres tipos de detección de colisiones: por caja, por vector y perfect pixel.

La más usual es la de caja, ya que es fácil y rápido de implementar. Es la que menos recursos consume, pero es la menos precisa, ya que no detecta los píxeles vacios.

La forma de implementar esto es sencilla: tienes 2 vertices por cada objeto: x,y que es la esquina superior izquierda y x2,y2 que es la inferior derecha. Solo tienes que comparar que obj2.x es menor o igual que obj1.x2 y que obj2.x2 es mayor o igual que obj1.x. Lo mismo para las coordenadas verticales.

La segunda forma requieres de la asignación de una estructura de vectores delimitados por dos puntos. El método anterior es una estructura con 4 vectoes que definen el cuadrado. En este método podemos usar los vectores para definir un borde. De esta manera formamos un dibujo a base de lineas uniendo puntos. El dibujo resultante, aunque no es preciso, ya que muchas veces parecen monigotes de palo, es bastante más preciso que la colisión por caja. Se usa bastante en 3D.

La forma de detectar la colisión es buscar los puntos de corte de todos los vectores. Por ejemplo, cojemos todos los vectores de colisión del personaje principal y comprobamos uno a uno los puntos de corte con los vectores del objeto a colisionar. Si ese punto está dentro de los rangos delimitados por las coordenadas de cada vector, quiere decir que se ha detectado la colisión.

La forma más precisa es la pixel perfection. El método comprueba pixel a pixel si uno de ellos está superpuesto a otro pixel del otro objeto. De esta manera solo se detectarán colisiones reales y precisas. Sin embargo esta es una taréa muy pesada. Mientras que con una buena fpu o una gráfica, el método de los vectores se calcula con asombrosa velocidad, el detectar todas las colisiones es una barbaridad, y más si hay muchos objetos en pantalla. 32x32 son 1024 píxeles a comprobar por imagen. A 3 objetos que haya en pantalla se nos va la cpu.

Para solventar este problema se extiende el método de las cajas. Lo primero es comprobar que haya una colisión por caja. Una vez hecha esta colisión tenemos que sacar el trozo donde colisiona. Imagínate un cuadrado de 32x32 cuya esquina superior izquierda está en la posición 1000,1000 y otro objeto de 64x16 que está en la posición 1010,1005. Tenemos que sacar dos trozos, el correspondiente al primer sprite el correspondiente al segundo, solo en las zonas en las que se solapa. De esta manera tenemos que comprobar las coordenadas 1010,1005 a 1032,1021 en ambos sprites.
Al primero le corresponde el recuadro de 10,5 a 32,21 y al segundo le corresponde el cuadrado 0,0 a 22,16. Ahora solo tenemos que buscar los píxeles no transparentes del primero y en caso de que no sea transparente, compararlo con su homólogo en el segundo sprite. Si no es transparente tampoco, se detecta la colisión. De esta manera, sacando el recuadro de colisión nos ahorramos que tener que iterar todos los píxeles de la colisión.
Blue escribió:Hay tres tipos de detección de colisiones: por caja, por vector y perfect pixel.

La más usual es la de caja, ya que es fácil y rápido de implementar. Es la que menos recursos consume, pero es la menos precisa, ya que no detecta los píxeles vacios.

La forma de implementar esto es sencilla: tienes 2 vertices por cada objeto: x,y que es la esquina superior izquierda y x2,y2 que es la inferior derecha. Solo tienes que comparar que obj2.x es menor o igual que obj1.x2 y que obj2.x2 es mayor o igual que obj1.x. Lo mismo para las coordenadas verticales.

La segunda forma requieres de la asignación de una estructura de vectores delimitados por dos puntos. El método anterior es una estructura con 4 vectoes que definen el cuadrado. En este método podemos usar los vectores para definir un borde. De esta manera formamos un dibujo a base de lineas uniendo puntos. El dibujo resultante, aunque no es preciso, ya que muchas veces parecen monigotes de palo, es bastante más preciso que la colisión por caja. Se usa bastante en 3D.

La forma de detectar la colisión es buscar los puntos de corte de todos los vectores. Por ejemplo, cojemos todos los vectores de colisión del personaje principal y comprobamos uno a uno los puntos de corte con los vectores del objeto a colisionar. Si ese punto está dentro de los rangos delimitados por las coordenadas de cada vector, quiere decir que se ha detectado la colisión.

La forma más precisa es la pixel perfection. El método comprueba pixel a pixel si uno de ellos está superpuesto a otro pixel del otro objeto. De esta manera solo se detectarán colisiones reales y precisas. Sin embargo esta es una taréa muy pesada. Mientras que con una buena fpu o una gráfica, el método de los vectores se calcula con asombrosa velocidad, el detectar todas las colisiones es una barbaridad, y más si hay muchos objetos en pantalla. 32x32 son 1024 píxeles a comprobar por imagen. A 3 objetos que haya en pantalla se nos va la cpu.

Para solventar este problema se extiende el método de las cajas. Lo primero es comprobar que haya una colisión por caja. Una vez hecha esta colisión tenemos que sacar el trozo donde colisiona. Imagínate un cuadrado de 32x32 cuya esquina superior izquierda está en la posición 1000,1000 y otro objeto de 64x16 que está en la posición 1010,1005. Tenemos que sacar dos trozos, el correspondiente al primer sprite el correspondiente al segundo, solo en las zonas en las que se solapa. De esta manera tenemos que comprobar las coordenadas 1010,1005 a 1032,1021 en ambos sprites.
Al primero le corresponde el recuadro de 10,5 a 32,21 y al segundo le corresponde el cuadrado 0,0 a 22,16. Ahora solo tenemos que buscar los píxeles no transparentes del primero y en caso de que no sea transparente, compararlo con su homólogo en el segundo sprite. Si no es transparente tampoco, se detecta la colisión. De esta manera, sacando el recuadro de colisión nos ahorramos que tener que iterar todos los píxeles de la colisión.


buena la explicacion, aunque si ya me parece un poco engorroso implementar la deteccion por cajas.. lo ultimo que dices ni me lo plantearia jeje. El sistema del vector me parece bastante ingenioso, y creo que da mejores resultados (que el de cajas, claro)
El de vectores es el más dificil de implementar. Primero necesitas un array de elementos y luego tienes que crear los vectores tu mismo. El pixel perfection es el mejor de todos ellos, pero el de los vectores puede apoyarse en aceleradoras. Sin duda, para un juego 2d el pixel perfect es el mejor de todos. No es realmente muy dificil de implementar, pero si que es cierto que hay que tener mucho cuidado con los excesos de los objetos. Muchas veces es más el problema de detección de colisiones lo que ralentiza un juego cuando hay un excesivo número de objetos.Hay que procurar ajustar el tamaño de los sprites para que no haya muchos huecos transparentes que puedan dar lugar a comparaciones continuas de espacios vacios. Tambien recordar que no hace falta comprar todos los píxeles, cuando encuentre una colisión se puede salir del método.
7 respuestas