Lightning touch

Something I’ve been messing around with. Touch the screen to generate a lightning effect. Satisfies your inner Palpatine!

-- Lightning Touch
displayMode(FULLSCREEN)

function setup()
    target=vec2(WIDTH/2,HEIGHT/2)
    generateArc()
    showLightning=false
end

function draw()
    -- This sets a dark background color
    background(42, 42, 83, 255)
    if showLightning then
    for i,a in pairs(arc) do
        if math.random(5)>1 then
        --do nothing - leave the arc blank    
        else
            local w=math.random(3)
            strokeWidth(w*5)
            
            stroke(102, 34, 129, 255)
            line(a.s.x,a.s.y,a.a.x,a.a.y)
            line(a.a.x,a.a.y,a.b.x,a.b.y)
            line(a.b.x,a.b.y,target.x,target.y)
            
            strokeWidth(w*3)
            
            stroke(182, 0, 255, 255)
            line(a.s.x,a.s.y,a.a.x,a.a.y)
            line(a.a.x,a.a.y,a.b.x,a.b.y)
            line(a.b.x,a.b.y,target.x,target.y)
            
            strokeWidth(w)
            stroke(255, 255, 255, 255)
            line(a.s.x,a.s.y,a.a.x,a.a.y)
            line(a.a.x,a.a.y,a.b.x,a.b.y)
            line(a.b.x,a.b.y,target.x,target.y)
            
        end
    end
    
    peturb()
    
    stroke(182, 0, 255, 255)
    fill(255)
    ellipse(target.x,target.y,10+math.random(5))
    end
end

function touched(t)
    target.x=t.x
    target.y=t.y
    generateArc()
    for i=1,25 do
        peturb()
    end
    if t.state==BEGAN then
        showLightning=true
    elseif t.state==ENDED or t.state==CANCELLED then
        showLightning=false        
    end
end

function peturb()
    for i,a in pairs(arc) do
        a.a.x=a.a.x+math.random(7)-4
        a.a.y=a.a.y+math.random(7)-4
        a.b.x=a.b.x+math.random(7)-4
        a.b.y=a.b.y+math.random(7)-4
    end
end

function generateArc()
    arc={}
    table.insert(arc,{s=vec2(0,0),a=vec2(target.x/3,target.y/3),b=vec2(2*target.x/3,2*target.y/3)})
    table.insert(arc,{s=vec2(WIDTH,0),a=vec2(WIDTH-(WIDTH-target.x)/3,target.y/3),b=vec2(WIDTH-2*(WIDTH-target.x)/3,2*target.y/3)})
    table.insert(arc,{s=vec2(0,HEIGHT),a=vec2(target.x/3,HEIGHT-(HEIGHT-target.y)/3),b=vec2(2*target.x/3,HEIGHT-2*(HEIGHT-target.y)/3)})
    table.insert(arc,{s=vec2(WIDTH,HEIGHT),a=vec2(WIDTH-(WIDTH-target.x)/3,HEIGHT-(HEIGHT-target.y)/3),b=vec2(WIDTH-2*(WIDTH-target.x)/3,HEIGHT-2*(HEIGHT-target.y)/3)})
    table.insert(arc,{s=vec2(WIDTH/2,0),a=vec2(WIDTH/2-(WIDTH/2-target.x)/3,target.y/3),b=vec2(WIDTH/2-2*((WIDTH/2-target.x)/3),2*target.y/3)})
    table.insert(arc,{s=vec2(WIDTH/2,HEIGHT),a=vec2(WIDTH/2-(WIDTH/2-target.x)/3,HEIGHT-(HEIGHT-target.y)/3),b=vec2(WIDTH/2-2*((WIDTH/2-target.x)/3),HEIGHT-2*(HEIGHT-target.y)/3)})
    table.insert(arc,{s=vec2(0,HEIGHT/2),a=vec2(target.x/3,HEIGHT/2-(HEIGHT/2-target.y)/3),b=vec2(2*target.x/3,HEIGHT/2-2*((HEIGHT/2-target.y)/3))})
    table.insert(arc,{s=vec2(WIDTH,HEIGHT/2),a=vec2(WIDTH-(WIDTH-target.x)/3,HEIGHT/2-(HEIGHT/2-target.y)/3),b=vec2(WIDTH-2*(WIDTH-target.x)/3,HEIGHT/2-2*((HEIGHT/2-target.y)/3))})
