Particle tree example

touch and drag to watch the particles form a tree:

--# GenParticle
GenParticle = class()

function GenParticle:init(pos,vel,angvel,ang,grav)
    -- you can accept and set parameters here
    self.parts = {}
    self.n = 0
    self.m = mesh()
    self.m.texture = readImage("Space Art:Beam")
    self.gen = 2
    self:addParticle(pos,vel,angvel,ang,grav)
    self.vel = vel
end

function GenParticle:addParticle(pos,vel,angvel,ang,grav)
    self.n = self.n + 1
    self.parts[self.n] = {}
    self.parts[self.n].r = self.m:addRect(pos.x,pos.y,30,5,ang)
    self.parts[self.n].pos = pos
    self.parts[self.n].vel = vel
    self.parts[self.n].avel = angvel
    self.parts[self.n].ang = ang
    self.parts[self.n].dang = 0
    self.parts[self.n].time = 1
    self.parts[self.n].grav = grav
end

function GenParticle:draw()
    for k,v in pairs(self.parts) do
        v.pos = v.pos + v.vel
        v.vel = v.vel:rotate(v.avel)
        v.ang = v.ang + v.avel
        v.dang = v.dang + v.avel
        self.parts[k].time = v.time -0.05
        self.m:setRect(v.r,v.pos.x,v.pos.y,30,5,vec2():angleBetween(v.vel))
        if v.pos.x<0 then
            v.vel.x = math.abs(v.vel.x)
            v.dang = 0
        elseif v.pos.x>WIDTH then
            v.vel.x = -math.abs(v.vel.x)
            v.dang = 0
        elseif v.pos.y<0 then
            v.vel.y = math.abs(v.vel.y)
            v.dang = 0
        elseif v.pos.y>HEIGHT then
            v.vel.y = -math.abs(v.vel.y)
            v.dang = 0
        end
        if v.time<0 then 
            self.gen = self.gen +2
            self.n=self.n-1
            self.m:setRect(v.r,0,0,0,0) table.remove(self.parts,k) 
            if self.gen%2==0 and self.gen<30 then
                
                for i=1,math.sqrt(self.gen) do
                    self:addParticle(v.pos,v.vel:rotate(math.random(-100,100)*0.01),0,v.ang)
                end
            end
        end
    end
    if #self.parts == 0 and self.m.size>0 then self.m:clear() end
    self.m:draw()
end

--# Main
-- Shake

-- Use this function to perform your initial setup
function setup()
    part = {}
    backingMode(RETAINED)
    parameter.watch("1/DeltaTime")
end

function touched(t) 
    table.insert(part,GenParticle(vec2(t.x,t.y),vec2(t.deltaX,t.deltaY)*0.2,math.random(-10,10)*0.001,
    vec2(0,0):angleBetween(vec2(t.deltaX,t.deltaY)),vec2(0.1,0)))
end
-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    --background(40, 40, 50,10)
    fill(0,10)
    rect(0,0,WIDTH,HEIGHT)
    -- This sets the line thickness
    strokeWidth(0)
    for k,v in pairs(part) do
        v:draw()
        if #v.parts==0 then table.remove(part,k) end
    end
    -- Do your drawing here
end

Updated code, I think this one should be called wheat:


--# GenParticle
GenParticle = class()

function GenParticle:init(pos,vel,angvel,ang,grav)
    -- you can accept and set parameters here
    self.parts = {}
    self.n = 0
    self.m = mesh()
    self.m.texture = readImage("Cargo Bot:Star Filled")
    self.gen = 2
    self:addParticle(pos,vel,angvel,ang,grav)
    self.vel = vel
end

function GenParticle:addParticle(pos,vel,angvel,ang,grav)
    self.n = self.n + 1
    self.parts[self.n] = {}
    self.parts[self.n].r = self.m:addRect(pos.x,pos.y,30,5,ang)
    self.parts[self.n].pos = pos
    self.parts[self.n].vel = vel
    self.parts[self.n].avel = angvel
    self.parts[self.n].ang = ang
    self.parts[self.n].dang = 0
    self.parts[self.n].time = 0.3
    self.parts[self.n].grav = grav
end

