626 lines
16 KiB
Lua
626 lines
16 KiB
Lua
local particles = {}
|
|
local precision = 1
|
|
|
|
-- base particle class
|
|
class("Particle").extends()
|
|
function Particle:init(x, y)
|
|
self.x = x or 0
|
|
self.y = y or 0
|
|
self.size = {1,1}
|
|
self.spread = {0,359}
|
|
self.speed = {1,1}
|
|
self.acceleration = {0, 0}
|
|
self.thickness = {0,0}
|
|
self.lifespan = {1,1}
|
|
self.decay = 1
|
|
self.particles = {}
|
|
self.colour = playdate.graphics.kColorBlack
|
|
self.bounds = {0,0,0,0}
|
|
self.mode = 0
|
|
if self.type == 2 then -- polys
|
|
self.points={3,3}
|
|
self.angular={0,0}
|
|
self.rotation={0,359}
|
|
elseif self.type == 3 then -- images
|
|
self.angular={0,0}
|
|
self.image = playdate.graphics.image.new(1,1)
|
|
self.table = nil
|
|
self.rotation = {0,359}
|
|
end
|
|
|
|
particles[#particles+1] = self
|
|
|
|
end
|
|
|
|
function Particle:remove()
|
|
for i = 1, #particles, 1 do
|
|
if particles[i] == self then
|
|
table.remove(particles, i)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
-- [[ SETTERS AND GETTERS ]] --
|
|
|
|
-- movement
|
|
function Particle:moveTo(x,y)
|
|
self.x = x
|
|
self.y = y
|
|
end
|
|
|
|
function Particle:moveBy(x,y)
|
|
self.x += x
|
|
self.y += y
|
|
end
|
|
|
|
function Particle:getPos()
|
|
return self.x, self.y
|
|
end
|
|
|
|
-- size
|
|
function Particle:setSize(min, max)
|
|
self.size = {min, max or min}
|
|
end
|
|
|
|
function Particle:getSize()
|
|
return self.size[1], self.size[2]
|
|
end
|
|
|
|
-- mode
|
|
function Particle:setMode(mode)
|
|
self.mode = mode
|
|
end
|
|
|
|
function Particle:getMode()
|
|
return self.mode
|
|
end
|
|
|
|
-- spread
|
|
function Particle:setSpread(min,max)
|
|
self.spread = {min, max or min}
|
|
end
|
|
|
|
function Particle:getSpread()
|
|
return self.spread[1], self.spread[2]
|
|
end
|
|
|
|
-- speed
|
|
function Particle:setSpeed(min,max)
|
|
self.speed = {min, max or min}
|
|
end
|
|
|
|
function Particle:getSpeed()
|
|
return self.speed[1], self.speed[2]
|
|
end
|
|
|
|
-- acceleration
|
|
function Particle:setAcceleration(min,max)
|
|
self.acceleration = {min, max or min}
|
|
end
|
|
|
|
function Particle:getAcceleration()
|
|
return self.acceleration[1], self.acceleration[2]
|
|
end
|
|
|
|
-- thickness
|
|
function Particle:setThickness(min, max)
|
|
self.thickness = {min, max or min}
|
|
end
|
|
|
|
function Particle:getThickness()
|
|
return self.thickness[1], self.thickness[2]
|
|
end
|
|
|
|
-- lifespan
|
|
function Particle:setLifespan(min,max)
|
|
self.lifespan = {min, max or min}
|
|
end
|
|
|
|
function Particle:getLifespan()
|
|
return self.lifespan[1], self.lifespan[2]
|
|
end
|
|
|
|
-- colour
|
|
function Particle:setColor(colour)
|
|
self.colour = colour
|
|
end
|
|
|
|
function Particle:getColor()
|
|
return self.colour
|
|
end
|
|
|
|
function Particle:setColour(colour)
|
|
self.colour = colour
|
|
end
|
|
|
|
function Particle:getColour()
|
|
return self.colour
|
|
end
|
|
|
|
-- bounds
|
|
function Particle:setBounds(x1, y1, x2, y2)
|
|
self.bounds = {x1,y1,x2,y2}
|
|
end
|
|
|
|
function Particle:getBounds()
|
|
return self.bounds[1],self.bounds[2],self.bounds[3],self.bounds[4]
|
|
end
|
|
|
|
-- decay
|
|
function Particle:setDecay(decay)
|
|
self.decay = decay
|
|
end
|
|
|
|
function Particle:getDecay()
|
|
return self.decay
|
|
end
|
|
|
|
-- particles
|
|
function Particle:getParticles()
|
|
return self.particles
|
|
end
|
|
|
|
function Particle:clearParticles()
|
|
self.particles = {}
|
|
end
|
|
|
|
function Particle:update()
|
|
end
|
|
|
|
-- [[ PARTICLE MODES ]] --
|
|
|
|
local function decay(partlist, decay)
|
|
for part = 1, #partlist, 1 do
|
|
local particle = partlist[part]
|
|
particle.size -= decay
|
|
|
|
if particle.size <= 0 then
|
|
particle.size = 0
|
|
end
|
|
|
|
partlist[part] = particle
|
|
end
|
|
|
|
for part = #partlist, 1, -1 do
|
|
local particle = partlist[part]
|
|
if particle.size <= 0 then
|
|
table.remove(partlist,part)
|
|
end
|
|
end
|
|
|
|
return partlist
|
|
end
|
|
|
|
local function disappear(partlist)
|
|
for part = 1, #partlist, 1 do
|
|
local particle = partlist[part]
|
|
particle.lifespan -= .1
|
|
end
|
|
for part = #partlist, 1, -1 do
|
|
local particle = partlist[part]
|
|
if particle.lifespan <= 0 then
|
|
table.remove(partlist,part)
|
|
end
|
|
end
|
|
|
|
return partlist
|
|
end
|
|
|
|
local function loop(partlist, bounds)
|
|
if bounds[3] > bounds[1] and bounds[4] > bounds[2] then
|
|
local xDif , yDif = bounds[3] - bounds[1], bounds[4] - bounds[2]
|
|
for part = 1, #partlist, 1 do
|
|
local particle = partlist[part]
|
|
if particle.x > bounds[3] then particle.x -= xDif
|
|
elseif particle.x < bounds[1] then particle.x += xDif end
|
|
if particle.y > bounds[4] then particle.y -= yDif
|
|
elseif particle.y < bounds[2] then particle.y += yDif end
|
|
end
|
|
end
|
|
|
|
return partlist
|
|
end
|
|
|
|
local function stay(partlist, bounds)
|
|
if bounds[3] > bounds[1] and bounds[4] > bounds[2] then
|
|
local xDif , yDif = bounds[3] - bounds[1], bounds[4] - bounds[2]
|
|
for part = #partlist, 1, -1 do
|
|
local particle = partlist[part]
|
|
if particle.x > bounds[3] then table.remove(partlist,part)
|
|
elseif particle.x < bounds[1] then table.remove(partlist,part)
|
|
elseif particle.y > bounds[4] then table.remove(partlist,part)
|
|
elseif particle.y < bounds[2] then table.remove(partlist,part) end
|
|
end
|
|
end
|
|
|
|
return partlist
|
|
end
|
|
|
|
class("ParticleCircle", {type = 1}).extends(Particle)
|
|
|
|
function ParticleCircle:create(amount)
|
|
for i = 1, amount, 1 do
|
|
local part = {
|
|
x = self.x,
|
|
y = self.y,
|
|
dir = math.random(self.spread[1],self.spread[2]),
|
|
size = math.random(self.size[1],self.size[2]) * precision,
|
|
speed = math.random(self.speed[1],self.speed[2]) * precision,
|
|
acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision,
|
|
lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision,
|
|
thickness = math.random(self.thickness[1],self.thickness[2]),
|
|
decay = self.decay
|
|
}
|
|
|
|
self.particles[#self.particles+1] = part
|
|
end
|
|
end
|
|
|
|
function ParticleCircle:add(amount)
|
|
self:create(amount)
|
|
end
|
|
|
|
function ParticleCircle:update()
|
|
local w = playdate.graphics.getLineWidth()
|
|
local c = playdate.graphics.getColor()
|
|
playdate.graphics.setColor(self.colour)
|
|
for part = 1, #self.particles, 1 do
|
|
local circ = self.particles[part]
|
|
if circ.thickness < 1 then
|
|
playdate.graphics.fillCircleAtPoint(circ.x,circ.y,circ.size)
|
|
else
|
|
playdate.graphics.setLineWidth(circ.thickness)
|
|
playdate.graphics.drawCircleAtPoint(circ.x, circ.y, circ.size)
|
|
end
|
|
|
|
circ.x += math.sin(math.rad(circ.dir)) * circ.speed
|
|
circ.y -= math.cos(math.rad(circ.dir)) * circ.speed
|
|
|
|
circ.speed += circ.acceleration / 100
|
|
|
|
self.particles[part] = circ
|
|
end
|
|
playdate.graphics.setLineWidth(w)
|
|
playdate.graphics.setColor(c)
|
|
if self.mode == 1 then
|
|
decay(self.particles, self.decay)
|
|
|
|
elseif self.mode == 0 then
|
|
disappear(self.particles)
|
|
|
|
elseif self.mode == 2 then
|
|
loop(self.particles, self.bounds)
|
|
|
|
else
|
|
stay(self.particles, self.bounds)
|
|
|
|
end
|
|
end
|
|
|
|
class("ParticlePoly", {type = 2}).extends(Particle)
|
|
|
|
function ParticlePoly:getPoints()
|
|
return self.points[1], self.points[2]
|
|
end
|
|
|
|
function ParticlePoly:setPoints(min,max)
|
|
self.points = {min, max or min}
|
|
end
|
|
|
|
-- angular
|
|
function ParticlePoly:getAngular()
|
|
return self.angular[1], self.angular[2]
|
|
end
|
|
|
|
function ParticlePoly:setAngular(min,max)
|
|
self.angular = {min, max or min}
|
|
end
|
|
|
|
function ParticlePoly:getRotation()
|
|
return self.rotation[1], self.rotation[2]
|
|
end
|
|
|
|
function ParticlePoly:setRotation(min,max)
|
|
self.rotation = {min, max or min}
|
|
end
|
|
|
|
function ParticlePoly:create(amount)
|
|
for i = 1, amount, 1 do
|
|
local part = {
|
|
x = self.x,
|
|
y = self.y,
|
|
dir = math.random(self.spread[1],self.spread[2]),
|
|
size = math.random(self.size[1],self.size[2]) * precision,
|
|
speed = math.random(self.speed[1],self.speed[2]) * precision,
|
|
acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision,
|
|
lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision,
|
|
thickness = math.random(self.thickness[1],self.thickness[2]) * precision,
|
|
angular = math.random(self.angular[1],self.angular[2]) * precision,
|
|
points = math.random(self.points[1], self.points[2]),
|
|
decay = self.decay,
|
|
rotation = math.random(self.rotation[1],self.rotation[2])
|
|
}
|
|
|
|
self.particles[#self.particles+1] = part
|
|
end
|
|
end
|
|
|
|
function ParticlePoly:add(amount)
|
|
self:create(amount)
|
|
end
|
|
|
|
function ParticlePoly:update()
|
|
local w = playdate.graphics.getLineWidth()
|
|
local c = playdate.graphics.getColor()
|
|
playdate.graphics.setColor(self.colour)
|
|
for part = 1, #self.particles, 1 do
|
|
local poly = self.particles[part]
|
|
local polygon = {}
|
|
local degrees = 360 / poly.points
|
|
for point = 1, poly.points, 1 do
|
|
polygon[#polygon+1] = poly.x + math.sin(math.rad(degrees * point + poly.rotation)) * poly.size
|
|
polygon[#polygon+1] = poly.y - math.cos(math.rad(degrees * point + poly.rotation)) * poly.size
|
|
end
|
|
if poly.thickness < 1 then
|
|
playdate.graphics.fillPolygon(table.unpack(polygon))
|
|
else
|
|
playdate.graphics.setLineWidth(poly.thickness)
|
|
playdate.graphics.drawPolygon(table.unpack(polygon))
|
|
end
|
|
|
|
poly.x += math.sin(math.rad(poly.dir)) * poly.speed
|
|
poly.y = poly.y - math.cos(math.rad(poly.dir)) * poly.speed
|
|
|
|
poly.rotation += poly.angular
|
|
|
|
poly.speed += poly.acceleration / 100
|
|
|
|
self.particles[part] = poly
|
|
end
|
|
playdate.graphics.setLineWidth(w)
|
|
playdate.graphics.setColor(c)
|
|
|
|
if self.mode == 1 then
|
|
decay(self.particles, self.decay)
|
|
|
|
elseif self.mode == 0 then
|
|
disappear(self.particles)
|
|
|
|
elseif self.mode == 2 then
|
|
loop(self.particles, self.bounds)
|
|
|
|
else
|
|
stay(self.particles, self.bounds)
|
|
|
|
end
|
|
end
|
|
|
|
class("ParticleImage", {type = 3}).extends(Particle)
|
|
|
|
function ParticleImage:getAngular()
|
|
return self.angular[1], self.angular[2]
|
|
end
|
|
|
|
function ParticleImage:setAngular(min,max)
|
|
self.angular = {min, max or min}
|
|
end
|
|
|
|
function ParticleImage:getRotation()
|
|
return self.rotation[1], self.rotation[2]
|
|
end
|
|
|
|
function ParticleImage:setRotation(min,max)
|
|
self.rotation = {min, max or min}
|
|
end
|
|
|
|
function ParticleImage:setImage(image)
|
|
self.image = image
|
|
self.table = nil
|
|
end
|
|
|
|
function ParticleImage:setImageTable(image)
|
|
self.image = nil
|
|
self.table = image
|
|
end
|
|
|
|
function ParticleImage:getImage()
|
|
return self.image
|
|
end
|
|
|
|
function ParticleImage:getImageTable()
|
|
return self.table
|
|
end
|
|
|
|
function ParticleImage:create(amount)
|
|
if self.image ~= nil then
|
|
for i = 1, amount, 1 do
|
|
local part = {
|
|
x = self.x,
|
|
y = self.y,
|
|
dir = math.random(self.spread[1],self.spread[2]),
|
|
size = math.random(self.size[1],self.size[2]) * precision,
|
|
speed = math.random(self.speed[1],self.speed[2]) * precision,
|
|
acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision,
|
|
lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision,
|
|
thickness = math.random(self.thickness[1],self.thickness[2]),
|
|
angular = math.random(self.angular[1],self.angular[2]) * precision,
|
|
decay = self.decay,
|
|
image = self.image,
|
|
rotation = math.random(self.rotation[1],self.rotation[2])
|
|
}
|
|
|
|
self.particles[#self.particles+1] = part
|
|
end
|
|
else
|
|
for i = 1, amount, 1 do
|
|
local part = {
|
|
x = self.x,
|
|
y = self.y,
|
|
dir = math.random(self.spread[1],self.spread[2]),
|
|
size = math.random(self.size[1],self.size[2]) * precision,
|
|
speed = math.random(self.speed[1],self.speed[2]) * precision,
|
|
acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision,
|
|
lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision,
|
|
thickness = math.random(self.thickness[1],self.thickness[2]),
|
|
angular = math.random(self.angular[1],self.angular[2]) * precision,
|
|
decay = self.decay,
|
|
image = self.table[math.random(#self.table)],
|
|
rotation = math.random(self.rotation[1],self.rotation[2])
|
|
}
|
|
|
|
self.particles[#self.particles+1] = part
|
|
end
|
|
end
|
|
end
|
|
|
|
function ParticleImage:add(amount)
|
|
self:create(amount)
|
|
end
|
|
|
|
function ParticleImage:update()
|
|
for part = 1, #self.particles, 1 do
|
|
local img = self.particles[part]
|
|
|
|
img.image:drawRotated(img.x,img.y,img.rotation,img.size)
|
|
|
|
img.rotation += img.angular
|
|
|
|
img.x += math.sin(math.rad(img.dir)) * img.speed
|
|
img.y = img.y - math.cos(math.rad(img.dir)) * img.speed
|
|
|
|
img.speed += img.acceleration / 100
|
|
|
|
self.particles[part] = img
|
|
end
|
|
|
|
if self.mode == 1 then
|
|
decay(self.particles, self.decay)
|
|
|
|
elseif self.mode == 0 then
|
|
disappear(self.particles)
|
|
|
|
elseif self.mode == 2 then
|
|
loop(self.particles, self.bounds)
|
|
|
|
else
|
|
stay(self.particles, self.bounds)
|
|
|
|
end
|
|
end
|
|
|
|
class("ParticleImageBasic", {type = 3}).extends(ParticleImage)
|
|
|
|
function ParticleImageBasic:update()
|
|
for part = 1, #self.particles, 1 do
|
|
local img = self.particles[part]
|
|
|
|
img.image:drawScaled(img.x,img.y,img.size)
|
|
|
|
img.rotation += img.angular
|
|
|
|
img.x += math.sin(math.rad(img.dir)) * img.speed
|
|
img.y = img.y - math.cos(math.rad(img.dir)) * img.speed
|
|
|
|
img.speed += img.acceleration / 100
|
|
|
|
self.particles[part] = img
|
|
end
|
|
|
|
if self.mode == 1 then
|
|
decay(self.particles, self.decay)
|
|
|
|
elseif self.mode == 0 then
|
|
disappear(self.particles)
|
|
|
|
elseif self.mode == 2 then
|
|
loop(self.particles, self.bounds)
|
|
|
|
else
|
|
stay(self.particles, self.bounds)
|
|
|
|
end
|
|
end
|
|
|
|
class("ParticlePixel").extends(Particle)
|
|
|
|
function ParticlePixel:create(amount)
|
|
for i = 1, amount, 1 do
|
|
local part = {
|
|
x = self.x,
|
|
y = self.y,
|
|
dir = math.random(self.spread[1],self.spread[2]),
|
|
speed = math.random(self.speed[1],self.speed[2]) * precision,
|
|
acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision,
|
|
lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision,
|
|
}
|
|
|
|
self.particles[#self.particles+1] = part
|
|
end
|
|
end
|
|
|
|
function ParticlePixel:add(amount)
|
|
self:create(amount)
|
|
end
|
|
|
|
function ParticlePixel:update()
|
|
local c = playdate.graphics.getColor()
|
|
playdate.graphics.setColor(self.colour)
|
|
for part = 1, #self.particles, 1 do
|
|
local pix = self.particles[part]
|
|
|
|
playdate.graphics.drawPixel(pix.x,pix.y,pix.size)
|
|
|
|
pix.x += math.sin(math.rad(pix.dir)) * pix.speed
|
|
pix.y -= math.cos(math.rad(pix.dir)) * pix.speed
|
|
|
|
pix.speed += pix.acceleration / 100
|
|
|
|
self.particles[part] = pix
|
|
end
|
|
playdate.graphics.setColor(c)
|
|
|
|
if self.mode == 0 then
|
|
disappear(self.particles)
|
|
|
|
elseif self.mode == 2 then
|
|
loop(self.particles, self.bounds)
|
|
|
|
else
|
|
stay(self.particles, self.bounds)
|
|
|
|
end
|
|
end
|
|
|
|
-- [[ GLOBAL PARTICLE STUFF ]] --
|
|
|
|
class("Particles").extends()
|
|
|
|
Particles.modes = {DISAPPEAR = 0, DECAY = 1, LOOP = 2, STAY = 3}
|
|
|
|
function Particles:update()
|
|
for particle = 1, #particles, 1 do
|
|
particles[particle]:update()
|
|
end
|
|
end
|
|
|
|
function Particles:clearAll()
|
|
for part = 1, #particles, 1 do
|
|
particles[part]:clearParticles()
|
|
end
|
|
end
|
|
|
|
function Particles:removeAll()
|
|
local lb = #particles
|
|
for part = 1, #particles, 1 do
|
|
particles[part] = nil
|
|
end
|
|
end
|
|
|
|
function Particles:setPrecision(prec)
|
|
precision = prec
|
|
end
|
|
|
|
function Particles:getPrecision()
|
|
return precision
|
|
end |