end

@West Nice effect. Reminds me of those plasma globes. Need to add more touches to really jazz it up.

From the code above, here would be a multitouch version:

-- Lightning Touch
displayMode(FULLSCREEN)

function setup()
    --target=vec2(WIDTH/2,HEIGHT/2)
    generateArc(vec2(0, 0))
    showLightning=false
    touches = {}
end

function draw()
    -- This sets a dark background color
    background(42, 42, 83, 255)
    if showLightning then
        for _, b in pairs(touches) do
            for i, a in pairs(b.arc) do
                if math.random(5)>1 then
                    --do nothing - leave the arc blank    
                else
                    local w=math.random(3)
                    strokeWidth(w*5)
                    
                    stroke(b.col:blend(color(0, 255)))
                    line(a.s.x, a.s.y, a.a.x, a.a.y)
                    line(a.a.x, a.a.y, a.b.x, a.b.y)
                    line(a.b.x, a.b.y, b.t.x, b.t.y)
                    
                    strokeWidth(w*3)
                    
                    stroke(b.col)
                    line(a.s.x, a.s.y, a.a.x, a.a.y)
                    line(a.a.x, a.a.y, a.b.x, a.b.y)
                    line(a.b.x, a.b.y, b.t.x, b.t.y)
                    
                    strokeWidth(w)
                    stroke(255, 255, 255, 255)
                    line(a.s.x, a.s.y, a.a.x, a.a.y)
                    line(a.a.x, a.a.y, a.b.x, a.b.y)
                    line(a.b.x, a.b.y, b.t.x, b.t.y)
                    
                end
            end
            
            --peturb()
            
            stroke(182, 0, 255, 255)
            fill(255)
            ellipse(b.t.x, b.t.y, 10+math.random(5))
        end
    end
end

function touched(t)
    if t.state==ENDED or t.state==CANCELLED then
        touches[t.id] = nil
        return
    else
        touches[t.id] = {
            t = t,
            arc = generateArc(vec2(t.x, t.y)),
            col = color(math.random(150, 255), math.random(0, 50), math.random(200, 255))
        }
    end
    
    local touchesAmount = 0
    for a, b in pairs(touches) do
        touchesAmount = a
    end
    
    showLightning = true
    if touchesAmount == 0 then
        showLightning = false
        return
    end
    
    --target.x=t.x
    --target.y=t.y
    --generateArc()
    for i=1,25 do
        touches[t.id].arc = peturb(touches[t.id].arc)
    end
end

function peturb(arc)
    for i,a in pairs(arc) do
        a.a.x=a.a.x+math.random(7)-4
        a.a.y=a.a.y+math.random(7)-4
        a.b.x=a.b.x+math.random(7)-4
        a.b.y=a.b.y+math.random(7)-4
    end
    return arc
end

function generateArc(target)
    arc={}
    table.insert(arc,{s=vec2(0,0),a=vec2(target.x/3,target.y/3),b=vec2(2*target.x/3,2*target.y/3)})
    table.insert(arc,{s=vec2(WIDTH,0),a=vec2(WIDTH-(WIDTH-target.x)/3,target.y/3),b=vec2(WIDTH-2*(WIDTH-target.x)/3,2*target.y/3)})
    table.insert(arc,{s=vec2(0,HEIGHT),a=vec2(target.x/3,HEIGHT-(HEIGHT-target.y)/3),b=vec2(2*target.x/3,HEIGHT-2*(HEIGHT-target.y)/3)})
    table.insert(arc,{s=vec2(WIDTH,HEIGHT),a=vec2(WIDTH-(WIDTH-target.x)/3,HEIGHT-(HEIGHT-target.y)/3),b=vec2(WIDTH-2*(WIDTH-target.x)/3,HEIGHT-2*(HEIGHT-target.y)/3)})
    table.insert(arc,{s=vec2(WIDTH/2,0),a=vec2(WIDTH/2-(WIDTH/2-target.x)/3,target.y/3),b=vec2(WIDTH/2-2*((WIDTH/2-target.x)/3),2*target.y/3)})
    table.insert(arc,{s=vec2(WIDTH/2,HEIGHT),a=vec2(WIDTH/2-(WIDTH/2-target.x)/3,HEIGHT-(HEIGHT-target.y)/3),b=vec2(WIDTH/2-2*((WIDTH/2-target.x)/3),HEIGHT-2*(HEIGHT-target.y)/3)})
    table.insert(arc,{s=vec2(0,HEIGHT/2),a=vec2(target.x/3,HEIGHT/2-(HEIGHT/2-target.y)/3),b=vec2(2*target.x/3,HEIGHT/2-2*((HEIGHT/2-target.y)/3))})
    table.insert(arc,{s=vec2(WIDTH,HEIGHT/2),a=vec2(WIDTH-(WIDTH-target.x)/3,HEIGHT/2-(HEIGHT/2-target.y)/3),b=vec2(WIDTH-2*(WIDTH-target.x)/3,HEIGHT/2-2*((HEIGHT/2-target.y)/3))})
    return arc
end

Note: I have only added all needs for multitouch, all your algorithms stayed, and they are great! I look to seeing more from you)

@dave1707 cheers - yes, though I’ve hard-coded in the location of the source points which makes it pretty inflexible.

@Anatoly good job on the multi touch

An updated version with multi touch and arcs on travel from a source point to the nearest touch. Additional demos of touch point to touch point arcs and arcs from initial touch point to current position are also demonstrated.

-- Lightning Touch
--displayMode(FULLSCREEN)

function setup()
    target=vec2(WIDTH/2,HEIGHT/2)
    arc={}
    showLightning=true
    touches={}
    tsup={}
    sources={
    {s=vec2(0,0),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(WIDTH/2,0),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(WIDTH,0),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(WIDTH,HEIGHT/2),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(WIDTH,HEIGHT),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(WIDTH/2,HEIGHT),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(0,HEIGHT),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(0,HEIGHT/2),t=vec2(WIDTH/2,HEIGHT/2)}
    }
    parameter.boolean("sourceTouches",true)
    parameter.boolean("connectTouches")
    parameter.boolean("anchorTouches")
    parameter.boolean("globe",false)
    parameter.color("arcCol",182,0,255)
end

