Particle System example

Here’s a basic particle system class that uses mesh. Feel free to use it however you like.

Emitter = class()

function Emitter:init(args)
    self.particleMesh = mesh()
    self.particleMesh.texture = args.tex
    self.minLife = args.minLife or 1
    self.maxLife = args.maxLife or 1
    self.spread = args.spread or 360
    self.angle = args.angle or 0
    self.minSpeed = args.minSpeed or 10
    self.maxSpeed = args.maxSpeed or 50
    self.minSize = args.minSize or 10
    self.maxSize = args.maxSize or 15
    self.growth = args.growth or 1
    self.startColor = args.startColor or color(255, 255, 255, 255)
    self.endColor = args.endColor or color(0, 0, 0, 0)
    self.streak = args.streak or false
    self.streakMult = args.streakMult or 2
    self.accel = args.accel or vec2(0,0)
    self.rAccel = args.rAccel or vec2(0,0) 
    
    self.particles = {}
    self.pCount = 0
    for i = 1,100 do
        table.insert(self.particles, Particle())
    end
end

function Emitter:emit(pos,count)
    for i = 1,#self.particles do
        local p = self.particles[i]
        if p.dead then
            self.pCount = math.max(i, self.pCount)
            p.dead = false
            p.pos = pos
            p.life = math.random(self.minLife, self.maxLife)
            p.size = math.random(self.minSize, self.maxSize)
            p.maxLife = p.life
            p.vel = vec2(0, math.random(self.minSpeed, self.maxSpeed))
            p.vel = p.vel:rotate(math.rad(self.angle + math.random(-self.spread/2, self.spread/2)))
            count = count - 1
            if count == 0 then return end
        end
    end
end

function Emitter:draw()
    -- update
    self.particleMesh:clear()
    for i = 1,self.pCount do
        local p = self.particles[i]
        if not p.dead then
            p.prevPos = p.pos
            p.pos = p.pos + p.vel * DeltaTime
            p.vel = p.vel + (self.accel + vec2(math.random(-self.rAccel.x, self.rAccel.x), math.random(-self.rAccel.y, self.rAccel.y)))  * DeltaTime
            p.life = math.max(0, p.life - DeltaTime)
            p.size = p.size + DeltaTime * self.growth
            if p.life == 0 then p.dead = true end
            local interp = p.life / p.maxLife
           
            p.col.r = interp * self.startColor.r + (1-interp) * self.endColor.r
            p.col.g = interp * self.startColor.g + (1-interp) * self.endColor.g
            p.col.b = interp * self.startColor.b + (1-interp) * self.endColor.b
            p.col.a = interp * self.startColor.a + (1-interp) * self.endColor.a
            local ind = self.particleMesh:addRect(p.pos.x, p.pos.y, p.size, p.size)
            self.particleMesh:setRectColor(ind, p.col)
            if self.streak then
                local dir = (p.pos - p.prevPos)
                local len = dir:len()
                local pos = (p.pos + p.prevPos) * 0.5
                local ang = math.atan2(dir.y, dir.x)
                self.particleMesh:setRect(ind, pos.x, pos.y, p.size * self.streakMult, p.size, ang)
            end
        end
    end
    self.particleMesh:draw()
end


Particle = class()

function Particle:init()
    self.pos = vec2(0,0)
    self.prevPos = vec2(0,0)
    self.vel = vec2(0,0)
    self.life = 0
    self.maxLife = 0
    self.dead = true
    self.col = color(0, 0, 0, 255)
    self.size = 0
end

-- create emitter
sparks = Emitter({tex = "Tyrian Remastered:Bullet Fire A",
                           startColor = color(0, 0, 0, 255),
                           endColor = color(0, 0, 0, 0),
                           minSize = 5, 
                           maxSize = 5,
                           minSpeed = 100,
                           maxSpeed = 150,
                           accel = vec2(0,-1000),
                           rAccel = vec2(1500,1500),
                           streak = true,
                           streakMult = 3})
-- emit particle
sparks:emit(vec2(100, 100), 10)

Thanks you! Wonderful!

Hello @John, brilliant. Do you have, maybe, an example for using it?
Thanks in advance.
Victor ~O)