Bennu Game Development

Foros en Español => Mesa de Ayuda => Topic started by: Arcontus on October 18, 2010, 07:06:22 PM

Title: Pixel de colisión
Post by: Arcontus on October 18, 2010, 07:06:22 PM
Buenas chicos,

me surge una duda: está claro que mediante la función "collision" podemos averiguar si un proceso colisiona con otro pero, ¿existe algun modo de saber la posición de dicho pixel?

Pej: estoy desarrollando un juego de naves, y me gustaría que cuando las naves colisionan contra paredes, se produzca unas chispas u otro efecto similar, pero para ello, necesito saber en que punto he de mostrarlas.

Gracias de antemano,

Saludos!
Title: Re: Pixel de colisión
Post by: SplinterGU on October 18, 2010, 07:42:59 PM
no, no es posible...
Title: Re: Pixel de colisión
Post by: Arcontus on October 18, 2010, 08:16:53 PM
Quote from: SplinterGU on October 18, 2010, 07:42:59 PM
no, no es posible...

Pues es curioso, por que si para valorar con collision el programa ha de ver si un pixel colisiona con otro, no debería ser demasiado complicado incluir una función que retorne ese punto ¿correcto?.

¿Se os ocurre alguna idea para solucionar este reto?

Saludos!
Title: Re: Pixel de colisión
Post by: Rein (K´)ah Al-Ghul on October 18, 2010, 10:00:24 PM
suponiendo q las paredes sean procesos, cuando la nave colisiona con las paredes esta podria crear procesos q son chispas...

digamos q la nave explata si se cocha con las paredes, podrias poner un mapa de dureza con dos colores uno que saque chispas y otro q haga q explote...
Title: Re: Pixel de colisión
Post by: Arcontus on October 18, 2010, 10:25:36 PM
Quote from: Rein (K´)ah Al-Ghul on October 18, 2010, 10:00:24 PM
suponiendo q las paredes sean procesos, cuando la nave colisiona con las paredes esta podria crear procesos q son chispas...

digamos q la nave explata si se cocha con las paredes, podrias poner un mapa de dureza con dos colores uno que saque chispas y otro q haga q explote...

Esa es la idea, el problema es saber donde está ese roce.
Title: Re: Pixel de colisión
Post by: Windgate on October 18, 2010, 10:47:45 PM
Se podría calcular la posición exacta recorriendo ambos mapas con map_get_pixel hasta localizar las zonas que coinciden. De hecho no sería complicado hacer una función que para toda posición de pixel coincidente invocase un proceso chispa en esa posición.

Ojalá tuviese tanto tiempo como antes para programar estas cositas, de verdad, con map_get_pixel sería facilísimo hacer la función que te digo :'(

PD: Y si existiesen los punteros a función/proceso... Apúntalos nuevamente para la 2.0 Splinter :D
Title: Re: Pixel de colisión
Post by: DCelso on October 18, 2010, 11:03:13 PM
pues yo no lo veo tan fácil, deberías de sacar la posicion absoluta de cada pixel de cada gráfico de los procesos inplicados en el mapa de la pantalla y calcular su pixel de color en su posición relativa del gráfico, osea, sería crearte a manini el collision, es mas, no solo un pixel dará colisión, podría darse el caso de que colisionen mas de un pixel si tus procesos se mueven a mas de un pixel por frame. Osea sería como crearte un collision que devuelva un array de pixeles. :D
Title: Re: Pixel de colisión
Post by: Drumpi on October 19, 2010, 12:02:46 AM
Bueno, si no se ha alterado el punto de control 0, sería tan fácil como buscar el punto de colisión entre los que forman la línea que los unen, sobre todo porque conoceríamos el tamaño de los mapas de ambos procesos.

Pero claro, estoy suponiendo colisiones entre objetos sencillos (formas cuadradas o redondas). Si uno es el mapa del nivel...
En ese caso: map_get_pixel en todos los puntos de la circunferencia/cuadrado que rodea a la nave y buscar el punto medio entre todos los que choquen.
Title: Re: Pixel de colisión
Post by: SplinterGU on October 19, 2010, 01:28:43 AM
Quote from: Arcontus on October 18, 2010, 08:16:53 PM
Quote from: SplinterGU on October 18, 2010, 07:42:59 PM
no, no es posible...