function draw()
    -- This sets a dark background color
    background(42, 42, 83, 255)
    
    if globe then
        local r=math.min(WIDTH,HEIGHT)/2
        noFill()
        ellipse(WIDTH/2,HEIGHT/2,r*2)
        sources={}
        for i=0,360,5 do
            table.insert(sources,{s=vec2(WIDTH/2+ r*math.cos(math.rad(i)),HEIGHT/2+ r*math.sin(math.rad(i))),t=vec2(WIDTH/2,HEIGHT/2)})
        end
    else
            sources={
    {s=vec2(0,0),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(WIDTH/2,0),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(WIDTH,0),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(WIDTH,HEIGHT/2),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(WIDTH,HEIGHT),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(WIDTH/2,HEIGHT),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(0,HEIGHT),t=vec2(WIDTH/2,HEIGHT/2)},
    {s=vec2(0,HEIGHT/2),t=vec2(WIDTH/2,HEIGHT/2)}
    }
    end
    
    if showLightning then
        arc={}
        --draw arc between each source point and nearest touch
        if sourceTouches then
            for j,s in pairs(sources) do
                s.t.x=-1
                s.t.y=-1
                for i,t in pairs(touches) do
                    if s.t.x==-1 then
                        s.t.x=t.x
                        s.t.y=t.y
                    end
                    if vec2(s.s.x,s.s.y):dist(vec2(t.x,t.y))<vec2(s.s.x,s.s.y):dist(vec2(s.t.x,s.t.y)) then
                        s.t.x=t.x
                        s.t.y=t.y
                    end
                end
            end
            
            for j,s in pairs(sources) do
                createArc(s.s.x,s.s.y,s.t.x,s.t.y)
            end
        end
        if anchorTouches then
            for i,t in pairs(touches) do
                createArc(t.x,t.y,tsup[i].tstartx,tsup[i].tstarty)
            end
        end
        
        --draw an arc between each touch
        if connectTouches then
            for i,t in pairs(touches) do
                for j,f in pairs(touches) do
                    if j~=f then
                        createArc(t.x,t.y,f.x,f.y)
                        createArc(t.x,t.y,f.x,f.y)
                    end
                end
            end
        end
        
        for i=1,25 do
            peturb()
        end
        
        for i,a in pairs(arc) do
            if math.random(5)>1 then
                --do nothing - leave the arc blank to create flicker
            else
                local w=math.random(3)
                strokeWidth(w*5)
                stroke(arcCol.r//3,arcCol.g//3,arcCol.b//3,255)
                line(a.s.x,a.s.y,a.a.x,a.a.y)
                line(a.a.x,a.a.y,a.b.x,a.b.y)
                line(a.b.x,a.b.y,a.t.x,a.t.y)
                
                strokeWidth(w*3)
                stroke(arcCol.r,arcCol.g,arcCol.b,255)
                line(a.s.x,a.s.y,a.a.x,a.a.y)
                line(a.a.x,a.a.y,a.b.x,a.b.y)
                line(a.b.x,a.b.y,a.t.x,a.t.y)
                
                strokeWidth(w)
                stroke(255, 255, 255, 255)
                line(a.s.x,a.s.y,a.a.x,a.a.y)
                line(a.a.x,a.a.y,a.b.x,a.b.y)
                line(a.b.x,a.b.y,a.t.x,a.t.y)
                
            end
        end
        
        stroke(arcCol.r,arcCol.g,arcCol.b,255)
        fill(255)
        
        local tcount=0
        for i,t in pairs(touches) do
            tcount = tcount + 1
            fill(255)
            ellipse(t.x,t.y,10+math.random(5))
            
        end
        if tcount==0 then showLightning=false end
    end
end

function touched(t)
    
    if t.state==MOVING then
        --record path
        if tsup[t.id]~=nil then
            table.insert(tsup[t.id].path,{pos=vec2(t.x,t.y),age=ElapsedTime})
        end
    end
    if t.state==ENDED or t.state==CANCELLED then
        touches[t.id] = nil
        tsup[t.id]=nil
    else
        touches[t.id] = t
        showLightning=true
        
        --if there is no supplementary info associated with the current touch then add it
        if tsup[t.id]==nil then
            tsup[t.id]={tstartx=t.x,tstarty=t.y,starttime=ElapsedTime,path={}}
        end
    end
end

function peturb()
    for i,a in pairs(arc) do
        a.a.x=a.a.x+math.random(7)-4
        a.a.y=a.a.y+math.random(7)-4
        a.b.x=a.b.x+math.random(7)-4
        a.b.y=a.b.y+math.random(7)-4
    end
end

function createArc(sx,sy,tx,ty)
    --create a line with two bend points between (sx,sy) and (tx,ty)
    local mp1x=(sx-tx)/3
    local mp1y=(sy-ty)/3
    local mp2x=2*(sx-tx)/3
    local mp2y=2*(sy-ty)/3
    table.insert(arc,{s=vec2(sx,sy),a=vec2(sx-mp1x,sy-mp1y),b=vec2(sx-mp2x,sy-mp2y),t=vec2(tx,ty)})
end


@West Nice job. I especially like the globe option with connect touches.

@dave1707 thanks - was pretty pleased at how it turned out

Very nice. The next modification could be to have it spark more or have a parameter for it.

Fun! Good job.

VERY nice

nice!

@Timmy_theBarbarian @RonJeffries thanks. Looking back over old code after a period of time sometimes highlights things I might have done differently/better(?)

In this case, in the perturb function I’d now replace the:

…+math.random(7)-4

with

…+math.random(-3,3)

Doesn’t change the functionality, just improves the readability ever so slightly

Good effect! I like it!