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!
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