function GenParticle:draw()
    for k,v in pairs(self.parts) do
        v.pos = v.pos + v.vel
        v.vel = v.vel:rotate(v.avel)
        v.ang = v.ang + v.avel
        v.dang = v.dang + v.avel
        v.time = v.time -0.05
        self.m:setRect(v.r,v.pos.x,v.pos.y,30,5,vec2():angleBetween(v.vel))
        if v.pos.x<0 then
            v.vel.x = math.abs(v.vel.x)
            v.dang = 0
        elseif v.pos.x>WIDTH then
            v.vel.x = -math.abs(v.vel.x)
            v.dang = 0
        elseif v.pos.y<0 then
            v.vel.y = math.abs(v.vel.y)
            v.dang = 0
        elseif v.pos.y>HEIGHT then
            v.vel.y = -math.abs(v.vel.y)
            v.dang = 0
        end
        if v.time<0 then 
            self.gen = self.gen +2
            self.n=self.n-1
            self.m:setRect(v.r,0,0,0,0) table.remove(self.parts,k) 
            if self.gen%4==0 and self.gen<26 then
                
                for i=1,math.sqrt(self.gen) do
                    self:addParticle(v.pos,v.vel:rotate(math.random(-100,100)*0.008),0,v.ang)
                end
            end
        end
    end
    if #self.parts == 0 and self.m.size>0 then self.m:clear() end
    self.m:draw()
end

--# Main
-- Shake

-- Use this function to perform your initial setup
function setup()
    part = {}
    backingMode(RETAINED)
    parameter.watch("1/DeltaTime")
end

function touched(t) 
    table.insert(part,GenParticle(vec2(t.x,t.y),vec2(t.deltaX,t.deltaY)*0.2,math.random(-10,10)*0.001,
    vec2(0,0):angleBetween(vec2(t.deltaX,t.deltaY)),vec2(0.1,0)))
end
-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    --background(40, 40, 50,10)
    fill(0,10)
    rect(0,0,WIDTH,HEIGHT)
    -- This sets the line thickness
    strokeWidth(0)
    for k,v in pairs(part) do
        v:draw()
        if #v.parts==0 then table.remove(part,k) end
    end
    -- Do your drawing here
end


And here’s a more colourful one:


--# GenParticle
GenParticle = class()

function GenParticle:init(pos,vel,angvel,ang)
    -- you can accept and set parameters here
    self.parts = {}
    self.n = 0
    self.m = mesh()
    self.m.texture = readImage("Cargo Bot:Condition Any")
    self.gen = 1
    self:addParticle(pos,vel,angvel,ang,grav)
    self.vel = vel
    self.generations = 1--math.random(3,7)
    self.amnt=7
    self.time = self.amnt*10
end

function GenParticle:addParticle(pos,vel,angvel,ang)
    self.n = self.n + 1
    self.parts[self.n] = {}
    self.parts[self.n].r = self.m:addRect(pos.x,pos.y,30,5,ang)
    self.parts[self.n].pos = pos
    self.parts[self.n].vel = vel
    self.parts[self.n].avel = angvel
    self.parts[self.n].ang = ang
    self.parts[self.n].dang = 0
    self.parts[self.n].time = 2
end

function GenParticle:draw()
    self.time=self.time-1
    for k,v in pairs(self.parts) do
        v.pos = v.pos + v.vel
        v.vel = v.vel:rotate(v.avel)
        v.ang = v.ang + v.avel
        v.dang = v.dang + v.avel
        v.time = v.time -0.1
        self.m:setRect(v.r,v.pos.x,v.pos.y,30,5,vec2():angleBetween(v.vel))
        if v.time<0 then 
            self.gen = self.gen +0.1
            self.n=self.n-1
            table.remove(self.parts,k)
            self.m:setRect(v.r,0,0,0,0)
            if self.generations<self.amnt then
                for i=1,2 do
                    self:addParticle(v.pos,v.vel:rotate(math.random(-100,100)*0.006),v.avel,v.ang)
                end
            end
        end
    end
    if self.time%10==0 then
        self.generations = self.generations +1
    end
    if #self.parts <= 0 and self.m.size>0 then self.m:clear() end
    self.m:draw()
end

--# Main
-- Shake

-- Use this function to perform your initial setup
function setup()
    part = {}
    backingMode(RETAINED)
    parameter.watch("1/DeltaTime")
    id = 1
end

function touched(t) 
    table.insert(part,GenParticle(vec2(t.x,t.y),vec2(t.deltaX,t.deltaY)*0.5,math.random(-10,10)*0.001,
    vec2(0,0):angleBetween(vec2(t.deltaX,t.deltaY))))
end
-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    --background(40, 40, 50,10)
    fill(0,10)
    rect(0,0,WIDTH,HEIGHT)
    -- This sets the line thickness
    strokeWidth(0)
    local n = 0
    for k,v in pairs(part) do
        v:draw()
        if #v.parts==0 then table.remove(part,k) end
        n = n + #v.parts
    end
    fill(255)
    rect(0,0,100,100)
    fill(0,255)
    text(n,50,50)
    -- Do your drawing here
    id = id + 1
    if id%6 == -1 then
        local p,d = vec2(WIDTH/2,HEIGHT/2),vec2(math.sin(id/20),math.cos(id/20))*math.random(3,6)
        table.insert(part,GenParticle(p,d,math.random(-10,10)*0.0025,vec2(0,0):angleBetween(d)))
    end
end


enjoy!

The user and all related content has been deleted.

