Performance Question

Im building a game where i want the environment to disappear when the distance to the player is bigger than a certain number.

What is better performant:
To have one script cycle through all the objects in the scene every frame and check the distance to the player, would do this with: for obj in scene.objects: … (but that might me performant heavy)

Or have a script in each object with an always sensor (true level triggering with freq 10) check the distance? (im thinking always sensors in each object might be performant heavy)

Or is there an alternative?
Maybe a script in each object not with an always sensor (near sensor doesnt seem to work for me - only activates if player is in the upper hemisphere of the near sensor sphere)

or something like: for obj in scene.objects that are in a sphere with a 50 radius

There are some strong arguments on a single object handling the “object streaming”.

  • you want to process all objects the same way - so it is always the same operation, just on different objects
  • you want to apply individual processing on the single objects, rather than create behavior repetition

More design decisions:

[World management]

  • how do you want to handle object creation (what to create)?
  • how do you know where to place what object?
  • how do you add an object that represents an object that was removed before (e.g. a door should be at the same position as before)?
  • how do you ensure the status of an previously removed object appears to be plausible (e.g. a door is still open when it was open before)?

[Timing]

  • when is it needed to remove objects?
  • when is it needed to add objects?

[Out of sight processing]

  • how to process objects that are not present in the scene (e.g. a NPC walking from A to B … how do you know where he is after 2 minutes not watching it)?

Just some things to think about.

World Management:

  1. property in the object itself, i now did it so i have a script in one object set a property in all terrain objects, and in the terrain object there is an property sensor (changed) that sets the mesh. If the player is far enough away, the obj becomes an obj with one vertex (dot --> see question)

for obj in scene.objects: 
    if "SceneObj" in obj.name:
        if obj.getDistanceTo("Player") < 40:
            obj["near"] = 1
        elif obj.getDistanceTo("Player") > 40:
            obj["near"] = 0

  1. the object is already at the right place (when loading the game the empty spawns the object at the right position)

  2. havent thought about that yet, but i could make a different script that works with the global Dict for these types of objects

  3. same as 3

Timing:

  1. and 2. just before the player can see them (im making a 2d game so its a lot easier this way) - enemies should disappear before terrain so i’ll think about that too

Out of Sight Processing:
havent thought about that either (no answer comes to mind just now)

Question:
While using the Replace Mesh Actuator with replace Physics set to True, i noticed, that the physics mesh doesnt update when changing to the dot mesh. I also tried obj.reinstancePhysicsMesh() but that doesnt work either. Do you know how to solve this?

Nvm my question, solved it by deleting the object and spawning an empty there, and that empty spawns the obj again if the player is near enough

Consider that things like properties are only available when the game object exist ;).

Replacing objects with other objects is not really a good idea. You do not render empties, but you still need to process them. Imagine all these objects. The BGE will be busy by to managing them that there will not be enough time to process your game.

You could collect several (potential) objects and add them by a single property. This would reduce processing time quite a lot.

my setup is:


if owner["SceneObj"] == 1: #empty spawns obj and despawns
    add.object = owner.name.replace("Empty","")
    cont.activate(add)
    owner.endObject()
elif owner["SceneObj"] == 0: #obj spawns empty and despawns
    add.object = owner.name+"Empty"
    cont.activate(add)
    owner.endObject()

(changed the “near” property to the “SceneObj” property)

logic bricks in the object: property TAP “SceneObj” == 0 ---- script ---- add actuator
logic bricks in the empty: property TAP “SceneObj” == 1 ---- script ---- add actuator

at the time i have 5 objects that can be spawned (e.g. SceneObjGround), and if they despawn, they add an empty with “Empty” after their name (e.g. SceneObjGroundEmpty), so the name property doesnt have to be saved (changed that after my answer from before)

i get your point if you are saying, that if the scene gets bigger (larger levels), it will slow down the game. need to think of a better way to do that than to cycle through all objects every 10 frames… (see below)

what do you mean “add by a single property”?

check out KDtree :smiley:

http://www.pasteall.org/blend/42405

do you mean this?


co_find=own.worldPosition
    kd=own['KD']
    kd2=own['KD2']
    # Find the closest 10 points to the 3d cursor
    L=[]
    L2=[]
    for (co, index, dist) in kd2.find_n(co_find, len(own['LampsLocal'])-1):
        L2.append(index)

if so, then please explain what he does there :stuck_out_tongue: (e.g. couldnt find own[“KD”] in camera properties, and is kd2.find_n a function callable on any object?)

I constructed the kd tree when generating the level, one sec.

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

just adapt it to use object world positions instead of mesh vertex locations :slight_smile:

edit: Let me see if I have a simple example laying around*

ok i tried to just do it like in your tes111 file, but it doesnt seem to work

(that double indent is because i have another if before that)



if not "tree" in player.getPropertyNames():
        
        player["objnumber"] = 0
        for obj in scene.objects: #determine size
            if "SceneObj" in obj.name:
                player["objnumber"] += 1
        player["objlist"] = []

        size = player["objnumber"]
        kd = mathutils.kdtree.KDTree(size)
        
        index = 0
        for obj in scene.objects:
            if "SceneObj" in obj.name:
                pos = mathutils.Vector(obj.worldPosition)
                kd.insert(pos,index)
                index += 1
        
        kd.balance()
        player["tree"] = kd

    else:
        
        kd = player["tree"]
        
        find = player.position
        
        list = kd.find_range(mathutils.Vector(find),50)
        
        print(list)
        
        for (co, index, dist) in kd.find_range(mathutils.Vector(find),50):
            if index not in player["objlist"]:
                player["objlist"].append(index)



print(list) prints out an emtpy list [] in the console…

can you please help? :stuck_out_tongue:

Found the Problem: i built the kdtree before my other objects were spawned xdd

Pretty simple: Rather than checking and creating a single object you could check for an area and create all objects in that area. This way you have one check.

You could even go a step further. Rather than using a game object for checking (which is possible) you could use a python model (dict, kdtree, whatever) to perform a fast check for potential visibility.

^What Monster said. If I recall correctly, that’s more or less exactly how Morrowind/Oblivion/Skyrim load their outside regions.

Edit: And those games are pretty huge.

ok now finally managed to make a kdtree from object coordinates that searches the objects in 50 range, and managed to spawn/delete the objects. (most of the issues were because of my loading system)

the object coordinates are from global dict, so i used both a kdtree and the global dict :stuck_out_tongue:

thanks!