Accessing objects after adding with scene.addObject()

Hi all,

I am kind of new to blender so I apologize in advance if this is a noob question. :slight_smile:

This is what I am doing:

from bge import logic
scene = logic.getCurrentScene()
newObject = scene.addObject(object, object, 0)

The thing is that here each object added to the scene at runtime has identical name as the previous one, and KX_GameObject has the name property as read only, so I cannot figure out how to distinguish these objects later on after they are added to the scene.

To summarize: Is there a way of securely distinguishing objects in a scene (similar to scene.objects[dynamic_name]) after they have been added to the scene using the addObject() method?

P.S. My current solution is to push these objects into a globally accessible associative array right after they are returned by addObject()… Any better ideas/solutions?

Thanks in advance

If someone has the same name as you … is he you or still another person?

Names are names … something that makes it easier for you as human to handle the objects they do not have direct access to. You do not need the name if you have the object.


first = scene.addObject(original, emitter)
second = scene.addObject(original, emitter)

print("Do first and second have equal names?", "yes" if first.name == second.name else "no")  
print("Are they the same objects?", "yes" if first is second else "no")
print("Are they even equal objects?", "yes" if first == second else "no")  

Therefore the name is just a little helper for you [in the past the name was indeed unique].

It is up to you what you do with the objects.

  • You can use and forget them,
  • you can store references in properties,
  • you can store references in modules,
  • you can store references in globalDict [bad idea - as it breaks save/load]
  • you can end the objects
  • you an store the references somewhere else as you do

so yes it is fine

Btw.
scene[name] is a naive implementation of an object search. It does not tell you if there are other objects with the same name.

Yep, all makes sense. It is a bit odd for me to be able to access objects by name and there are multiple objects with the same name… Having an associative array with items with same keys is not what I would expect… I expected this to be much more user friendly in blender.

Anyway, I have some ideas how to continue now. I haven’t had experience with saving/loading yet (I assumed you mean game save/load), but I will keep it in mind with the globalDict as you said.

Thanks for help :slight_smile:

Save/load always mean saving/loading game states (points, locations, health …).

These data needs to be able to get marshaled/un-marshaled (numbers, strings, lists, dictionaries).
Game objects can’t be marshaled, as there is no implementation on that. Therefore they are not supposed to be stored in globalDict unless you never want to use that for save/load via the build in save/loader operations or the save/load actuators.

Your way to store object references in an array sounds - at the first sight - a little bit strange. But that really depends on the situation.

The main question is: Who needs to know about exactly that object?
With the followup: How can the builder (the one how adds the object) tell the user (the one who want the object) what objects he created.

Ideally the builder and the user are the same … then they can communicate via variable:


addedObject = scene.addObject(..) # builder
...
doSomething(addedObject) #user

if the builder and user are not the same, you need to establish an interface (a way to access the object) between them as mentioned above.
The builder knows where to store and the user knows where the retrieve from. It is important that all participants know the shared storage.


def storeAddedObjectExample(addedObject):
   storage["addedObject"] = addedObject


def retrieveAddedObjectExample():
   return storage["addedObject"]

As written above, it is up to you what storage you choose (property, module, dictionary, list …).
[imagine storage is scene.objects :wink: - you see this is not sufficient as you can’t give a key, and the given key is not unique - as you already noticed]

Hint: when you store objects in storage that is accessible outside the scene, be aware that the content (the object) might be invalid. This can happen when you removed the scene where the object resides in. If you discover such situation I recommend to clean up the storage after/while you remove the scene. Alternatively you can backup by checking KX_GameObject.invalid.

Managed to make it work as I want :slight_smile:

Ok, so here is what I did:
(in the following text when I use the expression ‘group’ it means semantically a group, not a blender-related group term)

I have a character made. It consists of the following:
Character (group)

[INDENT=2]’ - - character_guide_frame
[/INDENT]
[INDENT=2]’ |__ character_armarute
[/INDENT]
[INDENT=2]’ | |__ character_mesh
[/INDENT]
[INDENT=2]’ |__ character_selection_indicator
’ - - character_tracker
[/INDENT]

This is the inheritance tree excluding the group.
I have the character on an inactive layer.
Each object has a property named ‘objectGroup’ (very important)
I wrote a script for object referencing (ObjectReferences.py)

During runtime, on middle mouse button a module is called which will add the character instance (semantically speaking) on the scene. Something like:

import ObjectReferences
gameObjects = {scene.objectsInactive['character_guide_frame_male'],\
                       scene.objectsInactive['character_tracker_male']}
                       
