How to add and delete objects based on distance from the player?

KD_Tree_example_loading_bubble.blend (769.2 KB)


this randomly generates a bunch of locations - you could use a look up table / dictionary or something instead as well

1 Like

KD_Tree_example_loading_bubble_with_terrain_planes_Start.blend (872.6 KB)

this picks from 4 types of objects and randomly spawns them per tile - and also spawns a tile

you could use perlin noise instead of random - and use perlin noise to deform the terrain too

1 Like

Thank you for your help, this looks really impresive.
Can you set it up for the player to have this bubble?
I’m not sure how far can this grid expand without loosing the performance.
What I wanted to achieve is:
Bubble_001 Bubble_002
To have Empty objects on map instead of a static objects.
Then activate the static objects when you are in range.
I guess it’s similar to what you are suggesting but it seems this calculate the whole map.

yeah you can do this - so when I build the KDTree I do it from a grid - / list

you can do
#scrape scene objects and get all objects with the property ‘Spawn_Location’

obList =[]
for obj in own.scene.objects:
    if 'Spawn_Location' in obj:
        obList.append(obj)

and use this list instead

when I get a chance I will set it up.

Since the grid didn’t work for me yet, I’ve been trying something else.
I’m not sure if this would be fast for processing or not.

for obj in scene.objects:
    if "Box" in obj:
        dist = obj.getDistanceTo(player)
        obj['dist'] = dist
        if obj['dist'] < 5 and obj['distState'] == False:
            addBox = obj.scene.addObject('Box', obj, 0)
            addBox.setParent(obj)
            obj['distState'] = True
        elif obj['dist'] >= 5 and obj['distState'] == True:
            for child in obj.children:
                if "BoxSpawned" in child:
                    child.endObject()
            obj['distState'] = False

The Empty objects have a Box property and when you are near them, they’ll spawn static objects for a collision. If you are far enough, the static objects are deleted.

you can use a collision sensor / objects on a collision layer for this (empty with a sphere bound for instance)

however this does not scale -

we need to store multiple objects data in a single empty and then spawn / despawn them

we can store a bunch of data in a string and use ast.literal_eval()

to convert it back into a list of lists or a list of tuple etc

what you could do is make a ‘converter’ in bpy - that takes a scene and stores it in empties

Yes, but I didn’t want to use physics for this. I wanted to apply the static objects only when you are at a certain distance from the Empty.
I’m testing my game on an old notebook and less static objects mean better performance.

yes - so instead we use the kdtree - one sec

KD_Tree_example_loading_bubble_with_terrain_empt_store_data.blend (884.6 KB)

this uses kdtree

Thank you, I’ll try it later.
The thing is I’m not using UPGE so this all doesn’t work right away.

should work in 0.2.5 - (just append everything into a new blend)

1 Like

Thank you, it looks really interesting.

keep in mind this works best for ‘kit’ - where all the object in the kit are using 1 material
you can spawn a cluster like this - and then use KX_BatchGroup to batch the draw calls in upbge - making the game render much much faster.

if it’s just a few objects it does not make sense - but like a whole little scene that batches is good
(like a 20+ objects)

1 Like

It has been a while since I’ve replied last time. I’ve been trying several methods to load and unload the objects but the KDtree you’ve mentioned seems to be the most interesting one.
The problem is that you’ve made an example on the newest Blender version with UPBGE. I on the other hand have been using Blender 2.79.
I’ve managed to make it work on Blender 2.79 by appending the objects.

How can I change the properties of an object that is appended to the loading grid?
EDIT: Ok, I’ve managed to add a property for the object.

stored[i].append( ( 'Object', (x3,y3,0), value ) )

and then I had to write this for some reason:

added['Property'] = ob[-1]

What I was expecting was to write ob[2] but that didn’t work.

Also what happens to the object if you move it?
The individual segements of the grid are created from bottom to top. Is there a way to change it to from left to right and start the grid from x0 and y0?

here is an example on how to do this in a flexible way.

here gets all the objects in the game scene who got a game property “someproperty” stored in a custom class that keep track of all data related to that object (this could be anything).

# init.py
import bge
import mathutils

cont = bge.logic.getCurrentController()
own = cont.owner

# a class to store relevant data
class GameObject:
    def __init__(self,name,position):
        self.name = name # name of object to spawn.
        self.position = position
        self.orientation = [[1,0,0],[0,1,0],[0,0,1]]
        self.scale = [1,1,1]
        self.color = [1,1,1,1]
        self.objref = None
        

own["objects"] = []


for obj in own.scene.objects:    
    if "someproperty" in obj:

        name = obj.name.split(".")
        
        # create instance of class GameObject and store relevant data
        gameobject = GameObject(name[0],list(obj.worldPosition))
        gameobject.orientation = [list(obj.worldOrientation[0]),list(obj.worldOrientation[1]),list(obj.worldOrientation[2])]
        gameobject.scale = list(obj.worldScale)
        gameobject.color = list(obj.color)
        # add the created gameobject to a list 
        own["objects"].append(gameobject)
        
        # end KX_Gameobject from scene
        obj.endObject()
        
        
own["KDtree"] = mathutils.kdtree.KDTree(len(own["objects"]))


for index,gameobj in enumerate(own["objects"]):
    own["KDtree"].insert(gameobj.position,index)
   
    
own["KDtree"].balance()

and here you draw or remove based on the distance to the player Cube

# draw.py
import bge

cont = bge.logic.getCurrentController()
own = cont.owner
playerpos = own.scene.objects["player"].worldPosition
placer = own.scene.objects["placer"]

maxdist = 40
mindist = maxdist - 2

result = own["KDtree"].find_range(list(playerpos), maxdist)
        
if result:
    for item in result:
        co,index,dist = item
        if dist < mindist:
            if own["objects"][index].objref == None:
                placer.worldPosition = own["objects"][index].position
                
                obj = own.scene.addObject(own["objects"][index].name,"placer",0)
                
                obj.color = own["objects"][index].color
                obj.worldOrientation = own["objects"][index].orientation
                obj.worldScale = own["objects"][index].scale
                
                own["objects"][index].objref = obj
        else:
            if own["objects"][index].objref != None:
                own["objects"][index].objref.endObject()
                own["objects"][index].objref = None
            

Demo blend to try it in action (BGE 2.79 version)
dynamic.blend (1.5 MB)

1 Like

a KDTree is best used for static objects, unless you want to recreated it every time a object moves ( not the best way to do things)

Thank you for your suggestion.
How is this code taxing on processing? It still adds objects based on distance.

Is it possible to make the bubble around the player another shape than a circle? Can you make it a square or a triangle?

I’ve tried to create a map with the KDtree and I have used your script for it. It works great but I’d like to ask for help if you have time.
This is the file I’ve been working on: KDTree_002.blend (703.8 KB)

The map is a 100 x 100 grid and I have two bubbles around the player.
The first one is for physics and the second one is for high polygon graphics.
What I wanted to do is to have the rest of the map, to be created for the low poly graphics.
Right now it adds a green plane if you leave a place where the bubble was before.
That green plane is a placeholder for the low poly objects.
If there was a way to place the green planes at the start inside the grid. Like the bubble around the player but add it to the whole level.
Then delete the green planes when the bubble overlaps those green planes.

Basically for it to look like this in the end: