| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
Benway Invitado
|
Publicado: Lun Jun 12, 2006 14:56 pm Asunto: Tutorial: Detección de colisiones |
|
|
Como ya dije, me he estado currando un mini tutorial sobre la detección de colisiones. Es bastante básico, no esperéis maravillas, pero creo que puede ser útil para quien esté empezando a programar, e interesante para recordar conceptos para los demás
Lo podéis bajar de http://computeremuzone.com
Ya me diréis qué os parece...
Ultima edición por Benway el Jue Abr 05, 2007 13:20 pm, editado 2 veces |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Lun Jun 12, 2006 16:06 pm Asunto: |
|
|
Ostras Ben!!! Muchísimas gracias y te lo has currao un huevazo tio !!!! _________________
 |
|
 |
|
 |
Benway Invitado
|
Publicado: Lun Jun 12, 2006 16:14 pm Asunto: |
|
|
Tú como siempre tan exageraoooo
He intentado contar lo que a mí me hubiese gustado que me contasen cuando empecé a programar, y que tuve que currarme mirando en mil sitios: 999 de ellos en inglish-pitinglish, que se me da fatal
De todas maneras, seguro que no he dicho nada que tú no supieras ya  |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Lun Jun 12, 2006 16:32 pm Asunto: |
|
|
De momento es que lo he ojeado por encima. Mañana me lo leeré de pé a pá porque me he pegao toda la tarde de programación y tengo la olla ya que no veas...
Yo es que me lo esperaba más sencillo y joder!!! le has metido fotos y esquemas tio!!!
Chapeau!!!! _________________
 |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Mie Jun 14, 2006 06:39 am Asunto: |
|
|
Oye Ben me he estado leyendo tu tutorial en el curro y joder, para mí está de puta madre. Lo único que el tema de la rotación binaria me lo tengo que empoyar porque me cuesta verle la aplicación y no lo acabo de entender
He leido en la parte del cálculo del triángulo rectángulo que te resulta pitágoras una formula lenta. Porqué no pruebas las del seno coseno que son más sencillas, directas y manejables?
vectorX = cateto convergente(coseno), vectorY= cateto opuesto(seno), Distancia=hipotenusa
Para calcular el vectorX:
cateto convergente=cos del ángulo*distancia
VectorY:
cateto opuesto=seno del ángulo*distancia
Distancia:
-si tienes vectorX:
distancia=cos del ángulo/cateto convergente
-Si tienes vectorY:
distancia=seno del ángulo/cateto opuesto
-----
Formulas básicas:
tan=cateto opuesto/cateto convergente
seno=cateto opuesto/hipotenusa
coseno=cateto convergente/hipotenusa
Todas las de arriba son estas despejadas y son las que uso en el curro. Con solo estas tres formulitas resuelves cualquier triángulo rectángulo (siempre y cuando tengas siempre dos elementos, grados o catetos)
:wink: _________________
 |
|
 |
|
 |
