Lightning Effect

Hello all I’ve been trying to create a lightning effect using the blender’s game engine.

So far, the approach I’ve been using is the render.drawLine() function. Basically I have two empties, one named “Start”, the other named “Finish”, and I’m using the drawLine() function to draw a line between these two points. What I want to do is get all the incremented points between “Start” and “Finish”, and then have them move perpendicular from the line at random points above and below it.

How do I do this?

Here’s what I have so far:

import bge
import random
from bge import logic
from bge import render

cont = logic.getCurrentController()
obj = cont.owner

start = logic.getCurrentScene().objects["Start"]
finish = logic.getCurrentScene().objects["Finish"]

dy = start.position.y - finish.position.y
dx = start.position.x - finish.position.x
slope = dy/dx
intercept = start.position.y-(slope*start.position.x)

def drawArc():
    render.drawLine( start.position, finish.position, [50, 0, 50])

logic.getCurrentScene().post_draw = [drawArc]

You’ll notice I already wrote the code to find the slope and the intercept of the line. So how do I write a function the starts a bunch of incremented points between “Start” and “Finish”, and then drawLine() between each point, and have the points move up and down randomly( each differently random from other points) perpendicular to the line between “Start” and “Finish”? This will hopefully give the effect of lightning.

Please help! And thank you!

I’ve made some progress… here’s what I have so far:

import bge
import random
from bge import logic
from bge import render

cont = logic.getCurrentController()
obj = cont.owner

start = logic.getCurrentScene().objects["Start"]
finish = logic.getCurrentScene().objects["Finish"]

dy = start.position.y - finish.position.y
dx = start.position.x - finish.position.x
slope = dy/dx
intercept = start.position.y-(slope*start.position.x)

points = []
r = start.position.x

while r <= finish.position.x:
    y = slope*r+intercept
    points.append([r, y, 0])
    r = r+1

length = int(len(points))

def drawLightning():
    for i in range(0, length-1):
        render.drawLine( points[i], points[i+1], [50, 0, 50])

logic.getCurrentScene().post_draw = [drawLightning]

Ok, I’ve ALMOST finished it… just a little more tweaking.

This script creates the effect of lightning.

import bge
import random
from bge import logic
from bge import render

cont = logic.getCurrentController()
obj = cont.owner

start = logic.getCurrentScene().objects["Start"]
finish = logic.getCurrentScene().objects["Finish"]

slope = (start.position.y-finish.position.y)/(start.position.x-finish.position.x)
intercept = start.position.y-(slope*start.position.x)

points = []

r = start.position.x

if start.getDistanceTo(finish) < 20:
    scale = int(20/start.getDistanceTo(finish))
elif start.getDistanceTo(finish) >= 20:
    scale = 1
    
while r <= finish.position.x:
    y = slope*r+intercept
    points.append([r+1/random.randrange(scale , scale+10), y+1/random.randrange( scale, scale+10), 1/random.randrange( scale, scale+10)])
    r = r+1

def drawLightning():
    for i in range(0, len(points)-1):
        render.drawLine( points[i], points[i+1], [50, 0, 50])

logic.getCurrentScene().post_draw = [drawLightning]

Hey, thats pretty cool.

One thing from testing: the objects have to be apart on both the X and the Y Axis or it will say, ZeroDivisionError: float division by 0. Also the lightning is only drawn along that plane.

but you probably already know this from how you wrote your code heh.

cool!!!
but the lighting not start from the Empty ?

i have attached the script in the Empty “Start”

hit = ud_ob.rayCast( own, own['enemy'], 2000.0, "hit", 1, 1, 0)
end = hit[1]
start = own.worldPosition

midpoint = [(start[0]+end[0])*0.5,(start[1]+end[1])*0.5,(start[2]+end[2])*0.5]
midpoint2 = [(midpoint[0]+end[0])*0.5,(midpoint[1]+end[1])*0.5,(midpoint[2]+end[2])*0.5]
midpoint3 = [(start[0]+midpoint[0])*0.5,(start[1]+midpoint[1])*0.5,(start[2]+midpoint[2])*0.5]


m1 = [midpoint[0] + GameLogic.getRandomFloat() -0.5,midpoint[1] + GameLogic.getRandomFloat() -0.5,midpoint[2] + GameLogic.getRandomFloat() -0.5]
m2 = [midpoint2[0] + GameLogic.getRandomFloat() -0.5,midpoint2[1] + GameLogic.getRandomFloat() -0.5,midpoint2[2] + GameLogic.getRandomFloat() -0.5]
m3 = [midpoint3[0] + GameLogic.getRandomFloat() -0.5,midpoint3[1] + GameLogic.getRandomFloat() -0.5,midpoint3[2] + GameLogic.getRandomFloat() -0.5]

