work in progress particle engine

Here is a little particle engine I’ve made. It can produce effects like trails, explosions, fireworks, trails, shooting stars, flames and much more. It can be slow when animating lots of particles 300+ or less on slower devices. You are free to use the code if you wish


--# Main
-- Main
displayMode(OVERLAY)
function setup()
    --_save("explosions","3.0",true)
    parameter.watch("FPS")
    parameter.watch("#explosions")
    parameter.integer("numSparks",10,500,50)
    parameter.number("damping",1.01,1.10,1.05)
    parameter.number("velocity",0.1,1,0.5)
    parameter.integer("MODE",1,3,2)--img,sq,circ
    parameter.boolean("constant",false)
    parameter.boolean("atTouch",false)
    parameter.boolean("Rebound",true)
    parameter.number("GRAVITY",0,5)
    parameter.integer("Xwind",-10,10,0)
    parameter.integer("Ywind",-10,10,0)
    explosions = {}
    img=readImage("Planet Cute:Star")
    print("\
tap for an explosion\
")
    print("scroll down to see all the parameters")
    print("MODES:\
1=image\
2=square\
3=circle")
end

function draw()    
    gravity = vec2(0,-GRAVITY)     
    wind = vec2(Xwind,Ywind)
    FPS=1/DeltaTime
    background(0)
    blendMode(ADDITIVE)
    for i =1, #explosions do
        explosions[i]:draw(gravity,wind)
    end
    cullexplosions()
    if constant then
        explosions[#explosions+1] = Sparks(origin.x,origin.y,numSparks/10,col,nil,30)
    end
    if not atTouch then origin=vec2(WIDTH/2,HEIGHT/2)end
end

function touched(touch)
    if atTouch then origin=vec2(touch.x,touch.y)end
    if touch.state == BEGAN and not constant then
explosions[#explosions+1] = Sparks(origin.x,origin.y,numSparks,col,nil,30)
    end
end

function cullexplosions()
    for i=#explosions,1,-1 do
        if not explosions[i].alive then
            table.remove(explosions,i)
        end
    end
end


--# Spark
Spark = class()

function Spark:init(x,y,c,t,size)
    self.texture = img
    self.size = math.random(size-20,size+20)
    self.pos = vec2(x,y)
    local vel = vec2(0,self.size*velocity)
    self.velocity = vel:rotate(math.random(360))
    self.col = color(255, 255, 0, 255)
    self.alive = true 
    self.angle = math.random(360)
    self.rotationdirection = math.random(-2,2)
    self.damping=damping
    --[[
    self.IsSquare=Square
    self.IsImg=Image
      ]]
    self.type=MODE
end

function Spark:draw(g,w)
    local _gravity = g or vec2(0,-1)
    local _wind = w or vec2(1,0)
    self:move(_gravity,_wind)
    pushMatrix()
    translate(self.pos.x,self.pos.y)
    rotate(self.angle)
    if self.type==1 then
        tint(self.col)
        sprite(self.texture,0,0, self.size)
    else
        fill(self.col)
        if self.type==2 then
            rectMode(CENTER)
            rect(0,0, self.size,self.size)
        else
            ellipse(0,0, self.size)
        end
    end
    popMatrix()
end

function Spark:move(g,w)
    self.size = self.size / self.damping--math.random(1.1,1.5)
    self.col.a = self.col.a /(self.damping)
    self.col.r = self.col.r / self.damping
    self.col.g = self.col.g / (self.damping^3)
    self.velocity = self.velocity / self.damping
    self.velocity = self.velocity + g
    --self.velocity = self.velocity:rotate(0.1)
    self.pos = self.pos + self.velocity
    self.pos = self.pos + w 
    self.pos = self.pos + g
    if self.col.a <= 50 then self.alive = false end
    
    self.angle = self.angle + self.rotationdirection*self.velocity:len()
    if Rebound then
        if self.pos.y<=0 then self.velocity.y=math.max(self.velocity.y,-self.velocity.y)end
        if self.pos.y>=HEIGHT then self.velocity.y=math.min(self.velocity.y,-self.velocity.y)end
        if self.pos.x<=0 then self.velocity.x=math.max(self.velocity.x,-self.velocity.x)end
        if self.pos.x>=WIDTH then self.velocity.x=math.min(self.velocity.x,-self.velocity.x)end
    end
end

Sparks = class()

function Sparks:init(x,y,amount,col,img,size)
    self.alive = true
    self.sparktable={}
    for i = 1, amount do
self.sparktable[i]=Spark(x,y,col or color(math.random(200,255), math.random(0,200), 0,255),img,size)
    end
    
end

function Sparks:draw(grav,wind)
    for i = 1, #self.sparktable do
        self.sparktable[i]:draw(grav,wind)
    end
    local i = 1
    while i <= #self.sparktable do
        if not self.sparktable[i].alive then 
            table.remove(self.sparktable,i)
            i = i - 1
        end
        i = i + 1
    end
    if #self.sparktable == 0 then self.alive = false end
end



@Jmv38 thanks

Really beautiful effect ! Thanks !

yes I think blendMode(ADDITIVE) makes all the diference

Now a video:
(Slow because it uses the inbuilt recording function.

here or here

nice!

@Coder in my project Circles blendMode(ADDITIVE) really makes a difference