Benway Invitado
|
Publicado: Mie Jun 14, 2006 12:10 pm Asunto: |
|
|
Muchas gracias, Alx...
Luego lo miro despacio y lo añado
--
Lo de la rotación binaria es muuuy fácil y útil
Si tienes dos sprites que tienen una FILA en común, es decir, uno está encima de otro, colisionando la última fila del primero y la primera del segundo, peeeero el de arriba está un píxel a la izquierda del segundo:
| Código: |
|------|
| |
|-====-|-
| |
|------| |
Y tenemos estas máscaras de bits:
última fila del primero:
11111110
primera fila del último
00000010
Se supone que las máscaras de bits son una representación de los sprites, pero... No tienen coordenadas. Es el gráfico sin más, con unos y ceros, pero hay que hacer algo para arreglar el tema de la posición "relativa" entre los dos sprites.
Si hacemos un AND entre esas dos máscaras, saldría de resultado 2 (2º Bit). PERO ES QUE EL SEGUNDO SPRITE está un píxel más a la derecha que el primero... así que la "corremos" a la derecha 1 posición:
00000001
Y esa operación de rotación la hacemos mediante el operador >> en C: 00000010 >> 1 = 00000001, o lo que es lo mismo: 2 >> 1 = 1
Lo único que hace es correr X veces hacia el lado que corresponda los números. Es como la multiplicación y la división por la unidad seguida de ceros en el sistema decimal:
234 * 100 = 23400 -> Corremos 2 posiciones a la izquierda
234 / 10 = 23 -> Corremos una posición a la derecha (se trunca, pq es un número entero... en la vida real sería 23,4)
Pos en binario igual
11011101 << 3 = 11101000
11011101 >> 2 = 00110111
Con esto, insisto, ajustamos las posiciones relativas de los sprites EN EL EJE HORIZONTAL, aplicándolo en las máscaras.
El eje vertical es más fácil: Basta con escoger las filas que se quieren usar, y compararlas con las adecuadas del sprite contrario 
Ultima edición por Benway el Mie Jun 14, 2006 12:47 pm, editado 1 vez |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Mie Jun 14, 2006 12:29 pm Asunto: |
|
|
No, si lo de que si rota 3 para la izquierda el "1" se corre 3 espacios a la izquierda lo entiendo.
Lo que no entiendo el uso de esto en un gráfico.
Es que al menos yo (y Fénix) trabajo sobre las coordenadas del sprite.
Si utilizo mapas de durezas que supongo que deben ser lo que tú llamas máscaras, utilizo la función map_get_pixel(); que me devuelve el valor de 0 255 del color que haya en ese pixel.
map_get_pixel(fichero de gráficos, mapa_de_dureza, x, y);
O sinó tengo la función collision(); que me dice si toca a un proceso por cualquier punto al píxel.
collision(TYPE proceso);
O sinó, utilizo variables usándolas como distancias:
distancia=prota1.x-prota2.x;
If(distancia<que lo que sea) bla bla bla...
Pero claro, esto de los unos y ceros rotándolos para los gráficos no lo acabo de pillar
Pero tampoco te calientes el tarro que lo acabaré entendiendo pisha!!! :wink: _________________
 |
|
 |
|
 |
Benway Invitado
|
Publicado: Mie Jun 14, 2006 12:45 pm Asunto: |
|
|
Okis... pero recuerda que estamos hablando "en genérico", a "bajo nivel"... No hay procesos "mágicos" tipo int Collision (...)... como tú dices que hay en fénix. Hay que currarse todo ... solo podemos comparar cosas y hacer bucles y tal . Es como verdaderamente se aprende
Las máscaras de bits son una matriz de 1 y 0:
| Código: |
00000000
00111100
01000010
01000010
01111110
01000010
01000010
00000000 |
Esa sería la máscara de una letra A.
Al principio del programa (o así lo hago yo), se rastrea el sprite y se almacenan esos unos y 0 en función de los colores del sprite
| Código: |
for (n = 0; n < AnchoSprite; n++)
for (m = 0; m < AltoSprite; m++)
if (getpixel (Sprite, n, m) != COLOR_TRANSP)
Mascara [m] += 1 << (AnchoSprite - n);
|
De esa manera, tenemos almacenados en un vector Mascara, de una dimensión igual al número de filas de píxeles que tenga el sprite. Es como cuando se hacían los gráficos en el spectrum
De esa manera, tenemos el gráfico almacenado 2 veces en memoria: Una en forma de Bitmap (el gráfico en sí), y otra simplificada, a "blanco y negro", que es la máscara. ¿Por qué hacemos esto? Pq es más rápido comparar las máscaras que comparar los sprites: Solo se comparan 0's y 1's.
Por qué desplazamos las máscaras? PARA TRABAJAR CON LAS COORDENADAS. En el ejemplo que te ponía antes, si no la desplazas, hay colisión, PERO EN REALIDAD NO LA HAY... porque el sprite de abajo está UN PÍXEL A LA DERECHA del de arriba. ¿Cómo podemos ajustar eso a la hora de comparar las máscaras? Rotándola un bit a la derecha ( o siete a la izquierda la máscara contraria, pq son máscaras de 8 bits) |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Mie Jun 14, 2006 13:02 pm Asunto: |
|
|
Bueno bueno bueno...voy pillando más Ben :wink:
Eso del bucle yo también lo he hecho con una array (tabla o matriz) en plan:
tiles[19]= 0,0,0,0,1,0,0,0,0,0,
0,0,0,0,0,1,1,1,0,0;
Luego le meto el bucle:
FOR (n=0; n<1; n++)
FOR (m=0; m<10; m++)
if (tiles[m]==1) PON UN GRÁFICO; end
end
end
Yo esto lo he usado y me ha funcionado pero sólo para poner gráficos, no sé como usarlos de otra forma
Es lo malo de ser Padawain  _________________
 |
