Autor Tema: Colisiones sprite<>sprite por software  (Leído 967 veces)

Laddh

  • Desarrolladores
  • Commodore Master
  • ******
  • Mensajes: 216
    • Ver Perfil
Colisiones sprite<>sprite por software
« en: Abril 30, 2018, 14:02:23 »
Buenas gente, había leído sobre este asunto en los foros y hasta ahora no le había dado importancia porque no me he encontrado con este problema, pero en lo que estoy trabando ahora las colisiones por hard no funcionaban de manera precisa, la rutina que funcionaba hasta ahora, aquí se comía la mitad de las colisiones de una manera inaceptable. Dando un vistazo por Codebase64 empiezo a encontrar muchos apuntes a las colisiones por soft para solventarlo, comentando para mi sorpresa que cuando hay que controlar muchas cosas a la vez en pantalla, el registro de colisiones ya no es el adecuado para controlarlo.
Aquí aparece la idea de colisiones por soft, se trata de determinar las cuatro esquinas que conforman el sprite y comprobar si las coordenadas del interior de este rectángulo coincide con las coordenadas de otro sprite determinado del mismo modo.
Como me ha costado unos cuantos días pelearme con esto, aquí os paso mi primera aproximación a la solución del problema, creo que cualquiera que desarrolle se encontrará con esto en algún momento.

Saludos!

Código: [Seleccionar]
; 10 SYS (2064)

v=$d000 ;inicio registros sprite

*=$0801

        BYTE    $0E, $08, $0A, $00, $9E, $20, $28,  $32, $30, $36, $34, $29, $00, $00, $00

*=$0810

        jsr sprite
l       jsr raster_wait
        jsr JOY
        jmp l

sprite  lda #3  ;pon 2 sprites en pantalla
        sta v+21
        lda #0
        sta v+39
        lda #3
        sta v+40
        lda #192
        sta 2040
        lda #193
        sta 2041
        lda #100
        sta v
        lda #190
        sta v+2
        lda #147
        sta v+1
        sta v+3
        rts

raster_wait             ;espera línea raster
l1      LDA #$EA
        CMP $D012
        BNE l1
        BIT $d011
        BMI l1
        rts

JOY     LDA $DC00   ;LEEMOS JOY
        AND #31     ;LA CUATRO DIRECCIONES ARRIBA ABAJO IZQ DER   
        CMP #30     
        BEQ ARR
        CMP #29
        BEQ ABJ
        CMP #27
        BEQ IZQ
        CMP #23
        BEQ DER
        rts

arr     dec $d001
        jsr coordenadas
        jsr comprueba_col           
        rts
abj     inc $d001   
        jsr coordenadas
        jsr comprueba_col           
        rts
izq     dec $d000
        jsr coordenadas
        jsr comprueba_col           
        rts
der     inc $d000
        jsr coordenadas
        jsr comprueba_col           
        rts

coordenadas             ;actualiza coordenadas de los 2 sprites
        lda v           ;y crea 4 variables con las 4 esquinas
        sta s1x1        ;de los sprites
        clc             ;s1x1 sprite 1 x1
        adc #23         ;s1x2 sprite 1 x2
        sta s1x2        ;etc....
        lda v+1
        sta s1y1
        clc
        adc #20
        sta s1y2

        lda v+2
        sta s2x1
        clc
        adc #23
        sta s2x2
        lda v+3
        sta s2y1
        clc
        adc #20
        sta s2y2
        rts             
s1x1    byte 0         
s1x2    byte 0
s1y1    byte 0
s1y2    byte 0
s2x1    byte 0
s2x2    byte 0
s2y1    byte 0
s2y2    byte 0

comprueba_col           ;comprueba colisión en base a las coordenadas
        lda s1x2        ;si se cumplen incrementa color borde
        cmp s2x1
        bcs comprueba_col1
        rts
comprueba_col1
        lda s1x1
        cmp s2x2
        bcc comprueba_col2
        rts
comprueba_col2
        lda s1y2
        cmp s2y1
        bcs comprueba_col3
        rts
comprueba_col3
        lda s1y1
        cmp s2y2
        bcc hit
        rts
hit     inc $d020
        rts

*=12288
incbin"prueba.bin"
 

Maniako

Re:Colisiones sprite<>sprite por software
« Respuesta #1 en: Mayo 02, 2018, 09:38:41 »
Qué curioso, ayer me estuve comiendo el tema de colisiones con sprites.

