Problems getting object names - python

I have a blender scene with a few objects, I would get the object name when mouse is over one of them, setting a property of an empy object.
What I have now is just the list of the scene objects. What can I do?
import GameLogic
cont=GameLogic.getCurrentController()
obj=cont.getOwner()
print obj
objlist=GameLogic.getCurrentScene().getObjectList()
print objlist
sen=cont.getSensor('sensor')
if sen.isPositive():
print objlist[0]
PropName=.... #how to set this with the object name?
print PropName

I suppose you can use SCA_MouseSensor sensor and its hitObject property to get the last object the mouse was over. It returns None or an object of KX_GameObject type. When you get it, you can use its name property to get the name (or just access other properties of the object).
Reference links:
SCA_MouseSensor in API documentation
KX_GameObject in API documentation
I haven't tested this yet, but I suppose it should work when used in Blender Game Engine. The information I've found refers to Blender 2.59, so make sure use are using appropriate version of the application.

In order to be useful to someone else, I answer my own question. What I've done was to set a mouse over sensor to each objects within the scene and that add a python script controller, in order to set a property of the scene Empty object.
import GameLogic
import Rasterizer as r
r.showMouse(1) #just in order to get the mouse visible within the game engine
print 'SetProperty.py\n'
cont=GameLogic.getCurrentController()
obj=cont.getOwner()
emptyOb = GameLogic.getCurrentScene().getObjectList()["OBEmpty"]
emptyOb.EmptyProp=obj
print 'object name, within emptyProp: ', emptyOb.EmptyProp

Related

Finding blocks with Item Method in AutoCAD

I am trying to automate some tasks in AutoCAD using Python and pywin32. AutoCAD version is 2018.
I have tried to follow the method shown here in the AutoCAD documentation: http://help.autodesk.com/view/ACD/2018/ENU/?guid=GUID-A5B6ACC4-DCD8-4FE2-AB06-D3C3C349475B
I want to select a specific block, and then edit some of its attributes.
My code:
acad = win32com.client.Dispatch("AutoCAD.Application")
acad.ActiveDocument = acad.Documents.Open(os.path.normpath(os.path.join(baseDir,filename)))
time.sleep(2)
doc = acad.ActiveDocument # Document object
entity = doc.Blocks.Item('TTLB ATTRIBUTES')
print entity.Name
print entity.HasAttributes
This correctly prints the block name, but attempting to access the HasAttributes property causes this error:
AttributeError: Item.HasAttributes
If I change the code to simply walk through all the objects, then it works:
acad = win32com.client.Dispatch("AutoCAD.Application")
acad.ActiveDocument = acad.Documents.Open(os.path.normpath(os.path.join(baseDir,filename)))
time.sleep(2)
doc = acad.ActiveDocument # Document object
for entity in doc.PaperSpace:
if entity.EntityName == 'AcDbBlockReference':
if entity.Name == 'TTLB ATTRIBUTES':
print entity.Name
print entity.HasAttributes
I don't understand why the second one works and the first one doesn't. When I read the documentation, it seems like they should both be finding the same object.
When invoking the Item method on the Blocks collection, you are obtaining a Block Definition object (AcDbBlockTableRecord), which is a container for the set of objects constituting the block geometry and does not have the HasAttributes property.
Whereas, when iterating over the objects held by the Paperspace Collection (which is itself a type of Block Definition), you are encountering Block Reference objects (AcDbBlockReference), which do have the HasAttributes property.
Consider that the Block Definition is essentially the "blueprint" for the block, and each Block Reference is an instance displaying the objects found within the block definition, at a specific position, scale, rotation & orientation in the drawing.
Attributes also have Attribute Definitions within the Block Definition, and corresponding Attribute References attached to each Block Reference. Such attribute references may then hold different text content for each block reference inserted in the drawing.
Aside, interestingly, attribute references may also be programmatically attached to a block reference independently of the block definition, however, this is not permitted when operating AutoCAD using the standard out-of-the-box front end.
With the above information, you will need to iterate over the block references found within the relevant layout container, and, if the block reference meets your criteria, iterate over the set of attribute references held by the block reference (which you can obtain using the GetAttributes method), changing the Textstring property of those attributes which meet your criteria.

How to duplicate the same object in Python with BGE?

When i want to load an object and draw it in the scene, i do :
scene = bge.logic.getCurrentScene()
path = "c:\\.....\\name.blend"
bge.logic.LibLoad(path,'Scene')
and after, I use worldPosition to change the object position.
But now, I want to use the same object many times.
How can I duplicate the same object, because i can't reload the same object ?
Thanks
Best regards
The Edit Object actuator has an option to Add object.
By connecting this to a sensor you can control placement of new objects. An empty is a good place to use this as it allows you to position the empty where you want to add the object.

How to see all attributes of a node in Maya?