newGroup = ObjectReferences.duplicateGroup(scene, gameObjects, 'character_male')
newGroup['character_guide_frame_male'].actuators['Steering'].target = newGroup['character_tracker_male']
newGroup['character_guide_frame_male'].actuators['Steering'].navmesh = scene.objects['Navmesh']

New group is created and proper setup is made after that.

So each new character added to the scene is a referenced group of objects.
Each of the characters use python scripts for cursor tracking, activity state, etc…
Now in each of these scripts, I can easily determine all group members of a single object. For example:

from bge import logic
import ObjectReferences

def main():
    
    scene = logic.getCurrentScene()
    controller = logic.getCurrentController()
    
    group = ObjectReferences.getObjectGroupByMember(controller.owner)
    
    armature = group['character_armature_male']
    tracker = group['character_tracker_male']
    character = group['character_mash_male']

I had trouble attaching the ObjectReferences.py for… reference :slight_smile: I didn’t yet get time to familiarize fully with forum rules I admit, so here is the code:


# references to objects - UNUSED FOR NOW
objectReferences = {}
# references to object groups {'group_name' : {'object_name' : object}}
objectGroupReferences = {}

#group increments {'group_name' : 4}
groupIncrements = {}

# adds an object to objectReferences - UNUSED FOR NOW
def addObjectReference(object):
    print(object.name)

# adds an object to an object group within objectGroupReferences
# @param KX_GameObject  object
# @param string         groupName
def addObjectGroupReference(object, groupName):
    global objectGroupReferences
    # create a group if it doesn't exist
    if not groupName in objectGroupReferences:
        objectGroupReferences[groupName] = {}
    objectGroupReferences[groupName][object.name] = object
    
    # add all children recursively
    if object.children:
        for objectChild in object.children:
            addObjectGroupReference(objectChild, groupName)
    
# finds an object by ID from objectReferences - UNUSED FOR NOW
def findObjectById():
    print('object found by ID')
    
# returns a whole group of objects from objectGroupReferences using group name
# @param string groupName
def getObjectGroupByName(groupName):
    global objectGroupReferences
    if groupName in objectGroupReferences:
        return objectGroupReferences[groupName]

# returns a whole group of objects from objectGroupReferences using an object which is a member of the group
# @param KX_GameObject object
def getObjectGroupByMember(object):
    groupName = object['objectGroup']
    return getObjectGroupByName(groupName)

# deletes object by ID from objectReferences - UNUSED FOR NOW
def deleteObjectById():
    print('object deleted by ID')

# duplicates an object to the scene and sends it to objectReferences - UNUSED FOR NOW
# @param KX_Scene       scene
# @param KX_GameObject  object
# @param string         groupName
def duplicateObject(scene, object, groupName):
    newObject = scene.addObject(object, object, 0)
    addObjectReference(newObject, group)
    
    return newObject

# duplicates a group of objects to the scene and sends them all to group assignment and object reference storage with children recursively
# @param KX_Scene       scene
# @param KX_GameObject  object
# @param string         groupName
def duplicateGroup(scene, objects, groupName):
    global groupIncrements
    
    # if the group increment doesn't exist yet, create a new one
    if not groupName in groupIncrements:
        groupIncrements[groupName] = 0
    
    # increment the group name
    nextGroupName = groupName + '_' + str(groupIncrements[groupName])
    groupIncrements[groupName] += 1
        
    # main logic
    for object in objects:
        newObject = scene.addObject(object, object, 0)
        assignGroupName(newObject, nextGroupName)
        addObjectGroupReference(newObject, nextGroupName)
    
    return getObjectGroupByName(nextGroupName)

# assigns a group name to the object 'objectGroup' property and to all children recursively
# property must exist in order for this to work
# @param KX_GameObject  object
# @param string         groupName
def assignGroupName(object, groupName):
    object['objectGroup'] = groupName
    if object.children:
        for objectChild in object.children:
            assignGroupName(objectChild, groupName)

The code above is still missing the cleanup function for deleted objects, and also export and import functions for save game… I am yet to get to this part.

Feel free to comment the code, I will appreciate all negative comments, since they will help me learn :slight_smile:

@Monster, thanks a lot for your advices (disclaimer: I might have misunderstood some :))

Just a little update for anyone looking at previous comments that I posted:
This was for a learning practice of python syntax and blender environment. I completely reworked the code posted above for some semantic reasons and implemented a more OOP oriented solution, which I would much rather suggest.