FizzX: Librería de colisiones para Love2D

18 May 2020

Hits
Love2D tiene un motor de físicas, en realidad es un port de la librería Box2D. A mi parecer es un como complicado de aplicar y en ocasiones cuando quiero hacer algo mas sencillo ni siquiera lo ocupo, en cambio uso una función simple para detectar colisiones:
local function checkCollision (a, b)
local dx = math.abs(a.x - b.x) -- x distance
local dy = math.abs(a.y - b.y) -- y distance
local mx = a.halfwidth + b.halfwidth -- minimum x distance
local my = a.halfheight + b.halfheight -- minimum y distance

return dx < mx and dy < my
end
Pero en ocasiones puede suceder que necesito una física mínima, no solo saber si dos cajas colisionan y toca implementar la física porteada de Box2D que viene en Love2D.

Por suerte, en la web se pueden encontrar muchas librerías de físicas además de la que viene con Love2D, algunas mas complejas y otras mas específicas, y en esta ocasión quiero exponer un poco sobre FizzX.

FizzX es una librería ligera de física al muy estilo de la vieja escuela, esto significa que tenemos lo básico para simular la física de un plataformero clásico.

Lo primero que debemos hacer es descargar la librería y colocarla en el proyecto, la importamos de esta manera en el main.lua:
local fizz = require("fizzx.fizz")
Fizz tiene 3 formas (shape) disponibles, rectangulo ("rect"), circulo ("circ") y línea ("line"), no acepta polígonos ni soporta rotaciones.

Al mismo tiempo soporta 3 tipos de cuerpos, static (cuerpo inamovible), kinematic (cuerpo que no colisiona), dynamic (cuerpo que si colisiona).

Por ejemplo:
local shape = fizz.addDynamic("rect", 50, 50, 20, 20) --forma, x, y, mitad ancho, mitad alto
local shape2 = fizz.addStatic("rect", 200, 200, 30, 100)
Luego para eliminar una forma de colisión solo hace falta poner fizz.removeShape(shape).

Cada forma tiene un callback para las colisiones, es decir, si añadimos la función onCollide() del shape esta será llamada cuando colisione:
function shape.onCollide(a,b,nx,ny,pen) -- self, shape, dirX, dirY,
print(a,b,nx,ny,pen)
end
a es el shape en sí mismo, b es el shape con el que colisionó, nx y ny es la dirección de la colisión, puede ser 0 o 1, es decir, si nx == 0 y ny == 1 entonces la colisión viene desde abajo.

A continuación un ejemplo que puedes probar con 2 shapes:
local fizz = require("fizzx.fizz")

local shape = fizz.addDynamic("rect", 50, 50, 20, 20)
local shape2 = fizz.addStatic("rect", 200, 200, 30, 100)

function shape.onCollide(a,b,nx,ny,pen) -- self, shape, dirX, dirY,
print(a,b,nx,ny,pen)
end

function love.update(dt)
fizz.update(dt)
if love.keyboard.isDown("right") then
shape.xv = 100
elseif love.keyboard.isDown("left") then
shape.xv = -100
else
shape.xv = 0
end
if love.keyboard.isDown("up") then
shape.yv = -100
elseif love.keyboard.isDown("down") then
shape.yv = 100
else
shape.yv = 0
end
end

function love.draw()
love.graphics.rectangle("fill", shape.x - shape.hw, shape.y - shape.hh, shape.hw*2, shape.hh*2)
love.graphics.rectangle("fill", shape2.x - shape2.hw, shape2.y - shape2.hh, shape2.hw*2, shape2.hh*2)
end
Fizz requiere que actualices en cada frame, por eso necesitas poner fizz.update(dt).

shape.xv y shape.xy son las variables de velocity, shape.x, shape.y son las variables de posición, shape.hw, shape.hh son las variables del tamaño del shape, sin embargo estas son las mitades, ya que las formas se dibujan desde el centro, es decir, hw significa half-width y hh half-height.

Personalmente me gusta esta librería ya que es muy sencilla aunque con muchas limitaciones, sirve para proyectos sencillos, si quieres saber mas de esta librería revisa el proyecto aquí.