|
 |
|
 |
Benway Invitado
|
Publicado: Mie Jun 14, 2006 13:49 pm Asunto: |
|
|
Ok... Entonces ya lo entiendes? Si no, dime x dónde sigo explicando
Lo de los tiles, en realidad, sería algo así como...
La matriz Tiles no tiene pq ser solo 0 y 1, sino el número de cada tile, y es más fácil hacerla bidimensional: Una auténtica cuadrícula, donde cada casilla es un tile:
| Código: |
Tiles[Ancho][Alto] =
{ 0, 0, 1, 0, 2, 3, 4, 2, 3 }
{ 0, 1, 2, 0, 5, 6, 7, 5, 6 }
...
for (n = 0; n < Ancho; n++)
for (m = 0; m < Alto; m++)
PONGRAFICO (Tiles[n][m], n * Anchodeltile (posicion X), m + Altodeltile (posición Y); |
Esto con una capa de tiles. Si queremos más, habría que meterle una tercera dimensión [Capas] a la matriz, y un tercer bucle AL PRINCIPIO de los otros dos : for (o = 0; o < Capas; o++) |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Mie Jun 14, 2006 14:07 pm Asunto: |
|
|
Sí, Fénix te deja hacer arrays o incluso estructuras de datos de más de una dimensión:
mi_tabla [10] [5] [0] [189273];---> 4dimensiones (o capas como dices tú)
Lo que no sé como se accedería a las otras dimensiones ej:
una dimension---> mi_tabla[9];
accedería con el puntero (indice) a la última posición de dimensión 1 así
---> mitabla[9]=valor que le quiero dejar;
Pero no sé como lo haría con 2 dimensiones:
2 dimensiones---> mi_tabla[9][9];
Como accedo si quiero poner un 2 en la última posición de la segunda dimensión?
-----> mitabla ? ?
------
Yo el número que pongo dentro de la matriz es el código del gráfico, el 0 es que no ponga nada.
0--->no pongas nada
1--->un gráfico de planta
2--->un perrito
3---->suelo
4---->cielo
y así hasta el infinito peeeeero, aquí viene MI GRAN DUDA.
Como leches se hace para que el gráfico del protagonista interaccione con estos números que están dentro de la cuadrícula?
Si pones un :
IF (pulso tecla derecha) incrementa hacia la derecha 8 píxels de golpe; END
Yo pondría la técnica del píxel perfect ( ) con un bucle punto por punto hasta 8 de incremento.
PERO COMO COJONES SABE EL PROTA QUE DELANTE TIENE UN 4 QUE ES CIELO????
 _________________
 |
|
 |
|
 |
Benway Invitado
|
Publicado: Mie Jun 14, 2006 14:16 pm Asunto: |
|
|
Yo los llamo dimensiones Las capas es para capas de tiles, quiero decir, si pones una capa posterior al plano de la acción, luego la del plano de la acción, y luego otra delante de los personajes... pues tienes 3 capas, pero eso, a la hora de definirlo en una matriz, se llama dimensión
Si tenemos una matriz Matrix[9][9], y quieres poner un 2 en la última casilla del todo, en C se haría así: Matrix[8][8] = 2; Ocho ocho y no 9 9, pq tiene 9 "casillas" en cada dimensión... y la primera es el 0, así que la última el 8.
Como interaccionar los sprites con los tiles? Pos mú fácil
Si los tiles se empiezan a poner en la posición 0, 0, y el personaje está en la 180, 120... ¿Qué tiles ocupa?
Pues...
En el eje X ocupa desde 180 / Anchodeltile hasta (180 + Ancho del sprite) / Anchodeltile
En el eje Y ocupa desde 120 / Altodeltile hasta (120 + Alto del sprite) / Altodeltile
Siempre pensando que la coordenada del sprite hace referencia a la esquina superior izquierda
Ahora tienes que hacer un bucle que rastree esos tiles, y mirar si colisionan PixelPerfect (pq bouncing box ya sabes que sí colisionan) con el sprite completo
Y ese es el secreto  |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Mie Jun 14, 2006 14:25 pm Asunto: |
|
|
| Benway escribió: |
Si tenemos una matriz Matrix[9][9], y quieres poner un 2 en la última casilla del todo, en C se haría así: Matrix[8][8] = 2; Ocho ocho y no 9 9, pq tiene 9 "casillas" en cada dimensión... y la primera es el 0, así que la última el 8. |
Ben, aquí te has colao. Una array de [9] lo que tiene son 10 espacios. Desde del 0 al 9 (en Fénix empiezan en 0 también y x0y0 es arriba izquierda también)
| Cita: |
Ocho ocho  |
| Cita: |
Como interaccionar los sprites con los tiles? Pos mú fácil
Si los tiles se empiezan a poner en la posición 0, 0, y el personaje está en la 180, 120... ¿Qué tiles ocupa?
Pues...
En el eje X ocupa desde 180 / Anchodeltile hasta (180 + Ancho del sprite) / Anchodeltile
En el eje Y ocupa desde 120 / Altodeltile hasta (120 + Alto del sprite) / Altodeltile
Siempre pensando que la coordenada del sprite hace referencia a la esquina superior izquierda
Ahora tienes que hacer un bucle que rastree esos tiles, y mirar si colisionan PixelPerfect (pq bouncing box ya sabes que sí colisionan) con el sprite completo
Y ese es el secreto  |
Ya tengo deberes !!!
Asias amo'll!!! _________________
 |
|
 |
|
 |
Benway Invitado
|
Publicado: Mie Jun 14, 2006 14:30 pm Asunto: |
|
|
| Alx escribió: |
| Benway escribió: |
Si tenemos una matriz Matrix[9][9], y quieres poner un 2 en la última casilla del todo, en C se haría así: Matrix[8][8] = 2; Ocho ocho y no 9 9, pq tiene 9 "casillas" en cada dimensión... y la primera es el 0, así que la última el 8. |
Ben, aquí te has colao. Una array de [9] lo que tiene son 10 espacios. Desde del 0 al 9 (en Fénix empiezan en 0 también y x0y0 es arriba izquierda también) |
En C, una matriz [9][9] tiene 9 x 9 "espacios", que van desde el 0 hasta el 8
| Alx escribió: |
| Cita: |
Ocho ocho  |
|
 |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Mie Jun 14, 2006 14:45 pm Asunto: |
|
|
Joder, que raro lo de la matriz, me extraña que vayan al revés.
En Fénix por ejemplo si guardo 3 graficos para las tres vidas haria:
grafico_nave[2];
grafico_nave[0]= nave();
grafico_nave[1]= nave();
grafico_nave[2]= nave();
O sea 3 elementos dentro de la tabla. Me extraña que en C se reste  _________________
 |
|
 |
|
 |
Benway Invitado
|
Publicado: Mie Jun 14, 2006 15:09 pm Asunto: |
|
|
| Alx escribió: |
O sea 3 elementos dentro de la tabla. Me extraña que en C se reste  |
No se resta... se dice la verdad. Si quieres guardar 3 gráficos, defines la matriz como de 3 elementos: Matriz [3]: Uno es el 0, otro el 1 y el último el 2.
Ultima edición por Benway el Mie Jun 14, 2006 18:16 pm, editado 1 vez |
|
 |
|
 |
Benway Invitado
|
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Mie Jun 14, 2006 15:24 pm Asunto: |
|
|
Rarísimo
No es que me refiera a que se reste, sinó que si quieres 5 en la array has de poner 4.
----
A veces lo que hago para las animaciones es no tener en cuenta el 0.
animacion[9]=9, 54,32,53,74,75,96,97,28,9;
En Fénix de esta forma tendré una animación de 9 frames y la posicion cero la uso como offset.
ani=1;
---
graph=animacion[ani++]
if(ani>animacion[0]) ani=1;
La tabla contiene 10 elementos, empieza en ani=1 (gráfico 54) pero si supera a animacion[0] (o sea 9) pasa a ani=1 otra vez. _________________
 |
|
 |
|
 |
Benway Invitado
|
Publicado: Mie Jun 14, 2006 15:35 pm Asunto: |
|
|
Eso que comentas, viene marcado porque una matriz, en realidad, es un puntero. Y entronca con el tema de la aritmética de punteros.
Si tienes una matriz, o, mejor dicho, vector a enteros int MiVector[9], puedes referirte a sus miembros individualmente como MiVector[0], MiVector[1] etc... , pero tb tienes un puntero a enteros que es el nombre del vector: MiVector. De tal manera que *MiVector es lo mismo que MiVector[0], *MiVector + 1 es lo mismo que MiVector[1], etc...
Se ve que en Fénix lo han hecho de la otra manera para simplificar esto de la aritmética de punteros y tal. |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Mie Jun 14, 2006 15:40 pm Asunto: |
|
|
jjjjjjjjjjjj.....
Porqué te crees que programo en él ...........
Pa tontos ! _________________
 |
|
 |
|
 |
Benway Invitado
|
Publicado: Mie Jun 14, 2006 18:21 pm Asunto: |
|
|
El C tb es muy fácil, de veras...
Yo prefiero trabajar a "bajo nivel", y tener toda la libertad para currarme las cosas como yo quiera, y de esa manera aprendo a hacerlo, y a "solucionar problemas" para cuando quiera hacer algo nuevo.
Por ejemplo, ahora estoy intentando optimizar un "scroll parallax", y me mola tener que pensar cómo hacerlo, en lugar de tener una función int ScrollParallax (...) que lo haga todo.
Lo que pasa es que tienes que perder más tiempo a veces para pensar cómo hacer las cosas... por ejemplo las colisiones.
Cuando estuve haciendo el "Horacio Esquiador", no me había planteado las colisiones. Cuando llegó el momento, hice las "Bouncing Box", que era lo que sabía hacer, y quedaba fatal así a secas. Estuve a punto de mandarlo a la mierda y dejar de programar, pero soy muy cabezota, así que pensé y pensé y pensé y pensé... Y tb googleé... y el caso es que al final opté por lo de las máscaras de bits, que me costó como 2 semanas hacer funcionar, pero que al final hizo que me sintiera muy orgulloso (aunque sea una chorrada) de haberlo hecho
Aunque luego está el tema de que si te manejas bien en un medio, (p.ej. fénix)... ¿te merece la pena perder tiempo aprendiendo otro? ... Depende de lo que quieras hacer, y las limitaciones de tu medio y las ventajas del otro. Por ejemplo, yo, por el momento, paso de aprender SDL pq ya estoy liao con Allegro, como comentaba en CEZ. |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Jue Jun 15, 2006 06:57 am Asunto: |
|
|
Sí claro Ben ! si yo estoy contigo es lo que dices al 501% de acuerdo.
Si mi máxima prioridad hoy día (más que el japonés ) es :
-Acabar todos mis proyectos: Scaramouche, MinerOman, Shotcan, Plump.
-Aprender de un aputa vez las colisiones/detecciones con tiles.
-Aprender C+ librería allegro o SDL (según tu recomendación )
A mi lo que me pasa es que Fénix al menos te sirve para aprender lo básico algo más fácil. Pero que tampoco creas que si me lié con Fénix fué por esto, fue porqué en su día me compré el primer Div Games Studio que fué la puerta mia a la programación. Div murió y me pasé a Fénix. _________________
 |
|
 |
|
 |
Benway Invitado
|
Publicado: Lun Sep 18, 2006 12:32 pm Asunto: |
|
|
| Alx escribió: |
Oye Ben me he estado leyendo tu tutorial en el curro y joder, para mí está de puta madre. Lo único que el tema de la rotación binaria me lo tengo que empoyar porque me cuesta verle la aplicación y no lo acabo de entender
He leido en la parte del cálculo del triángulo rectángulo que te resulta pitágoras una formula lenta. Porqué no pruebas las del seno coseno que son más sencillas, directas y manejables?
vectorX = cateto convergente(coseno), vectorY= cateto opuesto(seno), Distancia=hipotenusa
Para calcular el vectorX:
cateto convergente=cos del ángulo*distancia
VectorY:
cateto opuesto=seno del ángulo*distancia
Distancia:
-si tienes vectorX:
distancia=cos del ángulo/cateto convergente
-Si tienes vectorY:
distancia=seno del ángulo/cateto opuesto
-----
Formulas básicas:
tan=cateto opuesto/cateto convergente
seno=cateto opuesto/hipotenusa
coseno=cateto convergente/hipotenusa
Todas las de arriba son estas despejadas y son las que uso en el curro. Con solo estas tres formulitas resuelves cualquier triángulo rectángulo (siempre y cuando tengas siempre dos elementos, grados o catetos)
:wink: |
Oye, macho... que es que hoy estoy espesito, y no me entero
Quiero añadir esto al tutorial, pero...
Si yo conozco el cateto convergente y el cateto opuesto... ¿Cómo obtengo la hipotenusa?
Es decir, si el cateto "Vertical" es Y2 - Y1 (coordenadas Y de los dos puntos), y el "Horizontal" es X2 - X1 (idem de ídem)... ¿Cómo coño saco la hipotenusa si no es por pitágoras?
Es que, de verdad, se ve que hoy estoy tontorroncete y no me entero de ná  |
|
 |
|
 |
Alx Boss

 Registrado: 22 Mar 2006 Mensajes: 6926 Ubicación: Barcelona
        votos: 26 Sexo:
|
Publicado: Lun Sep 18, 2006 13:24 pm Asunto: |
|
|
Pues aquí me pillas un poco porque no es que no se pueda, lo que pasa es que una fórmula directa no la conozco y a lo mejor aquí si tú con pítagoras lo haces en un solo paso, usa esta. Si lo quieres como yo lo hago sería:
Si divides los dos catetos (C.opuesto/C.convergente) obtienes la Tangente.
Si haces el INVERSO de la Tangente te da el ángulo del triángulo rectángulo.
Y entonces con el ángulo ya resolverías la hipotenusa con cualquiera de los dos catetos:
Con el C.Opuesto sería:
Hipotenusa=C.opuesto/Seno de los grados del triángulo
Con el C.Convergente sería:
Hipotenusa=C.convergente/Coseno de los grados del triángulo.
---
Claro, es que como yo esto lo uso en el curro lo hago así y nunca me había pasado que programando un juego tuviese que sacar el cálculo que dices.
También me pillas ahora espeso que acabo de plegar y a lo mejor luego se me enciende la bombilla  _________________
 |
|
 |
|
 |
|