end2 = [end[0] + GameLogic.getRandomFloat() -0.5,end[1] + GameLogic.getRandomFloat() -0.5,end[2] + GameLogic.getRandomFloat() -0.5]
end3 = [end[0] + GameLogic.getRandomFloat() -0.5,end[1] + GameLogic.getRandomFloat() -0.5,end[2] + GameLogic.getRandomFloat() -0.5]


start2= [start[0] + (GameLogic.getRandomFloat()*0.2) -0.1,start[1] + (GameLogic.getRandomFloat()*0.2) -0.1,start[2] + (GameLogic.getRandomFloat()*0.2) -0.1]
start3= [start[0] + (GameLogic.getRandomFloat()*0.2) -0.1,start[1] + (GameLogic.getRandomFloat()*0.2) -0.1,start[2] + (GameLogic.getRandomFloat()*0.2) -0.1]
                            
color = [ 0.7, 0.8, 1.0]
Rasterizer.drawLine( start, m1, color)
Rasterizer.drawLine( m1, end, color)
Rasterizer.drawLine( start2, m2, color)
Rasterizer.drawLine( m2, end2, color)
Rasterizer.drawLine( start3, m3, color)
Rasterizer.drawLine( m3, end3, color)

m1 = [midpoint[0] + GameLogic.getRandomFloat() -0.5,midpoint[1] + GameLogic.getRandomFloat() -0.5,midpoint[2] + GameLogic.getRandomFloat() -0.5]
m2 = [midpoint2[0] + GameLogic.getRandomFloat() -0.5,midpoint2[1] + GameLogic.getRandomFloat() -0.5,midpoint2[2] + GameLogic.getRandomFloat() -0.5]
m3 = [midpoint3[0] + GameLogic.getRandomFloat() -0.5,midpoint3[1] + GameLogic.getRandomFloat() -0.5,midpoint3[2] + GameLogic.getRandomFloat() -0.5]

start2= [start[0] + (GameLogic.getRandomFloat()*0.2) -0.1,start[1] + (GameLogic.getRandomFloat()*0.2) -0.1,start[2] + (GameLogic.getRandomFloat()*0.2) -0.1]
start3= [start[0] + (GameLogic.getRandomFloat()*0.2) -0.1,start[1] + (GameLogic.getRandomFloat()*0.2) -0.1,start[2] + (GameLogic.getRandomFloat()*0.2) -0.1]
                            
color = [ 0.5, 0.2, 0.8]
Rasterizer.drawLine( start, m1, color)
Rasterizer.drawLine( m1, end, color)
Rasterizer.drawLine( start, m2, color)
Rasterizer.drawLine( m2, end2, color)
Rasterizer.drawLine( start, m3, color)
Rasterizer.drawLine( m3, end3, color)               


Here’s the code I’m using for my Particle projection cannon effect, kind of like a lightning gun. it’s better if you’re able to make the effect repeat over a number of frames, as it is, it may bee too quick to see (using 2.49)

@Scar: Yea I’m going to fix it so it can draw the lightning anywhere between those two points no matter where the points are with relation to each other.
@Smoking_Mirror: Hmm… Your right, you’re code creates the effect but it is quite hard to see.

lacks the Z coordinate, for this seemed to me that would not start from the correct position, also
if Start.x it is too similar to Finish.x, the lightning segments was too linear

@MarcoTT: Yes, I made it so you can have “Start” and “Finish” anywhere with relation to each other… which fixes the linear problem.

Here’s the update!

 
import bge
import math
import random
from bge import logic
from bge import render

cont = logic.getCurrentController()
obj = cont.owner

render.showMouse(1)

start = logic.getCurrentScene().objects["Start"]
finish = logic.getCurrentScene().objects["Finish"]

d = 0

while d < start.getDistanceTo(finish):
    obj["increments"] = d
    d = d+1

dx = (finish.position.x-start.position.x)/obj["increments"]
dy = (finish.position.y-start.position.y)/obj["increments"]
dz = (finish.position.z-start.position.z)/obj["increments"]

if start.getDistanceTo(finish) < 20:
    scale = int(20/start.getDistanceTo(finish))
elif start.getDistanceTo(finish) >= 20:
    scale = 1
    
t = 0
points = []   
 
while t < obj["increments"]:
    x = start.position.x+dx*t+(1/random.randrange(scale , scale+10))
    y = start.position.y+dy*t+(1/random.randrange(scale , scale+10))
    z = start.position.z+dz*t+(1/random.randrange(scale , scale+10))
    points.append([x, y, z])
    t = t+1
    
for i in range(0, len(points)-1):
    render.drawLine( points[i], points[i+1], [1, 0, 1])