@Luatee gotta say, this is pretty cool! Surprised you have time to do this while working on Aedif! :wink:

@Staples I have to wait to backup to my other with codea on it, so I thought I’d make a small project, thanks.

Beautiful! especially the 1rst one .

I have some flickering effect when it fades away, is it the same for you?

@Jmv38 its codeas fault. Haha thanks.

@luatee what do you mean? Do you see it too? Is it really a bug in Codea? I doubt that… Is it a problem with the current beta? I’d like to report to Simeon if it is the case.

@Luatee, @Jmv38 - it may be caused by a bug.

In the draw function, you are looping through the pairs in the part tables and deleting items. The simplified example below shows how this goes wrong

    a={1,2,3,4,5}
    for i,v in pairs(a) do
        print(i,v)
        if i==2 then table.remove(a,i) end -- delete item 2
    end
--output = 1 1, 2 2, 3 4, 4 5 << incorrect! Items 3 and 4 are wrong, and only four items got processed, rather than all five

The problem is that when you delete an item, all the remaining items move up one. So if you delete item 2, then item 3 becomes item 2, and when your loop goes to item 3, it will take what was item 4, and skip item 3 altogether.

I’m sure you’ll find a way to fix it :wink:

Brilliant @Ignatz.
I’ve tried to go backwards but it doesnt fix it…?
Any other idea?

--# GenParticle
GenParticle = class()

function GenParticle:init(pos,vel,angvel,ang)
    -- you can accept and set parameters here
    self.parts = {}
    self.n = 0
    self.m = mesh()
    self.m.texture = readImage("Cargo Bot:Condition Any")
    self.gen = 1
    self:addParticle(pos,vel,angvel,ang,grav)
    self.vel = vel
    self.generations = 1--math.random(3,7)
    self.amnt=7
    self.time = self.amnt*10
end

function GenParticle:addParticle(pos,vel,angvel,ang)
    self.n = self.n + 1
    self.parts[self.n] = {}
    self.parts[self.n].r = self.m:addRect(pos.x,pos.y,30,5,ang)
    self.parts[self.n].pos = pos
    self.parts[self.n].vel = vel
    self.parts[self.n].avel = angvel
    self.parts[self.n].ang = ang
    self.parts[self.n].dang = 0
    self.parts[self.n].time = 2
end

function GenParticle:draw()
    self.time=self.time-1
    for k=#self.parts,1,-1 do
        local v = self.parts[k]
        v.pos = v.pos + v.vel
        v.vel = v.vel:rotate(v.avel)
        v.ang = v.ang + v.avel
        v.dang = v.dang + v.avel
        v.time = v.time -0.1
        self.m:setRect(v.r,v.pos.x,v.pos.y,30,5,vec2():angleBetween(v.vel))
        if v.time<0 then 
            self.gen = self.gen +0.1
            self.n=self.n-1
            table.remove(self.parts,k)
            self.m:setRect(v.r,0,0,0,0)
            if self.generations<self.amnt then
                for i=1,2 do
                    self:addParticle(v.pos,v.vel:rotate(math.random(-100,100)*0.006),v.avel,v.ang)
                end
            end
        end
    end
    if self.time%10==0 then
        self.generations = self.generations +1
    end
    if #self.parts <= 0 and self.m.size>0 then self.m:clear() end
    self.m:draw()
end

--# Main
-- Shake

-- Use this function to perform your initial setup
function setup()
    part = {}
    backingMode(RETAINED)
    parameter.watch("1/DeltaTime")
    id = 1
end

function touched(t) 
    table.insert(part,GenParticle(vec2(t.x,t.y),vec2(t.deltaX,t.deltaY)*0.5,math.random(-10,10)*0.001,
    vec2(0,0):angleBetween(vec2(t.deltaX,t.deltaY))))
end
-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    --background(40, 40, 50,10)
    fill(0,10)
    rect(0,0,WIDTH,HEIGHT)
    -- This sets the line thickness
    strokeWidth(0)
    local n = 0
    for k,v in pairs(part) do
        v:draw()
    end
    for k=#part,1,-1 do
        local v = part[k]
        if #v.parts==0 then table.remove(part,k) end
        n = n + #v.parts
    end
    fill(255)
    rect(0,0,100,100)
    fill(0,255)
    text(n,50,50)
    -- Do your drawing here
    id = id + 1
    if id%6 == -1 then
        local p,d = vec2(WIDTH/2,HEIGHT/2),vec2(math.sin(id/20),math.cos(id/20))*math.random(3,6)
        table.insert(part,GenParticle(p,d,math.random(-10,10)*0.0025,vec2(0,0):angleBetween(d)))
    end
end

@Jmv38 - using my example as a test case, this seems to work

if i==2 then a[i]=nil end

@Ignatz good spot, I’ll try this. It never occurred to me as for me I don’t see it flicker until I have about 600 particles on the screen.