Electricity effect

I took the kids to ascience museum recently and they had a few tablets set up with an electricity style effect. Thought I’d share mine here, still lots of stuff which could improve it!

https://imgur.com/a/QDtEEN7

ElectricityEffect.zip (1.8 KB)

-- ElectricityEffect

local touchArcs = {}
local contact = nil

-- Use this function to perform your initial setup
function setup()
    viewer.mode = FULLSCREEN
    screenBody = physics.body( POLYGON, 
                               vec2(0,0), 
                               vec2(0, HEIGHT), 
                               vec2(WIDTH, HEIGHT), 
                               vec2(WIDTH, 0) )

    screenBody.type = STATIC
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(0, 40, 50)

    -- This sets the line thickness
    strokeWidth(5)

    stroke(0, 178, 255)
    blendMode(ADDITIVE)
    
    for _, bolt in pairs(touchArcs) do 
        local points = computeLightningArc(bolt.origin, bolt.destination)
        for i = 1, #points do
            if i == #points then
                break
            end
        
            line(points[i].x, points[i].y, points[i+1].x, points[i+1].y)
        end
    end

    if contact ~= nil then
        ellipse(contact.x, contact.y, 200)
    end
end

function nearestScreenEdgeInDirection(origin, direction)
    -- Find a point really far outside the screen
    local outsidePoint = origin + direction * 10000

    -- Then raycast back in to find a point along the edge
    local result = physics.raycast(outsidePoint, origin)
    if result then 
        return result.point
    end

    return nil
end

function computeLightningArc(origin, destination)

    local points = {}
    local numPoints = 10.0
    local maxLength = origin:dist(destination)
    local maxStepVariation = 1.0
    local direction = (destination - origin):normalize()
    
    -- Calculate the initial step size between each point
    local stepSize = maxLength / numPoints
    
    table.insert(points, origin)

    for i = 1, numPoints do
        -- Randomize the step size for each point
        local stepVariation = (math.random() * 2 - 1) * maxStepVariation
        local currentStepSize = stepSize + stepVariation
        
        -- Calculate the distance from offset for the current point
        local distance = currentStepSize * i

        -- Calculate the angle multiplier using cosine interpolation
        local x = (i - 1) / (numPoints - 1)
        local angleMultiplier = 0.02 * math.cos(math.pi * x - (math.pi/2.0))
        
        -- Generate a random angle within a certain range
        local angle = (math.random() * 2.0 - 1.0) * math.pi * angleMultiplier
        
        local nextDirection = (direction * distance):rotate(angle)

        -- Calculate the position of the point
        local point = origin + nextDirection -- direction * distance -- + vec2(math.cos(angle), math.sin(angle)) * distance
        
        -- Add the point to the table
        table.insert(points, point)
    end
    
    return points
end

function touched(touch) 
    if touch.state == BEGAN then 
        for i = 1, 20 do 
            table.insert(touchArcs, {
                origin = nearestScreenEdgeInDirection(touch.pos, vec2(1,0):rotate(math.random() * 2 * math.pi)),
                destination = touch.pos
            })
        end
    elseif touch.state == CHANGED then 
        for _, bolt in pairs(touchArcs) do
            bolt.destination = touch.pos
        end
    else         
        touchArcs = {}
    end
end

3 Likes

@sim been away a while, but picking back up with Codea. Reminded me of this old thread: Lightning touch

1 Like

Hah I like yours better, nice work!

1 Like