I'm trying to update some attribute values in Maya via code and I'm having a really tough time accessing them.
I need the attributes displayed name, (I'm pretty sure this is supposed to be their 'Nice Name'), but I can't seem to get them in any way. Using listAttr or using OpenMaya's MFnAttribute both don't give me what I want - they pass back long names and short names and cleaned up 'Nice Names' but none of those are the displayed UI name to the attributes.
As an example my node contains an attribute with the name 'Horizontal Damping Factor' under a drop down titled 'Advanced Anchor Controls.' When I query the node for a list of attribute nice names I get the similar name 'Anchor HDamping Factor', but that is not the displayed name. This is true for 23 other attributes as well.
Do you have any ideas on what's going on?
(All of these attributes are located in fields two dropdowns deep as well, is that a problem?)
EDIT: It's definitely because the attributes are two dropdowns deep... I still have no idea what these dropdowns are called or how to access the attributes contained inside of them.
EDIT 2: Well, I was wrong, the name of the attribute IS different from the name that's displayed, (when I adjust a slider the editor window shows the name of the value I just changed, which is different from the displayed name, and it's not just a 'Nice' name version of it either.) Still trying to figure this out.
EDIT 3: Not sure how clear this is but it shows the discrepancy between the UI label of the attribute and the 'Nice Name.' There is no 'Horizontal Damping Factor' in the list of attribute names.
FINAL EDIT: Looks like it's not possible to change the value of an attribute by querying the UI name if the attribute was given a different UI name then the authoritative name on creation. Created my own mappings in code instead.
The authoritative names are the ones in listAttr; the names you see in the UI are not reliable because an AETemplate can override them in any way it wishes. The AE often presents fake attributes which are used to calculate the real values -- for example, cameras have an angleOfView in the attribute editor, but setting it actually changes the focalLength attribute; there is no angleOfView on the camera node.
So, you may need to do some detective work to figure out what the visible UI is really doing. Playing with the sliders and watching the history is the usual first step.
FWIW
dict(zip(cmds.listAttr(), cmds.listAttr(sn=True)))
will give you a dictionary mapping the long names to the short names, which can be handy for making things more readable.
If you knew the longName of the attribute in question and the name of the node it is part of, you can use attributeQuery with the longName, shortName or niceName to get the it's long name, short name and nice name respectively.
From what I understand from your question, you want to be able to look at ll of this information for all the attributes of the node so you can make the right decision of which attribute to choose to do what you are doing. Here is a quick script I wrote, a simple query of sorts, to give you just that: (Interspersed generously with explanation as comments)
import maya.cmds as cmds
def printAttributes(node, like=''):
''' Convinience function to print all the attributes of the given node.
:param: node - Name of the Maya object.
:param: like - Optional parameter to print only the attributes that have this
string in their nice names.
'''
heading = 'Node: %s' % node
# Let's print out the fancy heading
print
print '*' * (len(heading)+6)
print '** %s **' % heading
print '*' * (len(heading)+6)
# Let's get all the attributes of the node
attributes = cmds.listAttr(node)
# Let's loop over the attributes now and get their name info
for attribute in attributes:
# Some attributes will have children. (like publishedNodeInfo)
# We make sure we split out their parent and only use the child's name
# because attributeQuery cannot handle attributes with the parentName.childName format.
attribute = attribute.split('.')[-1]
# Let's now get the long name, short name
# and nice name (UI name) of the atribute.
longName = cmds.attributeQuery(attribute, node=node, longName=True)
shortName = cmds.attributeQuery(attribute, node=node, shortName=True)
niceName = cmds.attributeQuery(attribute, node=node, niceName=True)
# if we the 'like' parameter has been set, we'll check if
# the nice name has that string in it;
# else we skip this attribute.
if like and like.lower() not in niceName.lower():
continue
# Now that we have all the info we need, let's print them out nicely
heading = '\nAttribute: %s' % attribute
print heading
print '-' * len(heading)
print 'Long name: %s\nShort name: %s\nNice name: %s\n' % (longName,
shortName,
niceName)
if __name__ == '__main__':
# Let us get a list of selected node(s)
mySelectedNodes = cmds.ls(sl=True)
# Let us do the printAttributes() for every selected node(s)
for node in mySelectedNodes:
# Just for example, just printing out attributes that
# contain the word 'damping' in their nice (UI) name.
printAttributes(node, like='damping')
Note that we use the command listAttr() to get a list of all the attributes of the node. Note that we can also use attributeInfo() to get a list of the attributes also. The advantage of attributeInfo() over listAttr() is that attributeInfo() has more filter flags to filter out the list based on various parameters and properties of the attributes.
It is worth it to go check out the documentation for these:
attributeQuery
attributeInfo
listAttr

python load from shelve - can I retain the variable name?

