get properties from the 3 nearest objects.

I am working on a little project where i have a bunch of empties scattered around my level for some data that i want to access from a script when the player or some other object is near.

I need to access the three nearest empties and get some data that i’ve stored in their game object properties.

I chose this way of storing data since i need to vary the density of data on different parts of my game and having precise control over their position in the 3d view is vital.

the data is going to be static so storing them in a data structure on game launch for fast access later is a good idea.

the object names of these empties start with “LP_”.

Below is an example of which object’s properties i would like to be able to access (from a script owned by the monkey, in this case)


Thank you very much in advance.

i would use the globalDict to store/save data, it’s meant for it. And it gives you easy acces to the data.

but this should do:

  • change PROPERTY to the ones in your ‘points’

def closest(cont):
    
    own     = cont.owner
    scene   = own.scene
    points  = [obj for obj in scene.objects if 'PROPERTY' in obj]
    
    if points:
        
        closest_points = sorted(points, key=lambda obj: own.getDistanceTo(obj))  
        
        point_1 = closest_points[0]
        point_2 = closest_points[1]
        point_3 = closest_points[2]   
        
        #do stuff with it
        point_2['property'] = 'abc123' 


run in module mode pointing to “Text.checkDistLP”:

import bge

scene = bge.logic.getCurrentScene()

## Find obj with "LP" as prefix ##
listLP = []
for obj in scene:
    split = obj.name.split("_")
    if split[0] == "LP":
        listLP.append(obj)

def checkDistLP(cont):  # Needs to be called from python controller
    global scene, listLP
    owner = cont.owner

    ## Sort list by Distance, game property "Dist" for access ##
    for obj in listLP:
        obj["Dist"] = owner.getDistanceTo(obj)
    listLP.sort(lambda x: x["Dist"])

    ## Update List of Top Closest, range loop for easy tweaking ##
    owner["NearLP"] = []
    for i in range(3):
        owner["NearLP"].append(listLP[i])

let it be said that python is slow for this kind of thing. untested, use with caution.

If you’ll have a lot of these around the map and they remain static (i.e. there position doesn’t change) then finding the distance to every one and figuring the top 3 would be quit expensive.

In that case using a KDTree would be the best option I think. Perhaps something like this :confused:

import bge
import mathutils

scene = bge.logic.getCurrentScene()


#### CREATING A LIST FOR THE OBJECTS #####


objList = []


for obj in scene.objects:
    if obj.name[0:3] == "LP_":
        objList.append(obj)
        
print("Lists Made")        


####### INITIALIZING KDTREE ######


kdTree = mathutils.kdtree.KDTree(len(objList))


for i in range(0, len(objList)):
    kdTree.insert(objList[i].worldPosition, i)
print("Tree Made")
   
###### USING KDTREE FOR POINT LOOKUPS ####
    
kdTree.balance()
print("Tree Balanced")


def mainLoop():   ## CALLED CONTINOUSLY THROUGH AN ALWAYS SENSOR


    goodLocs = kdTree.find_n(objList['Player'].worldPosition, 3) #returns the tuple of nearest 3 points to the players world position

    ## DON'T QUITE REMEMBER THE FORMAT OF THE TUPLES, BUT IT HAS THE INDICES i, WHICH YOU CAN USE TO            LOOK INTO THE OBJLIST AND GET THE PROPERTIES YOU WANT