Una de las características que tiene es que cada vez que haces una lectura en la dirección de las colisiones, estas se resetean y por eso, si haces dos lecturas seguidas, la segunda da 0.
Lo que hice fué guardar el valor de la primera lectura en una "variable" y entonces trabajar con ella.
Como uso interrupciones para temas de movimiento, he usado las mismas interrupciones para que me detecte barrido o sprites dependiendo del código que se esté ejecutando.
Cuando entro en la rutina "activada" por raster ,donde muevo y muestro los sprites (varias veces del tirón por tema de velocidad/dificultad del nivel del juego usando un bucle), conmuto entonces a interrupciones por colision sprite/sprite y desvio a otro bloque si hay colision.
Una vez salgo de la rutina del raster, desactivo las interrupciones de sprites y activo la de raster ya que no va a moverse nada hasta que entre de nuevo.

Lo de coordenadas está bién por que puedes hacer que los sprites puedan "rozarse" sin que te maten XD, pero te obliga a usar sprites casi cuadrados.

Como en mi caso estaba usando un sprite arqueado, este método detectaria colisión sin tocarse en los extremos y se veria raro.

En teoria deberia poder hacerse con dos comprobaciones, como pintar un cubo en pantalla. Coordenadas orígen y coordenadas destino. Ahora me vas a tener pensando en ello todo el día... maldición  ;D
LDA #$50
STA $0400
RTS
Lloré cuando conseguí hacer esto con el monitor del FC1.
 

Maniako

Re:Colisiones sprite<>sprite por software
« Respuesta #2 en: Mayo 02, 2018, 10:00:42 »
Creo que seria algo así:
X=coordenada X de un sprite y el numero=sprites a comparar.
Se debe tener en cuenta el ancho y alto del sprite, en el caso de mi ejemplo, 8x8 pixéls.
8/2=4. Así que la resta que entregue valores de -4 al +4 indica colisión.
 
---------------------
X1=100 X2=98
Y1=100 Y2=100

X1-X2=xxx 100-98=+2 que indica colisión por eje X
Y1-Y2=xxx 100-100=0 Idem por eje Y
---------------------

X1=100 Y1=100
X2=104 Y2=106

X1-X2=xxx 100-104=-4 que indica colisión por eje X
Y1-Y2=xxx 100-104=-6 No hay colision por eje Y.
------------------------

Si usas un sprite de 8x16, 8/2 =-4 a +4 para ejes X y 16/2=-8 a +8 para ejes Y.

Cuando hay colision en ambos ejes, matas o explotas el sprite XD.
Si uno de llos falla, no pasa nada.

No la he probado, pero creo que es así. Prueba a ver si te funciona.
LDA #$50
STA $0400
RTS
Lloré cuando conseguí hacer esto con el monitor del FC1.
 

Laddh

  • Desarrolladores
  • Commodore Master
  • ******
  • Mensajes: 216
    • Ver Perfil
Re:Colisiones sprite<>sprite por software
« Respuesta #3 en: Mayo 02, 2018, 10:16:09 »
He hecho muchas pruebas desde que me encontré con el problema, y el bueno del registro de colisiones no daba la fiabilidad necesaria, tanto si lo miras desde la interrupción, como si lo miras inmediatamente después de cada movimiento o las dos a la vez, y en cambio la rutina por soft se muestra fiable 100*100.
Sí, obliga a que sean cuadrados pero si lo miras prácticamente todos los sprites lo son, se puede jugar con las coordenadas para que solo colisione con las centrales si el sprite tiene una forma rara.
En el ejemplo que adjunte controla los 24*21 de cada sprite como habrás visto pero es ajustable fácilmente.
Creo que a partir de ahora me decanto más por este sistema.
 

Maniako

Re:Colisiones sprite<>sprite por software
« Respuesta #4 en: Mayo 02, 2018, 10:47:55 »
Te comprendo perfectamente.
Si solo chocan 2 sprites, no hay problema, pero con 3 ya es cuando hay que usar las coordenadas o te volverás loco.
Probe a desconectar los sprites no deseados y volver a comprobar colisiones y otras ideas que se me pasaron por la cabeza. Nada funcionó como me hubiera gustado.