I'm teaching myself how to write a basic game in python (text based - not using pygame). (Note: I haven't actually gotten to the "game" part per-se, because I wanted to make sure I have the basic core structure figured out first.)
I'm at the point where I'm trying to figure out how I might implement a save/load scenario so a game session could persist beyond a signle running of the program. I did a bit of searching and everything seems to point to pickling or shelving as the best solutions.
My test scenario is for saving and loading a single instance of a class. Specifically, I have a class called Characters(), and (for testing's sake) a sigle instance of that class assigned to a variable called pc. Instances of the Character class have an attribute called name which is originally set to "DEFAULT", but will be updated based on user input at the initial setup of a new game. For ex:
class Characters(object):
def __init__(self):
self.name = "DEFAULT"
pc = Characters()
pc.name = "Bob"
I also have (or will have) a large number of functions that refer to various instances using the variables they are asigned to. For example, a made up one as a simplified example might be:
def print_name(character):
print character.name
def run():
print_name(pc)
run()
I plan to have a save function that will pack up the pc instance (among other info) with their current info (ex: with the updated name). I also will have a load function that would allow a user to play a saved game instead of starting a new one. From what I read, the load could work something like this:
*assuming info was saved to a file called "save1"
*assuming the pc instance was shelved with "pc" as the key
import shelve
mysave = shelve.open("save1")
pc = mysave["pc"]
My question is, is there a way for the shelve load to "remember" the variable name assotiated with the instance, and automatically do that << pc = mysave["pc"] >> step? Or a way for me to store that variable name as a string (ex as the key) and somehow use that string to create the variable with the correct name (pc)?
I will need to "save" a LOT of instances, and can automate that process with a loop, but I don't know how to automate the unloading to specific variable names. Do I really have to re-asign each one individually and explicitly? I need to asign the instances back to the apropriate variable names bc I have a bunch of core functions that refer to specific instances using variable names (like the example I gave above).
Ideas? Is this possible, or is there an entirely different solution that I'm not seeing?
Thanks!
~ribs
Sure, it's possible to do something like that. Since a shelf itself is like a dictionary, just save all the character instances in a real dictionary instance inside it using their variable's name as the key. For example:
class Character(object):
def __init__(self, name="DEFAULT"):
self.name = name
pc = Character("Bob")
def print_name(character):
print character.name
def run():
print_name(pc)
run()
import shelve
mysave = shelve.open("save1")
# save all Character instances without the default name
mysave["all characters"] = {varname:value for varname,value in
globals().iteritems() if
isinstance(value, Character) and
value.name != "DEFAULT"}
mysave.close()
del pc
mysave = shelve.open("save1")
globals().update(mysave["all characters"])
mysave.close()
run()

How to change Operator's label in Blender 2.63 depending on the context?

I'm writing an exporter for a game my friend and I are making and it involves setting custom properties and tags to objects which are then recognized in the game and dealt with accordingly. Our engine, which is written in C/C++ has been successfully tested with my current version of the export script, and I''m currently working on tidying it up.
The script uses Blender's feature of custom properties to write custom tags to output file. The model typically consists of multiple 'parts' (Blender mesh objects that are parented to form a tree, with one 'parent' and multiple 'child' objects) and some of those parts are simple Blender Empty objects (for only it's X, Y and Z coordinates are needed) with custom properties that mark where things like ship's propulsion (it's a 3D shooter) are placed, or where the flames/explosions appear when ship's been shot. Those empty parts are also parented to either 'root' object or any of it's children. So far it's been working good, I have written a generic Operator class and some extended classes that reside in a panel which set part's properties (pretty handy since you don't have to add those custom properties by hand).
Now I want to speed thing up even more, that is to be able to simply click on an operator of desired type, and it should automatically add it to the scene and parent it to the active/selected object. I know how to do that, but I can't get those operators to change their labels. Basically, what I want is to operator to say 'Bullet point' when an existing empty is selected (I've got that part done), and when there's a mesh object selected to say 'Add bullet point'. So I just need a way to dynamically change operators' labels depending on the context (as the title of the question states clearly :))
This is what I got so far:
class OBJECT_OT_tg_generic (bpy.types.Operator):
bl_label = "Sets Generic Part Type"
bl_idname = "rbm.set_generic_part_type"
OB_TYPE = None
#classmethod
def poll (cls, context):
act = context.active_object
if 'Type' in act.keys ():
if act['Type'] == cls.OB_TYPE:
cls.bl_label = 'foo'
print (cls.bl_label)
# this prints foo but doesn't change the label
return False
return True
def execute (self, context):
# TODO: add code to automatically place empties and parent them to active object
bpy.context.active_object['Type'] = self.OB_TYPE
return{"FINISHED"}
And an example of a subclass:
class OBJECT_OT_tg_bullet_point (OBJECT_OT_tg_generic):
bl_label = "Bullet Point"
bl_idname = "rbm.set_bullet_point"
OB_TYPE = OT_BULLET_POINT
Here's how it looks in Blender:
http://i.imgur.com/46RAS.png
Guess I solved it. When you're adding an operator to a panel, you can do something like this:
def draw (self, context):
layout = self.layout
row = layout.row()
row.operator("foo.bar", text="Whatever you want")
and the "Whatever you want" is going to be your button's label. But what I did was something else. I didn't change the operators' labels, but instead gave them a different icons depending on whether it's a mesh or an empty currently selected/active:
def draw (self, context):
# (...) we're skipping some code here, obviously
act = context.active_object
if act.type == 'MESH':
op_icon = 'ZOOMIN'
else:
op_icon = 'EMPTY_DATA'
row = layout.column(align=True)
row.operator('rbm.set_bullet_point', icon=op_icon)
row.operator('rbm.set_rocket_point', icon=op_icon)
# (...) rest of the code

Categories