diff --git a/Examples/Circles/main.lua b/Examples/Circles/main.lua index 467f00c..7cba1b6 100644 --- a/Examples/Circles/main.lua +++ b/Examples/Circles/main.lua @@ -1,7 +1,7 @@ local gfx = playdate.graphics -import "coreLibs/graphics" -import "coreLibs/object" +import "CoreLibs/graphics" +import "CoreLibs/object" import "pdParticles" local particleA = ParticleCircle(200, 120) @@ -44,4 +44,4 @@ function playdate.update() if playdate.buttonJustPressed(playdate.kButtonUp) then Particles:clearAll() end -end \ No newline at end of file +end diff --git a/Examples/Circles/pdParticles.lua b/Examples/Circles/pdParticles.lua deleted file mode 100644 index 223565b..0000000 --- a/Examples/Circles/pdParticles.lua +++ /dev/null @@ -1,268 +0,0 @@ -local circles = {} - --- base particle class -class("Particle").extends() -function Particle:init(x, y) - self.x = x or 0 - self.y = y or 0 - self.size = {10,10} - self.spread = {0,359} - self.speed = {1,1} - 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 == 1 then - circles[#circles+1] = self - 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 - --- 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 ]] -- - --- circles -local function decayCirc(circs, decay) - for part = 1, #circs, 1 do - local circ = circs[part] - circ.size -= decay - - if circ.size <= 0 then - circ.size = 0 - end - - circs[part] = circ - end - - for part = 1, #circs, 1 do - local circ = circs[part] - if circ.size <= 0 then - table.remove(circs,part) - break - end - end - - return circs -end - -local function disappearCirc(circs) - for part = 1, #circs, 1 do - local circ = circs[part] - circ.lifespan -= .1 - end - for part = 1, #circs, 1 do - local circ = circs[part] - if circ.lifespan <= 0 then - table.remove(circs,part) - break - end - end - - return circs -end - -local function loopCirc(circs, 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, #circs, 1 do - local circ = circs[part] - if circ.x > bounds[3] then circ.x -= xDif - elseif circ.x < bounds[1] then circ.x += xDif end - if circ.y > bounds[4] then circ.y -= yDif - elseif circ.y < bounds[2] then circ.y += yDif end - end - end - - return circs -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]), - speed = math.random(self.speed[1],self.speed[2]), - lifespan = math.random(self.lifespan[1],self.lifespan[2]), - 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 - - self.particles[part] = circ - end - playdate.graphics.setLineWidth(w) - playdate.graphics.setColor(c) - if self.mode == 1 then - local newCircs = decayCirc(self.particles, self.decay) - self.circs = newCircs - elseif self.mode == 0 then - local newCircs = disappearCirc(self.particles) - self.circs = newCircs - elseif self.mode == 2 then - local newCircs = loopCirc(self.particles, self.bounds) - self.circs = newCircs - end -end - -class("Particles").extends() - -Particles.modes = {DISAPPEAR = 0, DECAY = 1, LOOP = 2, STAY = 3} - -function Particles:update() - for circle = 1, #circles, 1 do - circles[circle]:update() - end -end - -function Particles:clearAll() - for circle = 1, #circles, 1 do - circles[circle]:clearParticles() - end -end \ No newline at end of file diff --git a/Examples/Circles/pdParticles.lua b/Examples/Circles/pdParticles.lua new file mode 120000 index 0000000..fefaa93 --- /dev/null +++ b/Examples/Circles/pdParticles.lua @@ -0,0 +1 @@ +../../pdParticles.lua \ No newline at end of file diff --git a/Examples/Particle Avoider/main.lua b/Examples/Particle Avoider/main.lua index bd66a58..e185c31 100644 --- a/Examples/Particle Avoider/main.lua +++ b/Examples/Particle Avoider/main.lua @@ -5,7 +5,7 @@ local showFPS = false -- SET TO 'true' TO SEE FPS import "CoreLibs/graphics" -import "coreLibs/object" +import "CoreLibs/object" import "pdParticles" local gfx = playdate.graphics @@ -29,9 +29,9 @@ function menu() gfx.clear() gfx.drawText("Press A to Play", 200 - gfx.getTextSize("Press A to Play") / 2, 120) - if playdate.buttonJustPressed(playdate.kButtonA) then - playdate.update = game - partObstacles:add(30) + if playdate.buttonJustPressed(playdate.kButtonA) then + playdate.update = game + partObstacles:add(30) end end @@ -39,7 +39,7 @@ end function game() -- [[ UPDATE ]] -- - + -- set the player's position based on player input local changeX, changeY = 0, 0 if playdate.buttonIsPressed(playdate.kButtonUp) then @@ -84,4 +84,4 @@ function game() end playdate.update = menu -- override the playdate.update() function, setting it to the menu() function --- cool lua feature, way cleaner than a state machine \ No newline at end of file +-- cool lua feature, way cleaner than a state machine diff --git a/Examples/Particle Avoider/pdParticles.lua b/Examples/Particle Avoider/pdParticles.lua deleted file mode 100644 index ee002d7..0000000 --- a/Examples/Particle Avoider/pdParticles.lua +++ /dev/null @@ -1,578 +0,0 @@ -local particles = {} - --- 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.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 - --- [[ 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 - --- 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 = 1, #partlist, 1 do - local particle = partlist[part] - if particle.size <= 0 then - table.remove(partlist,part) - break - 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 = 1, #partlist, 1 do - local particle = partlist[part] - if particle.lifespan <= 0 then - table.remove(partlist,part) - break - 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 = 1, #partlist, 1 do - local particle = partlist[part] - if particle.x > bounds[3] then table.remove(partlist,part) break - elseif particle.x < bounds[1] then table.remove(partlist,part) break - elseif particle.y > bounds[4] then table.remove(partlist,part) break - elseif particle.y < bounds[2] then table.remove(partlist,part) break 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]), - speed = math.random(self.speed[1],self.speed[2]), - lifespan = math.random(self.lifespan[1],self.lifespan[2]), - 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 - - 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]), - speed = math.random(self.speed[1],self.speed[2]), - lifespan = math.random(self.lifespan[1],self.lifespan[2]), - thickness = math.random(self.thickness[1],self.thickness[2]), - angular = math.random(self.angular[1],self.angular[2]), - 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 - - 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]), - speed = math.random(self.speed[1],self.speed[2]), - lifespan = math.random(self.lifespan[1],self.lifespan[2]), - thickness = math.random(self.thickness[1],self.thickness[2]), - angular = math.random(self.angular[1],self.angular[2]), - 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]), - speed = math.random(self.speed[1],self.speed[2]), - lifespan = math.random(self.lifespan[1],self.lifespan[2]), - thickness = math.random(self.thickness[1],self.thickness[2]), - angular = math.random(self.angular[1],self.angular[2]), - 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 - - 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 - - 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]), - lifespan = math.random(self.lifespan[1],self.lifespan[2]), - } - - 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 - - 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 \ No newline at end of file diff --git a/Examples/Particle Avoider/pdParticles.lua b/Examples/Particle Avoider/pdParticles.lua new file mode 120000 index 0000000..fefaa93 --- /dev/null +++ b/Examples/Particle Avoider/pdParticles.lua @@ -0,0 +1 @@ +../../pdParticles.lua \ No newline at end of file diff --git a/Examples/Particle Player/main.lua b/Examples/Particle Player/main.lua index 9f07bc8..ed16bb0 100644 --- a/Examples/Particle Player/main.lua +++ b/Examples/Particle Player/main.lua @@ -1,7 +1,7 @@ local gfx = playdate.graphics -import "coreLibs/graphics" -import "coreLibs/object" +import "CoreLibs/graphics" +import "CoreLibs/object" import "pdParticles" local speed = 3 @@ -27,8 +27,6 @@ function playdate.update() part:add(1) Particles:update() - print(#part:getParticles()) - local vel = {0,0} if playdate.buttonIsPressed(playdate.kButtonDown) then @@ -45,4 +43,4 @@ function playdate.update() end part:moveBy(vel[1] * speed,vel[2] * speed) -end \ No newline at end of file +end diff --git a/Examples/Particle Player/pdParticles.lua b/Examples/Particle Player/pdParticles.lua deleted file mode 100644 index f2c8567..0000000 --- a/Examples/Particle Player/pdParticles.lua +++ /dev/null @@ -1,377 +0,0 @@ -local particles = {} - --- base particle class -class("Particle").extends() -function Particle:init(x, y) - self.x = x or 0 - self.y = y or 0 - self.size = {10,10} - self.spread = {0,359} - self.speed = {1,1} - 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 - self.angular={0,0} - self.points={3,3} - - particles[#particles+1] = self - -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 - --- 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 = 1, #partlist, 1 do - local particle = partlist[part] - if particle.size <= 0 then - table.remove(partlist,part) - break - 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 = 1, #partlist, 1 do - local particle = partlist[part] - if particle.lifespan <= 0 then - table.remove(partlist,part) - break - 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 = 1, #partlist, 1 do - local particle = partlist[part] - if particle.x > bounds[3] then table.remove(partlist,part) break - elseif particle.x < bounds[1] then table.remove(partlist,part) break - elseif particle.y > bounds[4] then table.remove(partlist,part) break - elseif particle.y < bounds[2] then table.remove(partlist,part) break 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]), - speed = math.random(self.speed[1],self.speed[2]), - lifespan = math.random(self.lifespan[1],self.lifespan[2]), - 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 - - self.particles[part] = circ - end - playdate.graphics.setLineWidth(w) - playdate.graphics.setColor(c) - if self.mode == 1 then - local newCircs = decay(self.particles, self.decay) - - elseif self.mode == 0 then - local newCircs = disappear(self.particles) - - elseif self.mode == 2 then - local newCircs = loop(self.particles, self.bounds) - - else - local newCircs = 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: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]), - speed = math.random(self.speed[1],self.speed[2]), - lifespan = math.random(self.lifespan[1],self.lifespan[2]), - thickness = math.random(self.thickness[1],self.thickness[2]), - angular = math.random(self.angular[1],self.angular[2]), - points = math.random(self.points[1], self.points[2]), - decay = self.decay, - rotation = 0 - } - - 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 - - self.particles[part] = poly - end - playdate.graphics.setLineWidth(w) - playdate.graphics.setColor(c) - - if self.mode == 1 then - local newCircs = decay(self.particles, self.decay) - - elseif self.mode == 0 then - local newCircs = disappear(self.particles) - - elseif self.mode == 2 then - local newCircs = loop(self.particles, self.bounds) - - else - local newCircs = 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 \ No newline at end of file diff --git a/Examples/Particle Player/pdParticles.lua b/Examples/Particle Player/pdParticles.lua new file mode 120000 index 0000000..fefaa93 --- /dev/null +++ b/Examples/Particle Player/pdParticles.lua @@ -0,0 +1 @@ +../../pdParticles.lua \ No newline at end of file diff --git a/Examples/Shapes/pdParticles.lua b/Examples/Shapes/pdParticles.lua deleted file mode 100644 index 09d7ccf..0000000 --- a/Examples/Shapes/pdParticles.lua +++ /dev/null @@ -1,377 +0,0 @@ -local particles = {} - --- base particle class -class("Particle").extends() -function Particle:init(x, y) - self.x = x or 0 - self.y = y or 0 - self.size = {10,10} - self.spread = {0,359} - self.speed = {1,1} - 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 - self.angular={0,0} - self.points={3,3} - - particles[#particles+1] = self - -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 - --- 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 = 1, #partlist, 1 do - local particle = partlist[part] - if particle.size <= 0 then - table.remove(partlist,part) - break - 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 = 1, #partlist, 1 do - local particle = partlist[part] - if particle.lifespan <= 0 then - table.remove(partlist,part) - break - 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 = 1, #partlist, 1 do - local particle = partlist[part] - if particle.x > bounds[3] then table.remove(partlist,part) break - elseif particle.x < bounds[1] then table.remove(partlist,part) break - elseif particle.y > bounds[4] then table.remove(partlist,part) break - elseif particle.y < bounds[2] then table.remove(partlist,part) break 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]), - speed = math.random(self.speed[1],self.speed[2]), - lifespan = math.random(self.lifespan[1],self.lifespan[2]), - 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 - - self.particles[part] = circ - end - playdate.graphics.setLineWidth(w) - playdate.graphics.setColor(c) - if self.mode == 1 then - local newCircs = decay(self.particles, self.decay) - - elseif self.mode == 0 then - local newCircs = disappear(self.particles) - - elseif self.mode == 2 then - local newCircs = loop(self.particles, self.bounds) - - else - local newCircs = 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: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]), - speed = math.random(self.speed[1],self.speed[2]), - lifespan = math.random(self.lifespan[1],self.lifespan[2]), - thickness = math.random(self.thickness[1],self.thickness[2]), - angular = math.random(self.angular[1],self.angular[2]), - points = math.random(self.points[1], self.points[2]), - decay = self.decay, - rotation = 0 - } - - 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 - - self.particles[part] = poly - end - playdate.graphics.setLineWidth(w) - playdate.graphics.setColor(c) - - if self.mode == 1 then - local newCircs = decay(self.particles, self.decay) - - elseif self.mode == 0 then - local newCircs = disappear(self.particles) - - elseif self.mode == 2 then - local newCircs = loop(self.particles, self.bounds) - - else - local newCircs = 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 circle = 1, #circles, 1 do - circles[circle]:update() - end -end - -function Particles:clearAll() - for part = 1, #particles, 1 do - particles[part]:clearParticles() - end -end \ No newline at end of file diff --git a/Examples/Shapes/pdParticles.lua b/Examples/Shapes/pdParticles.lua new file mode 120000 index 0000000..fefaa93 --- /dev/null +++ b/Examples/Shapes/pdParticles.lua @@ -0,0 +1 @@ +../../pdParticles.lua \ No newline at end of file diff --git a/pdParticles.lua b/pdParticles.lua index 4f4f100..2efbd50 100644 --- a/pdParticles.lua +++ b/pdParticles.lua @@ -1,9 +1,11 @@ local particles = {} local precision = 1 +local particle_pool_size = 25 -- base particle class class("Particle").extends() -function Particle:init(x, y) +function Particle:init(x, y, pool_size) + pool_size = pool_size or particle_pool_size self.x = x or 0 self.y = y or 0 self.size = {1,1} @@ -13,7 +15,6 @@ function Particle:init(x, y) 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 @@ -28,16 +29,35 @@ function Particle:init(x, y) self.rotation = {0,359} end - particles[#particles+1] = self + self.partlist = table.create(pool_size, 0) + self.active = table.create(pool_size, 0) + self.available = table.create(pool_size, 0) + self:create(pool_size) + table.insert(particles, self) +end +function Particle:default(part) + part = part or {} + -- Stub function, should be overridden by child classes + return part or {} end -function Particle:remove() - for i = 1, #particles, 1 do - if particles[i] == self then - table.remove(particles, i) - break - end +function Particle:create(amount) + for _ = 1, amount do + self.partlist[#self.partlist + 1] = self:default() + table.insert(self.available, #self.partlist) + end +end + +function Particle:add(amount) + if #self.available - amount < 0 then + self:create(amount - #self.available) + end + + for _ = 1, amount do + local index = table.remove(self.available) + table.insert(self.active, index) + self.partlist[index] = self:default(self.partlist[index]) end end @@ -158,11 +178,17 @@ end -- particles function Particle:getParticles() - return self.particles + return self.partlist +end + +function Particle:getActive() + return self.active end function Particle:clearParticles() - self.particles = {} + self.partlist = {} + self.active = {} + self.available = {} end function Particle:update() @@ -170,103 +196,90 @@ 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 +local function remove(index, active, available) + table.insert(available, index) + table.remove(active, index) +end - partlist[part] = particle - end +local function decay(parts, active, available, decay) + for i = #active, 1, -1 do + local index = active[i] + local part = parts[index] + part.size -= decay - for part = #partlist, 1, -1 do - local particle = partlist[part] - if particle.size <= 0 then - table.remove(partlist,part) + if part.size <= 0 then + part.size = 0 + remove(i, active, available) end end - - return partlist end -local function disappear(partlist) - for part = 1, #partlist, 1 do - local particle = partlist[part] +local function disappear(partlist, active, available) + for i = #active, 1, -1 do + local index = active[i] + local particle = partlist[index] particle.lifespan -= .1 - end - for part = #partlist, 1, -1 do - local particle = partlist[part] + if particle.lifespan <= 0 then - table.remove(partlist,part) + remove(i, active, available) end end - - return partlist end -local function loop(partlist, bounds) +local function loop(partlist, active, _, 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] + for index = 1, #active, 1 do + local particle = partlist[active[index]] 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) +local function stay(partlist, active, available, 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 + for i = #active, 1, -1 do + local index = active[i] + local particle = partlist[index] + if particle.x > bounds[3] then + remove(i, active, available) + elseif particle.x < bounds[1] then + remove(i, active, available) + elseif particle.y > bounds[4] then + remove(i, active, available) + elseif particle.y < bounds[2] then + remove(i, active, available) + 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) +function ParticleCircle:default(part) + part = part or {} + part.x = self.x + part.y = self.y + part.dir = math.random(self.spread[1],self.spread[2]) + part.size = math.random(self.size[1],self.size[2]) * precision + part.speed = math.random(self.speed[1],self.speed[2]) * precision + part.acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision + part.lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision + part.thickness = math.random(self.thickness[1],self.thickness[2]) + part.decay = self.decay + return part 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] + for i = #self.active, 1, -1 do + local index = self.active[i] + local circ = self.partlist[index] if circ.thickness < 1 then playdate.graphics.fillCircleAtPoint(circ.x,circ.y,circ.size) else @@ -276,25 +289,21 @@ function ParticleCircle:update() 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 + self.partlist[index] = circ end playdate.graphics.setLineWidth(w) playdate.graphics.setColor(c) if self.mode == 1 then - decay(self.particles, self.decay) - + decay(self.partlist, self.active, self.available, self.decay) elseif self.mode == 0 then - disappear(self.particles) - + disappear(self.partlist, self.active, self.available) elseif self.mode == 2 then - loop(self.particles, self.bounds) - + loop(self.partlist, self.active, nil, self.bounds) else - stay(self.particles, self.bounds) - + stay(self.partlist, self.active, self.available, self.bounds) end end @@ -325,37 +334,30 @@ 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) +function ParticlePoly:default(part) + part = part or {} + part.x = self.x + part.y = self.y + part.dir = math.random(self.spread[1],self.spread[2]) + part.size = math.random(self.size[1],self.size[2]) * precision + part.speed = math.random(self.speed[1],self.speed[2]) * precision + part.acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision + part.lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision + part.thickness = math.random(self.thickness[1],self.thickness[2]) * precision + part.angular = math.random(self.angular[1],self.angular[2]) * precision + part.points = math.random(self.points[1], self.points[2]) + part.decay = self.decay + part.rotation = math.random(self.rotation[1],self.rotation[2]) + return part 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] + for i = #self.active, 1, -1 do + local index = self.active[i] + local poly = self.partlist[index] local polygon = {} local degrees = 360 / poly.points for point = 1, poly.points, 1 do @@ -373,26 +375,22 @@ function ParticlePoly:update() 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 + self.partlist[index] = poly end playdate.graphics.setLineWidth(w) playdate.graphics.setColor(c) if self.mode == 1 then - decay(self.particles, self.decay) - + decay(self.partlist, self.active, self.available, self.decay) elseif self.mode == 0 then - disappear(self.particles) - + disappear(self.partlist, self.active, self.available) elseif self.mode == 2 then - loop(self.particles, self.bounds) - + loop(self.partlist, self.active, self.available, self.bounds) else - stay(self.particles, self.bounds) - + stay(self.partlist, self.active, self.available, self.bounds) end end @@ -432,55 +430,28 @@ 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) +function ParticleImage:default(part) + part = part or {} + part.x = self.x + part.y = self.y + part.dir = math.random(self.spread[1],self.spread[2]) + part.size = math.random(self.size[1],self.size[2]) * precision + part.speed = math.random(self.speed[1],self.speed[2]) * precision + part.acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision + part.acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision + part.lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision + part.thickness = math.random(self.thickness[1],self.thickness[2]) + part.angular = math.random(self.angular[1],self.angular[2]) * precision + part.decay = self.decay + part.image = self.image + part.rotation = math.random(self.rotation[1],self.rotation[2]) + return part end function ParticleImage:update() - for part = 1, #self.particles, 1 do - local img = self.particles[part] + for i = #self.active, 1, -1 do + local index = self.active[i] + local img = self.partlist[index] img.image:drawRotated(img.x,img.y,img.rotation,img.size) @@ -488,32 +459,29 @@ function ParticleImage:update() 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 + self.partlist[index] = img end if self.mode == 1 then - decay(self.particles, self.decay) - + decay(self.partlist, self.active, self.available, self.decay) elseif self.mode == 0 then - disappear(self.particles) - + disappear(self.partlist, self.active, self.available) elseif self.mode == 2 then - loop(self.particles, self.bounds) - + loop(self.partlist, self.active, nil, self.bounds) else - stay(self.particles, self.bounds) - + stay(self.partlist, self.active, self.available, 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] + for i = #self.active, 1, -1 do + local index = self.active[i] + local img = self.partlist[index] img.image:drawScaled(img.x,img.y,img.size) @@ -524,71 +492,58 @@ function ParticleImageBasic:update() img.speed += img.acceleration / 100 - self.particles[part] = img + self.partlist[index] = img end if self.mode == 1 then - decay(self.particles, self.decay) - + decay(self.partlist, self.decay) elseif self.mode == 0 then - disappear(self.particles) - + disappear(self.partlist) elseif self.mode == 2 then - loop(self.particles, self.bounds) - + loop(self.partlist, self.bounds) else - stay(self.particles, self.bounds) - + stay(self.partlist, 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) +function ParticlePixel:default(part) + part = part or {} + part.x = self.x + part.y = self.y + part.dir = math.random(self.spread[1],self.spread[2]) + part.size = math.random(self.size[1],self.size[2]) * precision + part.speed = math.random(self.speed[1],self.speed[2]) * precision + part.acceleration = math.random(self.acceleration[1],self.acceleration[2]) * precision + part.lifespan = math.random(self.lifespan[1],self.lifespan[2]) * precision + return part 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] - + for i = #self.active, 1, -1 do + local index = self.active[i] + local pix = self.partlist[index] + 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 + self.partlist[index] = pix end playdate.graphics.setColor(c) if self.mode == 0 then - disappear(self.particles) - + disappear(self.partlist, self.active, self.available) elseif self.mode == 2 then - loop(self.particles, self.bounds) - + loop(self.partlist, self.active, nil, self.bounds) else - stay(self.particles, self.bounds) - + stay(self.partlist, self.active, self.available, self.bounds) end end @@ -624,3 +579,11 @@ end function Particles:getPrecision() return precision end + +function Particles:setParticlePoolSize(size) + particle_pool_size = size +end + +function Particles:getParticlePoolSize() + return particle_pool_size +end