Light manager

Hello,

I have made a simple light manager script, it moves the lamps to empties at the nearest locations around the player.
script will explain itself, have fun with it.


#
# Light manager by Cotax
#


# on lamp(s) add property: light


# on placeholders(empties) add properties: 
# - light_source -> boolean -> True (on/off)
# - energy -> float -> 1.0
# - distance -> float -> 4.0
# - color -> string -> 111 (rgb)


#run scriptname.place_light  from any object you like with always(true)->python(module)


def first_run(cont):
    
    own = cont.owner
    
    own['lights']           = [obj for obj in own.scene.objects if 'light' in obj]
    own['light_sources']    = [obj for obj in own.scene.objects if 'light_source' in obj if obj['light_source'] == True]
    own['light_manager']     = True




def place_light(cont):
    
    own = cont.owner
    camera = own.scene.active_camera
    
    if not 'light_manager' in own:
        first_run(cont)       
    
    lights          = own['lights']
    light_sources   = own['light_sources']
    
    placeholders    = sorted(light_sources, key=lambda light_source: camera.getDistanceTo(light_source)) 
        
    i = 0


    for lamp in lights:


        if (i+1) <= len(light_sources):


            lamp.worldPosition  = placeholders[i].worldPosition   
            lamp.energy         = placeholders[i]['energy']
            lamp.distance       = placeholders[i]['distance']
            
            r = float(placeholders[i]['color_rgb'][0])
            g = float(placeholders[i]['color_rgb'][1])
            b = float(placeholders[i]['color_rgb'][2])
            
            lamp.color  = [r,g,b]
            
            i+=1


        #else:        
            #print('there are more lights then placeholders!')

Demo file(bge/upbge): (P to play, W to move)
light_manager.blend (489 KB)

For static light sources I would use mathutils KDTree or a 2dArray :smiley:

you are free to use whatever you like, i am using blender and blender alone. And this works for my needs, donā€™t need anything fancy just something that works. I share it for people who like it and or can use it.

also added first_run():, so you donā€™t scan every frame for the lights and light sources.

kdtree is in mathutils :smiley:

itā€™s part of blender, it has a nice method to get all points inside radius, and another function to get the closest N points.

https://www.blender.org/api/blender_python_api_2_70_0/mathutils.kdtree.html

just use your world vectors of objects rather then mesh data,

also itā€™s super handy for editing large meshes in the bge (you donā€™t need to itterate :slight_smile: )

That would probably be a lot faster but IMHO a really flexible light manager needs to be able to deal with moving lightsources and new light sources being added to the scene. Iā€™ve built mine in to my particles manager so I can have light emitting particles. Iā€™ve not found it to be that slow as long as I donā€™t have like a million light sources. :slight_smile:

@cotax

I usually use a for i in range(number of lights) loop rather than a for light in lights loop. Then it doesnā€™t matter if you have more lights than placeholders:

lights = [particle for particle in self.particles if particle.light]
light_casting = sorted(lights, key = lambda particle: self.get_light_distance(particle)) 
                        
for i in range(len(self.dynamic_lights)):
    lamp =  self.dynamic_lights[i]
    
    if i < len(light_casting):                
        light_particle = light_casting[i]
        lamp.worldPosition = light_particle.object_box.worldPosition.copy()                
        lamp.energy = light_particle.light_energy
        lamp.color = light_particle.light_color
        lamp.distance = light_particle.light_distance
        
    else:
        lamp.energy = 0.0       


I set up self.dynamic lights at the start, but get my list of hooks/placeholders each tic, in this case all my lights are particles (but not all my particles are lights :smiley: ).

for dynamic lights I do this

build list of dynamic lamps in scene

sort list each frame by distance

add lamps to the closest x hooks until distance is greater then visual range

break loop when distance is reached (since list is ordered by distance)

kdtree is in mathutils

Ok nice to know, i didnt now this and always tought that KDtree was an addon.

But for this its not needed (my case) due to i want to have control over it, spawning lights and removing them, playing actions etc (remember i have no clue how KDTree works) so i rather make my own script. and does not grab much reso. from anything.

I usually use a for i in range(number of lights) loop rather than a for light in lights loop. Then it doesn't matter if you have more lights than placeholders:

so you do actually the same, for i in range(light) or for light in lights. both ends up looping trough the lights.
the script i posted doesnā€™t care about having 100 lamps and only 2 place holders, thatā€™s why i count the light_sources, the script stops when all light sources are taken. That is why i have the else: commented out, its just a check that you can use, or use it to set the energy to 0 like you do.

but get my list of hooks/placeholders each tic

same i do it every tic aswell, t just depends on what you use it for, i updated the script to just scan it once at game start, for people who like that over scanning every tic. and everyone should be good enough to remove those parts to get it every tic.

Ah ok. I see. :slight_smile:
You can use the built in method for i in range() to do the same as you did there though. Itā€™s not really better but might be more recognizable to other people (like me) :stuck_out_tongue:

itā€™s similar to a script that i made:
original post from fisicomolon
there was a bug with loaded scenes that prevented new lights from being created, so i made a light manager to move lights around to objects with the correct properties. my method uses a navmesh and precreated lights.
dinamic loading and light manager blend
maybe you can use it to improve your script:

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

#scene
scene = bge.logic.getCurrentScene()
objList = scene.objects

sensa = cont.sensors[ā€œNavmeshā€]

if (sensa.positive):#I often run out of words to use for variables and use nonsense words to name them

 mames = sensa.hitObject
nomames = objList.get(mames['namesh'])
lightlist = [a for a in objList if 'LIGHT' in a]
luces = -1
for abc in lightlist:
    lightposition = [abc.worldPosition[0], abc.worldPosition[1], 0.0]
    elsiguiente = nomames.findPath(obj.worldPosition, lightposition)
    lightdistance = len(elsiguiente)
    luces += 1

     if (lightdistance < 4 and luces < 3):
        actu = 'Luz'+str(luces)
        LightNomi = objList[actu]
        LightNomi.worldPosition = abc.worldPosition
        LightNomi.color = [abc["RedC"], abc["BlueC"], abc["GreenC"]]
        LightNomi.distance = abc["DistanceC"]
        LightNomi.energy = abc["EnergyC"]

     elif (lightdistance > 4 and luces < 3):
        actu = 'Luz'+str(luces)
        LightNomi = objList[actu]
        LightNomi.worldPosition = [70.0, 70.0, 70.0]
        LightNomi.energy = 0.0

     elif (luces > 3):
        luces = -1

else:
bge.logic.sendMessage(ā€˜REMOVEā€™)

maybe you can use it to improve your script:

i donā€™t see anything in your script that can improve mine.

The script i posted is already with pre made lights, moving to nearby light_source(property), there is not a single need for a navmesh.

#edit
added demo file

2 Likes