Pues es curioso, por que si para valorar con collision el programa ha de ver si un pixel colisiona con otro, no debería ser demasiado complicado incluir una función que retorne ese punto ¿correcto?.

¿Se os ocurre alguna idea para solucionar este reto?

Saludos!

pues no, no es curioso, hacer una colision del tipo que pensas no seria algo muy optimo, que ya de por si no lo es la funcion de colision, ya el simple hecho de que el primer punto (o juego de puntos, dependiendo de la profundidad de los graficos involucrados) que se detecta la colision ya se dice que colisiona, pero este primer punto no necesaria es el hotspot de la colision.

Quote from: Windgate on October 18, 2010, 10:47:45 PM
Se podría calcular la posición exacta recorriendo ambos mapas con map_get_pixel hasta localizar las zonas que coinciden. De hecho no sería complicado hacer una función que para toda posición de pixel coincidente invocase un proceso chispa en esa posición.

Ojalá tuviese tanto tiempo como antes para programar estas cositas, de verdad, con map_get_pixel sería facilísimo hacer la función que te digo :'(

PD: Y si existiesen los punteros a función/proceso... Apúntalos nuevamente para la 2.0 Splinter :D

eso seria terriblemente lento.

Quote from: DCelso on October 18, 2010, 11:03:13 PM
pues yo no lo veo tan fácil, deberías de sacar la posicion absoluta de cada pixel de cada gráfico de los procesos inplicados en el mapa de la pantalla y calcular su pixel de color en su posición relativa del gráfico, osea, sería crearte a manini el collision, es mas, no solo un pixel dará colisión, podría darse el caso de que colisionen mas de un pixel si tus procesos se mueven a mas de un pixel por frame. Osea sería como crearte un collision que devuelva un array de pixeles. :D

el color no tiene nada que ver, pero por ahi va la cosa, el problema no es simple como vos decis, porque en la mayoria de los casos (yo diria mas del 90%) no colisiona 1 solo pixel, sino que lo hacen muchos, y el "hotspot" de colision podria estar determinado por muchas cosas, como angulos, direccion del movimiento de cada uno de los objetos que estan colisionando y otras tantas cosas, para esto deberia tenerse en cuenta algun algoritmo de fisica.

no hay que olvidar que calcular posicion pixel a pixel seria una locura de procesamiento, es ilogico, ademas de que el algoritmo no debe limitarse solo a la primera colision, sino que deberia detectar todos los puntos de colision y procesarlo en base a reglas fisicas que variaran segun la aplicacion.

Quote from: Drumpi on October 19, 2010, 12:02:46 AM
Bueno, si no se ha alterado el punto de control 0, sería tan fácil como buscar el punto de colisión entre los que forman la línea que los unen, sobre todo porque conoceríamos el tamaño de los mapas de ambos procesos.

Pero claro, estoy suponiendo colisiones entre objetos sencillos (formas cuadradas o redondas). Si uno es el mapa del nivel...
En ese caso: map_get_pixel en todos los puntos de la circunferencia/cuadrado que rodea a la nave y buscar el punto medio entre todos los que choquen.

el punto de control 0 no significa que vaya a colisionar con el.

