How to do lightning

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
Gunroar:Cannon()
Party member
Posts: 1088
Joined: Thu Dec 10, 2020 1:57 am

How to do lightning

Post by Gunroar:Cannon() »

Like the zap zap kind. Not a misspelling.
The closest thing I've found is this and I'm not really sire how it applies to love2d.
I'm guessing a crude way be to get 2 points (start and destination) and then create a bunch of lines (that fit into the width of end minus start) of different lengths and offsets to each other. But that's crude I think.

Any known nice way of implementing it. (Examples Nuclear throne, MDickie games (Extra Lives, BackWars))
Image
Not that sporadic but this is the gif I could find :)
The risk I took was calculated,
but man, am I bad at math.

-How to be saved and born again :huh:
User avatar
togFox
Party member
Posts: 779
Joined: Sat Jan 30, 2021 9:46 am
Location: Brisbane, Oztralia

Re: How to do lightning

Post by togFox »

While not at destination
Determine random segment length
Determine random angle
Draw segment
End

There is probably some recursion in there somewhere.
Current project:
https://togfox.itch.io/backyard-gridiron-manager
American football manager/sim game - build and manage a roster and win season after season
User avatar
darkfrei
Party member
Posts: 1178
Joined: Sat Feb 08, 2020 11:09 pm

Re: How to do lightning

Post by darkfrei »

:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
Gunroar:Cannon()
Party member
Posts: 1088
Joined: Thu Dec 10, 2020 1:57 am

Re: How to do lightning

Post by Gunroar:Cannon() »

So I tried with the posts I got + some ideas and now I have this...

Code: Select all

local function distance(x,y,xx,yy)
    return math.sqrt(((x-xx)^2)+(y-yy)^2)
end

rand  = function(x)
    return math.random(-x, x)
end
ldraw = function(x,y,xx,yy)
    local drawLine = love.graphics.line
    local len =  distance(x,y,xx,yy)
    local nlen = len
    
    local lines = {}
    local nn = 15
    
    local ox, oy = x, y
    
    local min, max = 3,13
    local mx = math.random(min,max)
 
    while nlen>0 do
        local t = len/(math.random(min,max))
        if t > nlen then
            t = nlen
        end
        
        nlen = nlen - t
        
        local done = nlen<=0
        local line = {
            x = ox,
            
            y = oy,
            
            x2 = ox+(done and 0 or rand(nn)),
            y2 = oy+t,0+(done  and 0 or rand(nn))
        }
        ox,oy=line.x2, line.y2
        
        lines[#lines+1] = line
         
    end
     
    
    for xi = 1, #lines do
        local l = lines[xi]
        drawLine(l.x, l.y, l.x2, l.y2)
    end
end

love.draw = function()
    ldraw(100,10,100,300)--startx, starty, endx, endy
    --love.graphics.line(200,10,200,300)
end
It's a little fast but I think it's pretty good. Not fancy but could work.
Though problems that I couldn't seem to fix:
1) As I see it I can only go one axis/direction at a time. Either a vertical path or a horizontal one whereas I'd like there to also be diagonal.

2) The last segment doesn't end at the intended destination.
Attachments
zap.love
(548 Bytes) Downloaded 106 times
The risk I took was calculated,
but man, am I bad at math.

-How to be saved and born again :huh:
User avatar
darkfrei
Party member
Posts: 1178
Joined: Sat Feb 08, 2020 11:09 pm

Re: How to do lightning

Post by darkfrei »

Gunroar:Cannon() wrote: Wed Jul 13, 2022 10:27 am 2) The last segment doesn't end at the intended destination.
This.
Make the line between start and end points.
Take a point between them and move it slightly. So you have two lines now, that are not on the straight line between start and end points.
For each line take any point plus/minus near the middle and move it slightly.
Ignore too short lines and repeat until result.

The animation is just random moving this all new middle points, respecting the sequence of it creation.
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
Gunroar:Cannon()
Party member
Posts: 1088
Joined: Thu Dec 10, 2020 1:57 am

Re: How to do lightning

Post by Gunroar:Cannon() »

darkfrei wrote: Wed Jul 13, 2022 10:48 am
Take a point between them and move it slightly.
Is that possible in love2d. Won't I need a mesh or something similar for that? My implementation consists of multiple lines starting at the end of the line that came before them(or the starting point if the line is the first one).
The risk I took was calculated,
but man, am I bad at math.

-How to be saved and born again :huh:
User avatar
pgimeno
Party member
Posts: 3549
Joined: Sun Oct 18, 2015 2:58 pm

Re: How to do lightning

Post by pgimeno »

Gunroar:Cannon() wrote: Wed Jul 13, 2022 11:09 am Is that possible in love2d. Won't I need a mesh or something similar for that?
A table. Think of lines in abstract, not as in love.graphics.line(). You'll get to the rendering part later.
User avatar
Gunroar:Cannon()
Party member
Posts: 1088
Joined: Thu Dec 10, 2020 1:57 am

Re: How to do lightning

Post by Gunroar:Cannon() »

pgimeno wrote: Wed Jul 13, 2022 12:02 pm
Gunroar:Cannon() wrote: Wed Jul 13, 2022 11:09 am Is that possible in love2d. Won't I need a mesh or something similar for that?
A table. Think of lines in abstract, not as in love.graphics.line().
Ahhh, yes! I'll try this.
The risk I took was calculated,
but man, am I bad at math.

-How to be saved and born again :huh:
User avatar
darkfrei
Party member
Posts: 1178
Joined: Sat Feb 08, 2020 11:09 pm

Re: How to do lightning

Post by darkfrei »

(not tested)

Code: Select all

local source ={x=0, y=0}
local target ={x=800, y=600}

local lightning= {
  source=source,
  target=target,
  mainLine={source, target},
}

