newb question - python tags

Total newb question- just tryign to understand the difference between the various things called “tags”.

In the past, I’ve done things like this in the past to conveniently track attributes of game objects:

character.isOK = True
character.SPD = 6
character.name = "Bob"

While adding clickable objects functionality, I created a tag called “clickable” like so:

character.clickable = "1"

and found that it didn’t work:

I had to do it like this:

character.setTag("clickable", "1")

Likewise, I wanted to print the name of what I’d clicked , so I did this at the end of my mouse pick function:

	if chQueue.getNumEntries() > 0:
		chQueue.sortEntries()
		pickedObj = chQueue.getEntry(0).getIntoNodePath()
		pickedObj = pickedObj.findNetTag("clickable")
		if not pickedObj.isEmpty():
			print "you clicked on ", pickedObj.name

but i got:
AttributeError: ‘libpanda.NodePath’ object has no attribute ‘name’

change the last line to:

print "you clicked on ", pickedObj.getPythonTag("name")

and it works.

So there’s obviously a difference between setting them the shorthand way, and with setTag, and using getPythonTag, etc.
I guess they’re different internally, I just wanted to understand it better.

Solution:

class(def) character: #object
       isOK = None #variable
       clickable = 0 #variable
       anothervariable = True #variable

You probably converted from Game Maker, right? I am just curious. :smiley:

by the way, the thing you want to create is called [b]object/b, but you have created variable(isOK or clickable). You can not assign variables to variables, you have to assign [b]variables/b to [b]objects/b, right? Python is an object-oriented language, so don’t forget that :slight_smile:

I’m not sure what Deny0 is talking about, but to answer your question, there’s a difference between the python syntax:

thing.name = "foo"

which stores a name attribute on the Python object “thing”, whatever it is, and the syntax:

thing.setPythonTag("name", "foo")

which stores a name attribute on the underlying node that a NodePath references.

Here’s the thing: a node is not a Python object. Panda is written in C++, and all of its objects are available to Python, but they are not themselves native Python objects (though they do appear to be so at first glance). This means that you can’t store attributes on them the same way you can store attributes on any other Python object.

Here’s another thing: an Actor, or some class that inherits from NodePath, is a Python object. The Actor class is written in Python and thus any instance of Actor is a proper Python object in the usual sense, and you can store attributes on it. BUT! NodePath is just a wrapper around the actual node, so when you store attributes on your Actor, you are only storing them on the wrapper for the node. This means when you find the node again from the scene graph, for instance as the result of the picking operation, and Panda creates a new wrapper object for you, this new wrapper will not have the attributes you have stored on the old wrapper.

That’s why we have setPythonTag(), which allows you to store attributes on the underlying node. Attributes stored here will be accessible to any wrapper object that references the same node. And before you ask, I don’t think it’s a good idea to transparently map syntax like “thing.name” to “thing.setPythonTag()”, because they really are doing different things. Sometimes you really do want to store attributes on the wrapper, and sometimes you want to store them on the node.

David

1 Like

thanks again , drwr, that’s very helpful.

So to chk my understanding.:

  • Panda nodes are C++ objects, not Python, and thus we cannot assign name attributes via the shorthand method of:
character.clickable = "1"
  • Actors (and other nodepath classes) are Python objects. which explains why my character.name = “Bob” line works (character is an Actor in my code) But this is only setting this attribute on the wrapper for the node, i.e. Actor.

  • setPythonTag - stores attribs on the node itself.

Two followup questions:

  1. Is there a difference between setPythonTag and setTag? I used setTag on my picker code and it seems to work.

  2. As I mentioned , I set name with: character.name = “Bob”
    and I can read it with: pickedObj.getPythonTag(“name”)

So it seems getPythonTag is returning the name attribute on the Actor wrapper. pickedObj is created with:

pickedObj = chQueue.getEntry(0).getIntoNodePath()

pickedObj.name doesn’t work because pickedObj , while a Nodepath wrapper, is not the same wrapper I assigned character.name to.
Is that right?

Your understanding is correct.

setTag can only store strings, while setPythonTag can store any arbitrary python object (including strings). On the other hand, setTag values can be stored in an egg file or bam file, while setPythonTag cannot.

Hmm, actually, I don’t believe this. getPythonTag() can only return the value that was previously stored on the node with setPythonTag(); it has no capability of looking within the wrapper class. So, is it possible that you accidentally stored the name with setPythonTag() and then forgot about doing this?

Exactly right.

David

you’re right on #2. :slight_smile:
I double-checked and I had used setTag to give it a value which getTag was reading.
thx!