Como estoy con un juego tipo Arkanoid, tocar el PAD con forma curvada es esencial, así que opté por evitar que otros sprites se tocasen entre ellos y a correr. Así no me ha fallado de momento, seguro que cuando lo ponga a prueba más a fondo la bola se enganchará en el pad cambiando de sentido sin fín o atravesará el pad... cruzare ese rio cuando llegue XD
LDA #$50
STA $0400
RTS
Lloré cuando conseguí hacer esto con el monitor del FC1.
 

Dashiad

Re:Colisiones sprite<>sprite por software
« Respuesta #5 en: Mayo 04, 2018, 18:38:12 »
Laddh, cuando dices que la interrupcion es imprecisa, es porque no detecta colisiones que han ocurrido, o por el problema de detectar qué sprites son los que han colisionado (cuando son más de dos)?
 

Laddh

  • Desarrolladores
  • Commodore Master
  • ******
  • Mensajes: 216
    • Ver Perfil
Re:Colisiones sprite<>sprite por software
« Respuesta #6 en: Mayo 04, 2018, 18:54:03 »
Hola Dashiad, sí, me refiero a que no detecta todas las colisiones, se saltaba muchas. La verdad es que no hay color, ahora que voy evolucionando la rutina por soft, es impecable.
 

josepzin

Re:Colisiones sprite<>sprite por software
« Respuesta #7 en: Mayo 04, 2018, 21:25:29 »
Me parece raro que tenga problemas para detectar las colisiones pero bueno, tampoco soy un experto en el tema.

Dashiad

Re:Colisiones sprite<>sprite por software
« Respuesta #8 en: Mayo 04, 2018, 21:34:42 »
Precisamente por eso lo preguntaba...he estado buscando un poco sobre que las interrupciones no sean precisas, y no he encontrado referencias...Hay alguna que sepas, Laddh?
 

Scooter

Re:Colisiones sprite&lt;&gt;sprite por software
« Respuesta #9 en: Mayo 05, 2018, 08:18:11 »
Uff, recuerdo haber leído artículos en Commodore World al respecto.
Creo que tiene que ver con el raster, que solo detecta las interrupciones cuando pasa o algo así.
Si los sprites van lentos seguro que pasa pero si el movimiento es rápido no, eso o que detecta en el segundo paso del raster despues de mover el sprite, algo había que lo hacía casi inútil en juegos rápidos.
Creo recordar que ya entonces abogaban por una rutina software.

La ventaja es que la interrupción hardware si que aplica la forma del Sprite mientras que una software sencilla es aplicar formas de caja. Hacer el análisis de si dos formas complejas se tocan o no es trabajoso.

Tiene sentido si pensamos como debe de funcionar, habrá un contador que va pasando por cada bit del bitmap o de la ROM de caracteres y pintando píxeles en la pantalla, mas o menos eso es el raster. Al mismo tiempo comprueba si en esa posición hay un sprite activado y entonces pinta el pixel del sprite en lugar del bitmap o caracer, pero si hay varios entonces pinta el de mayor prioridad y activa la interrupción. Algo pasa que la interrupción no se activa en ese momento, lo mismo se activa al terminar el cuadro para que no bombardee a interrupciones si al lado hay otros dos sprites colisionando. Si cuando termina el cuadro los sprites se han movido y se genera la interrupción y cuando vas al registro a ver cuáles están chicando, como ya no chocan no lo ves. Eso o que directamente no salta la interrupción si al acabar el cuadro los sprites ya no colisionan.

Me suena que la solución era poner una interrupción del raster Al final de la pantalla y solo mover sprites después de haber pintado toda la pantalla y haber atendido a todas las posibles colisiones. Eso además evita posibles parpadeos si da la casualidad de que mueves un sprite a mitad de pintarlo.
Eso también implica que si usas el raster para mostrar mas de ocho sprites a la vez en pantalla o sprites en los bordes ya no puedes usar las colisiones por hardware, o en todo caso solo podrás usar las de la última sección de la pantalla.

Espero no ser del todo inexacto y no haber 'desinformado' porque hace treinta y cinco años desde que leí el artículo y nunca lo apliqué.
« última modificación: Mayo 05, 2018, 08:28:24 por Scooter »
 

Dashiad