function addPoint (lightning, index) -- index = math.random(#lightning.mainLine -1)
  local x1=lightning.mainLine[index].x
  local y1=lightning.mainLine[index].y
  local x2=lightning.mainLine[index+1].x
  local y2=lightning.mainLine[index+1].y
  local t = 0.25 + 0.5*math.random()
  local x = x1+ t*(x2 - x1)
  local y = y1+ t*(y2 - y1)
  x = x + 0.25*(y2 - y1)* (math.random()-1)
  y = y + 0.25*(x2 - x1)* (math.random()-1)
  table.insert (lightning.mainLine, index+1, {x=x,y=y})
end
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
Gunroar:Cannon()
Party member
Posts: 1088
Joined: Thu Dec 10, 2020 1:57 am

Re: How to do lightning

Post by Gunroar:Cannon() »

A little too fast (no delay implemented) but here's what I scrounged up (still haven't tested darkfrei's one yet, just wanted to see if this idea worked first).

Code: Select all

local function choose(t)
    return t[math.random(#t)]
end

local function point_distance(x,y,xx,yy)
    return math.sqrt(((x-xx)^2)+(y-yy)^2)
end

local function point_direction(x,y,xx,yy)
    return -math.atan2(yy-y, xx-x)
end

random_range  = function(x,y)
    return math.random((y and x or -x), y or x)
end

array_length = function(t)
    return #t
end


function lengthdir_x(spd, ang)
    return spd*math.cos(ang)
end

function lengthdir_y(spd, ang)
    return spd*-math.sin(ang)
end

function draw_set_alpha(a)
    local r,g,b = love.graphics.getColor()
    love.graphics.setColor(r,g,b,a)
end


function set_color(rr,gg,bb,aa)
    
    local r,g,b,a = love.graphics.getColor()
    
    if not rr then
        return r, g, b, a
    end
    
    love.graphics.setColor(rr,gg,bb,aa)
    return r,g,b,a
end

function draw_line_width_colour(x1, y1, x2, y2,size,color1,color2)
    local r,g,b,a = set_color(color1)
    local p = love.graphics.getLineWidth()
    love.graphics.setLineWidth(sizge or p)
    love.graphics.line(x1,y1,x2,y2)
    set_color(r,g,b,a)
    love.graphics.setLineWidth(p)
end

function draw_circle_colour(x,y,r,c1,c2)
    local r,g,b,a = set_color(c1)
    love.graphics.circle("fill",x,y,r)
    set_color(r,g,b,a)
end

local c_white = {1,1,1}
function draw_lightning(x1, y1, x2, y2, branches, size, color)
    --draw_lightning(x, y, x2, y2, branches, size, colour)
    --
    --draws a lightning bolt from the given starting location to the given end location
    --
    --x = x of the bolt's start
    --y = y of the bolt's start
    --x2 = x of the bolt's end
    --y2 = y of the bolt's end
    --branches = true or false, if the lightning bolt branches into multiple smaller ones
    --size = pixel width of the lightning
    --colour = colour of the glow
    --
    --amusudan 23/5/2016
    --
    --feel free to use this in your project!
    --
    local dir = point_direction(x1,y1,x2,y2)
    local length = point_distance(x1,y1,x2,y2) --error(length)
    local colour = color;
    local _size = size;
    --make different segments
    local point = {};
    point[1] = 0;
    local i2 = 2;
    for i = 1, length do
        if (math.random() < .06) then
            point[i2] = i;
            i2 = i2+1;
        end
    end
    point[i2] = length;-- error(point[#point-0])
    local points = array_length(point);
    --draw segments
    local i2 = 2
    local difx = 0;
    local difx2 = 0;
    local dify = 0;
    local ii =0
    local dify2 = 0;    --error(points)
    local dis = 7
    for i2 = 2, points do
        local i2 = i2+ii
        difx = random_range(dis)
        dify = random_range(dis)
        local xx = x1 + lengthdir_x(point[i2 - 1],dir);
        local yy = y1 + lengthdir_y(point[i2 - 1],dir);
        local xx2 = x1 + lengthdir_x(point[i2],dir);
        local yy2 = y1 + lengthdir_y(point[i2],dir); --error(xx2..","..x1..",y2:"..yy2..","..y1..","..dir..","..point[i2])
        --create a branch
        if (math.random() < .15 and branches) then
            local bdir = dir + choose({random_range(-45,-25),random_range(45,25)});
            local blength = random_range(5,30);
            draw_lightning(xx + difx2, yy + dify2, xx + difx2 + lengthdir_x(blength,bdir), yy + dify2 + lengthdir_y(blength,bdir), false, _size, colour)
        end
        --draw the glow of the lightning
        set_color(1,1,1,.1)
        
        draw_line_width_colour(xx + difx2,yy + dify2,xx2 + difx,yy2 + dify, size + 5,colour,colour);
        draw_line_width_colour(xx + difx2,yy + dify2,xx2 + difx,yy2 + dify, size + 3,c_white,c_white);
        draw_line_width_colour(xx + difx2,yy + dify2,xx2 + difx,yy2 + dify, size + 1,c_white,c_white);
        draw_set_alpha(1)
        --draw the white center of the lightning
        draw_line_width_colour(xx + difx2,yy + dify2,xx2 + difx,yy2 + dify, size,c_white,c_white);
        --ii = ii+1;
        difx2 = difx;
        dify2 = dify;
    end
    --draw a glowing circle
    if (branches) then
        draw_set_alpha(.91);
        draw_circle_colour(x1,y1,size + 2.5,colour,colour,false);
        draw_circle_colour(x1,y1,size + 1.5,colour,colour,false);
        draw_circle_colour(x1,y1,size + .5,colour,colour,false);
        draw_set_alpha(1);
        draw_circle_colour(x1,y1,size,c_white,c_white,false);
    end
end

love.draw = function()
    love.graphics.scale(.5)
    --love.graphics.translate(0,500)
    local x = 100
    local y = 100
    local xx = 150
    local yy = 300

    --draw_line_width_colour(x,y,xx,yy,1,{0,1,0})
    draw_lightning(x,y,xx,yy,true,10)
end
But it works, can even branch :P
The risk I took was calculated,
but man, am I bad at math.

-How to be saved and born again :huh:
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 88 guests