miércoles, 9 de marzo de 2016

Lo que sé sobre: Como detectar colisiones en Love2d ( Rectángulo VS rectángulo y rectángulo de intersección)




¿Acaso no sabes como hacer que el héroe de tu juego sea capaz de golpear a ese maldito enemigo?

¿Como demonios hago para que mi ratón pulse es bonito botón?


Pues poco a poco voy a explicar lo que yo descubrí sobre como detectar varios tipos de colisiones.

Pues en esta entrada paso a explicar tres nuevas funciones a incluir en nuestro archivo ControlDeColisiones.lua. Esta vez las funciones nos valdrán para detectar colisiones entre rectángulos y si es así generar el rectángulo de intersección que se crea mediante la colisión.


Las funciones a crear serán:

  • crear_rectangulo(xr,yr,wr,hr): Recibe la estructura de un rectángulo y la retorna convertida en una tabla donde; x,y serán las coordenadas del rectángulo y w,h, serán el ancho y el alto
  • colision_entre_rectangulos(rA,rB): Recibe la estructura de dos rectángulos y retorna true si estos están en colisión.
  • rectangulo_interseccion(rA,rB):Recibe la estructura de dos rectángulos y retorna el rectángulo de intersección que se genera entre ambos

La primera función que vamos a incluir en el archivo ControlDeColisiones.lua, será la función que usaremos para generar la estructura de los rectángulos


--[[Esta función retorna la estructura de un rectángulo contenidos en una tabla.

Los datos contenidos en la tabla retornada seran

x=posición horizontal

y=posición vertical

w=ancho del rectángulo

h=como alto del rectángulo]]--

function ControlDeColisiones.crear_rectangulo(xr,yr,wr,hr)

     rect={x=xr,y=yr,w=wr,h=hr}

    return rect

end

La siguiente función a crear será colision_entre_rectangulos(rA,rB) y como dijimos se le pasa como argumentos la estructura de dos rectángulos creados por la anterior función.



--[[Recibe la estructura de dos rectángulos y retorna true si estos dos se están tocando]]--

function ControlDeColisiones.colision_entre_rectangulos(rA,rB)


     --[[Comprobamos si la posición orizontal de rA es menor que la suma de la posición horizontal  
     de rB más su ancho y

    si la posición horizontal de rB es menor que la posición horizontal de rA más su ancho. Si es así
     ignifica que los dos rectángulos

    se chocan en horizontal]]--

    if (rA.x<rB.x+rB.w and rB.x<rA.x+rA.w) then

        --[[Comprobamos si la posición vertical de rA es menor que la posición vertical de rB más su alto
           y si la posición vertical de rB

         es menor que la posición vertical de rA más su alto.

         Si esta comprobación retorna true significa que los rectángulos chocan en vertical]]--

        if (rA.y<rB.y+rB.h and rB.y<rA.y+rA.h) then

            --[[Si las dos comprobaciones son correctas la función retornará true]]--

            return true

        end

   end

   return false

end

uY por último implementamos la función encargada de generar el rectángulo de intersección rectangulo_interseccion(rA,rB)

--[[Retorna el rectangulo de intersección generado por la colisión entre dos rectángulos]]--

function ControlDeColisiones:rectangulo_interseccion(rA,rB)

     --Usamos la función max de la biblioteca math para saber cual de las dos coordenadas x de los rectángulos es mayor

     --Guardamos el resultado en una nueva variable nX

     nX=math.max(rA.x,rB.x)

     --Usamos la función max de la biblioteca math para saber cual de las dos coordenadas y de los rectángulos es mayor

     --Guardamos el resultado en una nueva variable nY

     nY=math.max(rA.y,rB.y)

     --[[Sumamos el ancho de rA + su coordenada x y sumamos el ancho de rB mas su coordenada x,

     Usamos la función min de la biblioteca math para adivinar el menor de los dos resultados 
      anteriores y le restamos nX

     y guardamos el valor en una nueva variable]]--

     nW=math.min(rA.x+rA.w,rB.x+rB.w)-nX

     --[[Sumamos el alto de rA mas su coordenada y y sumamos el alto de rB más su coordenada y,

     Usamos la función min de la biblioteca math y adivinamos el menor de los anteriores 
      resultados, al resultado le restamos nY

     y guardamos el valor en una nueva variable]]--

     nH=math.min(rA.y+rA.h,rB.y+rB.h)-nY


     --Usamos las nuevas variables para generar un nuevo rectángulo con la funcion 
     crear_rectangulo y lo retornamos

    nR=self.crear_rectangulo(nX,nY,nW,nH)

    return nR

end

Con esto nuestro archivo ControlDeColisiones.lua estará listo para detectar colisiones entre rectángulos. Para comprobarlo escribiremos el siguiente ejemplo. Dibujaremos dos rectángulos en pantalla y a uno de ello le haremos que se mueva junto con el cursor del ratón. Si los dos rectángulos colisionan avisaremos con un mensaje y dibujaremos el rectángulo de intersección generado por la colisión.

Para generar la estructura del ejemplo haremos lo mismo que en los anteriores post.

En la función love.load de nuestro archivo main.lua incluimos el archivo ControlDeColisiones.lua, creamos la estructura de dos rectángulos, el mensaje de control y la variable que contendrá el rectángulo de intersección si los dos primeros están en contacto.

function love.load()

     --Incluimos nuestro controlador de colisiones

     controlChoques=require("ControlDeColisiones")


     rA=controlChoques.crear_rectangulo(100,100,40,40)

     rB=controlChoques.crear_rectangulo(300,300,40,40)


     texto="no están en colisión"

     rInterseccion=nil

end

En love.update(dt) actualizamos el movimiento del primer rectángulo, comprobamos si existe colisión y generamos el rectángulo de intersección.

function love.update(dt)

     --Recogemos las posiciones del cursor

     mX=love.mouse.getX()

     mY=love.mouse.getY()


     --Asignamos las posiciones del cursor al rectángulo a para que se desplace con el movimiento del cursor

     rA.x=mX

     rA.y=mY



     --Llamamos a la función para comprobar la colisión

     if (controlChoques.colision_entre_rectangulos(rA,rB)) then

         texto="Están en colisión"

         --[[Si los rectángulos se tocan generamos el rectangulo de interseccion]]--

         rInterseccion=controlChoques:rectangulo_interseccion(rA,rB)

     else

         rInterseccion=nil

         texto="no están en colisión"

     end

end

Dibujamos el resultado en pantalla


function love.draw()

     --dibujamos los rectángulos

     love.graphics.rectangle("fill", rA.x,rA.y,rA.w,rA.h)

     love.graphics.rectangle("fill", rB.x,rB.y,rB.w,rB.h)

     --dibujamos el texto de control en pantalla

     love.graphics.print(texto,10,10)

     --Etiqueta para indicar donde mostramos el rectángulo de intersección

     love.graphics.print("Intersección:",10,40)

     --Si los rectángulos se tocan dibujamos el rectángulo de intersección.

     --Lo hacemos usando el operador ~= que significa distinto de.

     --Quiere decir: si rIntersección es distinto del valor nil

     if (rInterseccion~=nil) then

         --Dibjamos el rectangulo en 10 y 70 porque de usar las posiciones propias de la tabla rIntersección

         --el rectángulo se dibujaría sobre los otros dos.

         love.graphics.rectangle("fill", 10,70,rInterseccion.w,rInterseccion.h)

     end

end

El resultado de todo esto en pantalla sería el siguiente


Y hasta aquí todo lo que sé, sobre como detectar colisiones entre rectángulos.

No hay comentarios:

Publicar un comentario