la cosa seria tener muchos puntos de control, y si un objeto colision, verificar cuales puntos de control entre ellos colisionan con el objeto, y en ese caso tomar alguno de ellos como el punto de impacto, con la cantidad de puntos de control adecuadas no importaria mucho la precision del impacto.
Title: Re: Pixel de colisión
Post by: Noivern on October 19, 2010, 02:02:51 AM
mmm quizás viendolo como un sistema vectorial y un margen de impacto...
y si obtienes el ángulo que hay entre lo que chocas y tu protagonista. Con ese dato, a partir del centro de tu prota le sumas a la X el (coseno del ángulo) * |distancia entre los puntos - margen de impacto| y la Y el (seno del angulo)  * |distancia - margen impacto|. En el punto que obtengase creas las chispas.
El margen de impacto es con lo que choca el prota... no va a ser  pixel preciso, pero yo creo que te serviría para lo que quieres hacer.
A ver si mis mates no me fallan y me dejan en ridículo xD u.u
Title: Re: Pixel de colisión
Post by: Windgate on October 19, 2010, 11:59:52 AM
Sería lento, pero tampoco tanto, al fin y al cabo consistiría en recorrer 2 mapas pixel a pixel. El problema vendría si se ha alterado el valor de size o de angle xD
Title: Re: Pixel de colisión
Post by: SplinterGU on October 19, 2010, 03:06:41 PM
cierto, me habia olvidado de eso, igual pensa que no son 2 mapas, pixel a pixel, pueden ser mas, obviamente deberia ser solo de los que colisionan, pero bueno, se podria, haciendo un map_put sobre otro.
Title: Re: Pixel de colisión
Post by: osk on October 19, 2010, 03:56:14 PM
O no lo entendido bien, o soy un genio (!?), pero con un simple x=father.x ¿no sería suficiente para colocar las chispas donde colisiona la nave?
Title: Re: Pixel de colisión
Post by: TYCO on October 19, 2010, 04:28:22 PM
Quote from: osk on October 19, 2010, 03:56:14 PM
O no lo entendido bien, o soy un genio (!?), pero con un simple x=father.x ¿no sería suficiente para colocar las chispas donde colisiona la nave?
Sí, siempre y cuando crees pequeños procesos ocultos que estén por los bordes de la nave y compruebes con collision si tocan la pared.
Title: Re: Pixel de colisión
Post by: SplinterGU on October 19, 2010, 06:22:56 PM
Quote from: osk on October 19, 2010, 03:56:14 PM
O no lo entendido bien, o soy un genio (!?), pero con un simple x=father.x ¿no sería suficiente para colocar las chispas donde colisiona la nave?

pues no, un simple father.x no es el punto del impacto, a menos que la "bala" o "misil" o lo que sea, sea lo suficientemente pequeño, pero no siempre son balas lo que colisiona, suponete un juego donde son autos que colisionan entre si, y queres ponerle chispas en el roce, con father.x no lo lograras.
Title: Re: Pixel de colisión
Post by: Arcontus on October 19, 2010, 06:40:44 PM
Me alegro de como mínimo haber sacado un buen tema de discusión y de discurrir.

Se me había ocurrido lo que comenta SplinterGU, es decir, introducir por ejemplo 6 puntos en mi nave repartidos en el area de esta (dentro del grafico visible) y de alguna manera, revisar si son esos los puntos de colision, pero que yo sepa, collision no sirve para un punto de imagen ¿cierto?.

Respecto a rehacer toda la funcion collision para esto, no es la idea por rendimiento como también habéis comentado. Yo más bien estaba pensando que collision apuntara el primer pixel que colisiona en una variable de coordenadas para que posteriormente se pudiera consultar, algo similar a KEY y ASCII. No sería 100% preciso, pero para el efecto de chispas serviría.

Y como minimo le veo 2 utilidades:
* Hacer las chispas, obviamente.
* Calcular la dirección del rebote. Es decir que la nave salga disparada en dirección opuesta a la pared del mapa, simplemente calculando el angulo entre el centro de la (o X e Y del proceso) nave y el pixel que ha colisionado.

Este último punto que comento, es algo que estoy intentando discurrir, como realizar un rebote. Si no se si la nave ha impactado contra el mapa de frente o rozando de lado, es dificil determinar la dirección hacia donde debe rebotar la nave... no se si me explico. El mapa es totalmente irregular, pero collision es booleano.

Alguna idea más?

Saludos!
Title: Re: Pixel de colisión
Post by: Noivern on October 19, 2010, 07:04:37 PM
¿Alguien leyó lo que escribí?
Encuentro que usando trigonometría es la manera más simple, incluso se me ocurrio otra forma aun más fácil. A partir del centro del prota creas los chispasos. Debes calcular el ángulo entre la nave y con lo que choca, un simple get_angle() si es un proceso, y luego a las chispas darle un xadvance() con el angulo obtenido y la cantidad de pixeles definida como el radio de "mostrar la colision" de la nave, todo esto antes del primer frame de las chispas.
Como resultado veras las chispas crearse en un area de la zona en que chocó la nave. Como dije no es pixel exacto pero con varios chispasos (generador de particulas) ni se va a notar.
Title: Re: Pixel de colisión
Post by: SplinterGU on October 19, 2010, 07:25:27 PM
por supuesto que te leimos, pero no creo que sea tan simple como eso, aunque quizas una solucion cutre sea poniendo la chispa en la coordenada resultante del medio del box area de colision de ambos procesos, esto es:

- generamos 2 regiones segun el tamaño de cada grafico que colisiono (tambien se puede usar esto como algoritmo de colison) con centro en la mitad del grafico
- hacemos un region_union, y obtenemos una nueva region, que es la region de colision
- el centro de esta nueva region es el centro de la colsion y ahi tenemos donde poner la chispa.

con esto no me refiero a usar las funciones de REGION incluidas en bennu, porque creo que no estan todas exportadas, asi que quizas lo mejor es hacerlo a mano, son pocos calculos.

EDIT: estoy pesando que asi son las nuevas funciones de colision circle y colision box, no son pixel perfect, pero si colisionan por regiones, unas circulares y otras cuadradas, y podria meter alguna funcion adicional y opcional con parametros punteros x e y, para retornar el centro de la colision solo para estos 2 tipos de colision, no lo haria en pixel perfect.
Title: Re: Pixel de colisión
Post by: DCelso on October 19, 2010, 08:43:52 PM
y ¿que tal poner las chispas en el medio de la distancia del centro ente los dos sprites colisionados?
Title: Re: Pixel de colisión
Post by: Windgate on October 19, 2010, 11:14:45 PM
Kagondio, estoy por hacer la prueba con un par de sprites que se mueven y detectar exactamente los píxeles de colisión para sacar ahí unos cuantos procesos chispa.

De acuerdo, eso consume, ¿Pero para qué tenemos las CPU de hoy en día?

Anda que no consume polígonos el ZBrush cuando modelas "a pico y pala", pero para eso tenemos esas cucarachitas circuiteadas xD

PD: Ni 100 líneas de código tendría esa cosa...
Title: Re: Pixel de colisión
Post by: Arcontus on October 19, 2010, 11:28:19 PM
Quote from: DCelso on October 19, 2010, 08:43:52 PM
y ¿que tal poner las chispas en el medio de la distancia del centro ente los dos sprites colisionados?


El mapa es demasiaaado grande e irregular como para tener en cuenta esa posibilidad.

