using python to copy an object change a "name" property failure

Ok so here is the problem. I have a scene with some basic building blocks. Using the below python code, I allow the player to copy the object they are looking at, and put it at the exact same position as the original. Then they can move the new copied object wherever they want. As part of this code I want to change a property inside this new copy of the original from “Pillar1” to “Pillar1 2” to signify that it is different than the original since the KXgame_object name doesn’t change when the new object is created, even though it has the same actual name.

Now, the problem is that when I let go of this new block and look away, when I come back to move it again, it has reverted back to the original name “Pillar1” inside the property. Now, I also know that this name property does in fact get changed because of the print statement just after I rename it. I think this has something to do with the fact that the new block was created post game startup.

So, why is this property not permanently changed? Also, is there some way to change the KXgame_object name in the process of adding the new object?

scene = GameLogic.getCurrentScene()
SceneObjectsList = scene.objects

if RaySensor.positive:
	BlockKX = RaySensor.hitObject
	BlockName = BlockKX['BlockName']
	print BlockName

if CopyButton.positive and RaySensor.positive:
	BlockKX = RaySensor.hitObject
	BlockName = BlockKX['BlockName']
	print BlockName
	AddObj.object = BlockKX
	AddObj.instantAddObject()		
	NewGuyKX = AddObj.objectLastCreated
	for j in SceneObjectsList:
		print "Does j-item:",j,"=",NewGuyKX
		if j == NewGuyKX:
			print "YES! - ",j,"=",NewGuyKX
			NewGuyKX.position = j.position
			Mynum = ScObj.count(j)
			j['Bname'] = str(j) + " " + str(Mynum + 1)
			print "ScObj  KX name:",j, "Bname:", j['Bname']
			break 

The real reason this is an issue is because I want the player to be able to save their work. I am doing this via pickle, or rather blendenzo’s ad-lib version of it. This method basically creates a txt file that I am writing programmatically using the names of each block and and their position. So when loading from this txt file, I need to know the difference between Pillar1 and Pillar1 even though technically blender does not (i.e. having two objects with the same name inside the scene.objects list).

Thanks for your insights
-Scifi-aholic-

I have just started python so I may have no idea what I am talking about.
It might have something to do with this line.
AddObj.instantAddObject()

If this creates an instance of the object then the object is really just an “instance” of the original, instead of a new object. which might explain why blender does not know the difference between the two.

These links might help.
http://www.tutorialsforblender3d.com/GameModule/ClassKX_Scene_1.html
http://download.blender.org/documentation/NaN_docs/BlenderGameReference/actuators.html

Thanks John316,
The instance thing makes sense, though a cursory read of the API on the add object actuator doesn’t mention it. Also, I looked up the two links you gave me; going through the scene game type did yield a much more concise version of creating the object, but still I can’t seemingly change that property value. Could it be that the new object is only a copy of the mesh of the previous block, and does not have that property? Or maybe somehow the object[‘propname’] = newvalue is treated as a local in this particular situation.

Well we need a fred! (fairly reliable expert dude, or the guy who fixes my car who’s name is fred :D)

Hi scifi-aholic,

if you want to store the objects states to a file and restore it later, you can check the SaveLoader. It adds objects that where instanciated as well. Check the file there is a demo scene.

Instances share the same mesh data, but have their own object instance (local version of the property dictionary).

You can check the properties of all objects with a specific name with this function:


def printObjects(objectName):
    for obj in GameLogic.getCurrentScene().objects:
        if obj.name == objectName:
            print obj.name
            print "props:"
            for propName in obj.getPropertyNames():
                print "	",propName+":",obj[propName]

I hope it helps

Thanks Monster,

That looks like quite the master piece you have going there. Forgive me but I am still quite simple when it comes to scripting, and therein my inability to simply read through your code. Obviously I could just give you credit and copy in your code to my blend, but really the reason I am asking my question in the first place is to learn by doing. Frankly, trying to read through all that was a little more than overwhelming, at least for the moment. I want you to understand that I am not trying to just solve a problem but am trying to grasp at understanding the framework of blender. Like having a woodshed of new tools, and gradually taking them all out, one by one, and exploring their uses.

So, I was wondering if I could rephrase my question: could you tell me how to work with this whole instance thing in blender? Or maybe could you refer me to someplace that does? I think I understand the concept of it but there must be a way of interacting with these “instances” better than how I am going about it now. Lets start with properties. I still don’t know how to interact with an object’s instance’s properties obviously from my above method, seeing as it fails and is flawed somehow.

Thanks again,
Scifi-aholic

alright, so apparently it isn’t possible to rename a property in an object immediately after it’s creation like I was doing. You have to wait until the script has finished executing or use another outside script to do the renaming. The later is what I did. As you can see, I am using it almost as a function call.

scene.addObject(My_KX_object,My_KX_object,0)
Blender.Run("renameProp")

# renameProp script =========================================
objlist = []
objnumlist = []

for obj in scene.objects:
	if obj.has_key('Bname'):
		try: 
			index = objlist.index(obj.name)
			objnumlist[index] += 1
			obj['Bname'] = str(obj) + " " + str(objnumlist[index])
		except ValueError:
			objlist.append(obj.name)
			objnumlist.append(0)
			obj['Bname'] = str(obj) + " " + str(0)
		print "Object:", obj, "-  Bname:", obj['Bname']
# =======================================================

Hello scifi-aholic,

You’re method seems tome a little bit complicated. And do not use module Blender. I will not be available at standalone.

renaming properties makes no sense, but you can copy a properties and delete the old one. The result is the same.

Your script seems to assign a property called “Bname” with a unique value to the objects. I suggest a more simpler method.
Method 1:
When using AddObject call Util.addObj (most likely at the emitter object): sensor — Python controller (module: Util.addObj)
Method 2:
Assigned to the template object! This ensures after the object is created the “id” will be set within the next frame.
sensor Always (no pulses) — Python controller (module: Util.setId) + Priority flag enabled!
Util.py:


import GameLogic

# prepare a storage that keeps track of the next available Id
GameLogic.nextAvailableId=0

Pid = "id" # define the name of the ID property here (easier for a later change)

def assignNewId(obj):
   if not Pid in obj: # no Id assigned?
        obj[Pid] = GameLogic.nextAvailableId # assign a free Id
        GameLogic.nextAvailableId += 1 # store the next free Id

#=== callable by Python Module controller
def setId(cont):
   assignNewId(cont.owner)

def addObj(cont):
    scene = GameLogic.getCurrentScene()
    cube = scene.objectsInactive["OBCube"] # apply your logic here to determine the template object
    
    newObj = scene.addObject(cube, cont.owner)
    assignNewId(newObj)
    

I hope it helps