Re:Colisiones sprite<>sprite por software
« Respuesta #10 en: Mayo 05, 2018, 12:56:21 »
Mm..yo lo que si que he leido, y a la vez, es logico, es que si un sprite (ej, una bala) se mueve a x pixeles por frame, y el enemigo se mueve a y pixeles por frame, en direccion contraria, si la bala pasa por una zona del enemigo que sea menos ancha de x+y pixeles, no va a haber colision...porque efectivamente, nunca la ha habido.
Como bien dices, la colision se detecta en tiempo de raster, por lo que o en un frame realmente se dibuja un sprite encima de otro, o no ha habido colision.
Pero si este es el problema, pasar a bounding boxes es una solucion parcial...el bounding box en ese caso es una forma aproximada de calcular un area de efecto.
Y si, por ganar precision, se reduce el bounding box para que coincida con la forma del sprite, el problema vuelve a ser el mismo...si los objetos se mueven demasiado rapido, se cruzan en vez de colisionar..Si es asi, la solucion seria basada en interpolar o aproximar las trayectorias.
 

Laddh

  • Desarrolladores
  • Commodore Master
  • ******
  • Mensajes: 216
    • Ver Perfil
Re:Colisiones sprite<>sprite por software
« Respuesta #11 en: Mayo 05, 2018, 12:57:39 »
Dashiad, el problema que yo me he encontrado no es que tenga que ver con la interrupción IRQ porque lo aplique sin interrupciones para probar, verificando el registro de colisiones a cada movimiento X,Y de los sprites y el resultado era el mismo, se comía muchas colisiones sin detectarlo, el contexto es los 8 sprites a la vez, naves, lasers, misiles..., como expliqué anteriormente me sorprendí porque esa misma rutina de colisiones había funcionado bien en proyectos anteriores.
Tal vez tenga que ver con lo que explica Scooter, el caso es que en búsquedas profundas por internet de este tema acabas leyendo comentarios de coders que efectivamente abogan por el método soft si quieres ser fiable al 100x100, despreciando el metodo hard por registro.
Mi moraleja por ahora es, primero prueba por registro de colisiones, es fácil de programar y si funciona adelante, que no, pues sistema soft, una vez lo entiendes tambien es fácil.
 

Dashiad

Re:Colisiones sprite<>sprite por software
« Respuesta #12 en: Mayo 05, 2018, 13:40:22 »
El registro de colisiones no lo puedes comprobar tras cada movimiento.Lo dispara el raster.El que cambies la posicion de un sprite no te genera una interrupcion.En el momento en el que el VIC intenta pintar los pixeles solapados por la colision, es cuando se genera.
 

Laddh

  • Desarrolladores
  • Commodore Master
  • ******
  • Mensajes: 216
    • Ver Perfil
Re:Colisiones sprite<>sprite por software
« Respuesta #13 en: Mayo 05, 2018, 14:16:31 »
Sí, ya, ya, no espero una colisión por comprobarlo pero manejo una nave, no se cuando va ha haber una colisión, y como podrás imaginar sincronizo cualquier movimiento en pantalla por raster.
Por cierto, un placer mantener una conversación técnica sobre commodore, da gusto comprobar que más gente entiende mi idioma. Una vez que el asm te atrapa ya no hay escape... ;)
 

Scooter

Re:Colisiones sprite&lt;&gt;sprite por software
« Respuesta #14 en: Mayo 05, 2018, 14:55:24 »
Si mueves tres veces un Sprite entre raster y raster es un esfuerzo inútil porque solo se verá el último.
¿En serio se dispara la colisión en el mismo punto de la colisión o al terminar el cuadro?
Lo digo porque puedes tener dos sprites colisionando y un pixeles más allá otra colisión lo que llevaría a dos interrupcciones demasiado juntas en el tiempo.
Algo pasaba que efectivamente se perdían colisiones.
Me suena que la solución era mover los sprites solo en el tiempo del margen; poner una interrupción del raster en la línea 200 o 200 y poco de la pantalla, nada más terminar y entonces mover lo que sea.
Claro que eso llevaría a que si se refresca 50 veces por segundo limitas mucho la velocidad ya que en recorrer los 200 en vertical o los 320 en horizontal, tardas más de un segundo. Si saltas de 5 en 5 pixeles y la bala tiene 4 pixeles... Te lo puedes saltar. (Bueno, en realidad la suma de los anchos de los sprites...)
Pero claro, es que es tontería pintar más de un movimiento por barrido porque no se va a ver. Dependerá entonces de si es más fácil discriminar para solo pintar uno por barrido o pintar todos igual sin pensar, pero en ambos casos no funcionaría la colisión hardware.
Quizás una técnica mixta funcione bien. No sé.