Respecto al metodo que comenta SplinterGU, no lo entendi. :(

Windgate, pues me harías un favor, o como minimo explicarme como harías la funcion y la intento hacer yo.

Gracias,

Saludos!
Title: Re: Pixel de colisión
Post by: SplinterGU on October 19, 2010, 11:46:16 PM
Quote from: DCelso on October 19, 2010, 08:43:52 PM
y ¿que tal poner las chispas en el medio de la distancia del centro ente los dos sprites colisionados?


pues no, eso sirve si los graficos que colisionan son del mismo tamaño.

Quote from: Windgate on October 19, 2010, 11:14:45 PM
Kagondio, estoy por hacer la prueba con un par de sprites que se mueven y detectar exactamente los píxeles de colisión para sacar ahí unos cuantos procesos chispa.

De acuerdo, eso consume, ¿Pero para qué tenemos las CPU de hoy en día?

Anda que no consume polígonos el ZBrush cuando modelas "a pico y pala", pero para eso tenemos esas cucarachitas circuiteadas xD

PD: Ni 100 líneas de código tendría esa cosa...

despues lo van a querer correr en una consolita portatil.... y ahi no hay tanta cpu...

como extraño la programacion de la vieja escuela... :(

Quote from: Arcontus on October 19, 2010, 11:28:19 PM
Quote from: DCelso on October 19, 2010, 08:43:52 PM
y ¿que tal poner las chispas en el medio de la distancia del centro ente los dos sprites colisionados?


El mapa es demasiaaado grande e irregular como para tener en cuenta esa posibilidad.

Respecto al metodo que comenta SplinterGU, no lo entendi. :(

Windgate, pues me harías un favor, o como minimo explicarme como harías la funcion y la intento hacer yo.

Gracias,

Saludos!

poder ver el codigo del collision y del calculate_box o algo asi, en la lib de render.

es demasiado simple, pensa en 2 pedazos de papel cuadrados (cada 1 representa un grafico) cuando colisionan, ambos se superponen, y esa superposicion forma un nuevo rectangulo (no nos preocupemos en esta instancia por las rotaciones y tamaño, si necesitamos poder ver el codigo de la librender para calcular los corners -esquinas- del grafico) y ese nuevo rectangulo es el que digo yo, el centro de eso es el "punto caliente" de la colision.
Title: Re: Pixel de colisión
Post by: Drumpi on October 20, 2010, 12:35:16 AM
Quote from: Arcontus on October 19, 2010, 11:28:19 PM
Quote from: DCelso on October 19, 2010, 08:43:52 PM
y ¿que tal poner las chispas en el medio de la distancia del centro ente los dos sprites colisionados?


El mapa es demasiaaado grande e irregular como para tener en cuenta esa posibilidad.

En ocasiones me alegro de usar un motor de tiles basado en proceso por tile ;D
No, en serio, la primera idea de hacerlo fue simplificar las colisiones de un submarino con el escenario.

Luego determiné que era más rápido usar 4 puntos de control y map_get_pixel!=0 ^^U
Title: Re: Pixel de colisión
Post by: Windgate on October 20, 2010, 12:37:09 AM
Se me ocurre una solución eficiente:

Una vez detectada la colisión de la nave con ese mapa taaaan graaaande, se lanzan 8 sondas, una en cada dirección, que comprueban dónde hubo colisión con el mapa.

Aquellas que detecten colisión con el mapa sacan chispas en ese punto y ya.

Pero sigo insistiendo en que no debería consumir tanto la solución de detectar exactamente los píxeles que chocan.
Title: Re: Pixel de colisión
Post by: SplinterGU on October 20, 2010, 02:49:27 AM
dale wind, hace la prueba y mete una cantidad razonable de procesos... unos 100 o 200... estaria bueno probarlo.
Title: Re: Pixel de colisión
Post by: Arcontus on October 20, 2010, 05:34:27 PM
Karma Up para SplinterGU, Windgate, Drumpi y DCelso.

SplinterGU, ahora entiendo que quieres decir, pero sigo sin saber como programarlo...

Windgate, me encanta la solucion de las sondas, es excelente como mínimo para el rebote de la nave y para la precisión de las chispas es cuestión de lanzar mas de 8 sondas :D.

A ver si este fin de semana tengo tiempo en programar la idea de Windgate y os cuento.

Drumpi, aun no se si utilizar tiles o no, por que el mapa es cerrado, algo así como un circuito y no se si es más optimo hacerlo por tiles o mediante un solo mapa. En definitiva si lo hiciera por tiles sería el mismo mapa recortado a cuadriculas y nuevamente montado.

Respecto a rendimiento, pues mientras más tire mejor, pero no está pensado para resoluciones inferiores a 1024x768 por la cantidad de elementos que hay que controlar, así que consolas descartado.

Saludos!
Title: Re: Pixel de colisión
Post by: Windgate on October 20, 2010, 07:44:21 PM
Me imagino que consumirá lo suyo y con muchos procesos se notará, pero si sólo es para hacerlo entre la nave protagonista y otros procesos no se ejecutará tan a menudo, sólo cuando haya una colisión que suele ser cada varios FRAMES y casi siempre con un sólo proceso cada vez.

Si lo pruebas sube el ejemplo, me gustaría mucho verlo :D
Title: Re: Pixel de colisión
Post by: Arcontus on October 24, 2010, 12:40:41 PM
Quote from: Windgate on October 20, 2010, 07:44:21 PM
Me imagino que consumirá lo suyo y con muchos procesos se notará, pero si sólo es para hacerlo entre la nave protagonista y otros procesos no se ejecutará tan a menudo, sólo cuando haya una colisión que suele ser cada varios FRAMES y casi siempre con un sólo proceso cada vez.

Si lo pruebas sube el ejemplo, me gustaría mucho verlo :D

Lo prometido es deuda; Aquí tienes la funcion programada:


FUNCTION AnguloColision(int x1,int y1);
PRIVATE
int izq, der, arr, aba, indice, coincidencias, precision, escala;
BEGIN
x = x1;
y = y1;
//variables que guardaran el numero de coincidencias por lado
izq = 0;
der = 0;
arr = 0;
aba = 0;
coincidencias = 0;
//Numero de pixeles a partir de la coordenada de la nave que serán evaluados por cada lado
precision = 6;
//Escala entre el mapa y su grafico de durezas
escala = 500;

//Calculamos los pixeles de dureza del lateral "izquierdo".
for (indice = 0; indice < precision; indice ++)
x = x + escala;
if ((map_get_pixel(durezaFPG, 1, X /escala, Y /escala)) != 0);
izq++;
else
x = x + (escala/2);
END
END
    //En caso de haber encontrado pixels de colision por la "izquierda", aumentamos "coincidencias"
if (izq != 0) coincidencias++;END
//Restablecemos las coordenadas para calcular el siguiente bucle
x = x1;

    //Calculamos los pixeles de dureza del lateral "derecho".
for (indice = 0; indice < precision; indice ++)
x = x - escala;
if (map_get_pixel(durezaFPG, 1, X /escala, Y /escala) != 0);
der++;
else
x = x - (escala/2);
END
END
//En caso de haber encontrado pixels de colision por la "derecha", aumentamos "coincidencias"
if (der != 0) coincidencias++;END
//Restablecemos las coordenadas para calcular el siguiente bucle
x = x1;

//Calculamos los pixeles de dureza del lateral "abajo".
for (indice = 0; indice < precision; indice ++)
        y = y + escala;
if (map_get_pixel(durezaFPG, 1, X /escala, Y /escala) != 0);
aba++;
else
y = y + (escala/2);
END
END
//En caso de haber encontrado pixels de colision por "abajo", aumentamos "coincidencias"
if (aba != 0) coincidencias++;END
//Restablecemos las coordenadas para calcular el siguiente bucle
y = y1;

    //Calculamos los pixeles de dureza del lateral "arriba".
for (indice = 0; indice < precision; indice ++)
y = y - escala;
if (map_get_pixel(durezaFPG, 1, X /escala, Y /escala) != 0);
arr++;
else
y = y - (escala/2);
END
END
//En caso de haber encontrado pixels de colision por "arriba", aumentamos "coincidencias"
if (arr != 0) coincidencias++;END

//No podemos decidir cual es el lateral de escape si las 4 coordenadas dieran alguna "coincidencia".
//En el caso de que suceda, evaluaremos como angulo de escape aquel que tenga menos "coincidencias".
while (coincidencias == 4)
arr--;
aba--;
izq--;
der--;
coincidencias = 0;
    if (arr != 0) coincidencias++;END
    if (aba != 0) coincidencias++;END
    if (izq != 0) coincidencias++;END
    if (der != 0) coincidencias++;END
END

//En el caso de que haya 0 coincidencias (o bien por que no se detecta colision con el mapa de durezas,
//o bien por que con la "precision" establecida todos los lados tienen la misma cantidad de coincidencias, retornamos -1
if (coincidencias == 0) return -1;END
//En el caso de que haya más de 1 "coincidencia", retornamos el valor de la primera coordenada "libre" de colision.
if (coincidencias > 1)
if (izq == 0) return 0;END
if (der == 0) return 180000;END
if (arr == 0) return 90000;END
if (aba == 0) return 270000;END
END
//En el caso de que haya solo 1 coincidencia, retornamos el angulo inverso donde esta se localizo.
if (coincidencias == 1)
        if (izq == 1) return 180000;END
if (der == 1) return 0;END
if (arr == 1) return 270000;END
if (aba == 1) return 90000;END
END
//Si hubiera algun error en el proceso, retornamos -1.
return -1;
END


Como se podrá observar, la funcion es muy rudimentaria y mejorable a nivel de optimización de código, pero quería mostrarla lo más simple posible para que se entienda como funciona. Concretamente solo evalua 4 puntos cardinales con respecto a las coordenadas pasadas. Retorna el "mejor" valor de escape de la colisión contra el mapa de durezas.

Para que funcione, hay que configurar la variable escala, a la escala del mapa de durezas que utiliceis. Por otro lado, se tiene que tener en cuenta que el único pixel que cuenta como no colisionable, es el 0. Y por último obviamente el mapa de durezas.

Mis impresiones son positivas, ya que hace lo que necesitaba, y no observo bajada de rendimiento en el juego. Supongo que el hecho de que solo evalue "resolucion" x 4 coordenadas hace que sean pocos pixeles a evaluar, de manera que va bien la cosa...

Si alguien quiere usar esa funcion en su código, sientase libre de hacerlo.

Espero que les agrade la solución,

Saludos!