Recommended Class to Subclass for custom classes?

Hola!

I was wondering what class is recommended to subclass to create custom in game entities. ie, I want all the entities you can interact with to have a function that returns what color they like. So that when a collision happens between the two entities, I can easily query each to determine if they like the color of the other, and do something.

The airblade game seemed to use DirectObject for the base of alot of their classes, while I would think that perhaps ActorNode would make more sense for what I’m looking for.

Any insights would be most appreciated,
-Nick

DirectObject is a fundamental class that is the base class for many different things used within the Python code, including Actor. DirectObject provides basic messaging services using the messenger; Actor inherits all this, and also inherits from NodePath to provide a handle to an object you can put in the scene graph, and furthermore adds animation functionality.

So you can subclass from Actor if you want the actor functionality, but if you don’t need this, it would make more sense to subclass from some DirectObject or some other class (if you subclass from anything at all).

But there’s a potential trouble spot I anticipate you discovering soon: Actor is a module defined in Python, and it inherits from NodePath, which is actually a C++ class. If you subclass Actor your new class will also, therefore, inherit (indirectly) from NodePath. But the C++ code doesn’t know about either of these inheritances, and when you store your entity in the scene graph, it only stores the C++ part of it. Normally, that’s not a problem, since you are keeping a handle to the Python part of it yourself.

But if you use any core C++ method (like the collision interface) that pulls the entity you stored out of the scene graph, the object it gives you will be just a plain old NodePath–it won’t be an Actor, and it won’t be your subclassed entity.

You will have to find some way to map the NodePath it gives you back into the advanced Python object you think it really is. One way is to store your objects in a dictionary by unique NodePath key, e.g. myDict[obj.getKey()] = obj. With this dictionary, you can then get your object back via obj = myDict[nodePath.getKey()].

David

Wow, good info! Good to know about a potential gotcha before I encounter it :slight_smile:

I was thinking of just subclassing ActorNode, and then attaching it to a NodePath. Then in the collision handler, looping through all of the children of the node path, until I found the one that was my class, and using that.

I’m looking to have my subclass do as much work as possible. ie, in the init, load up the model, add the collision info, any required physics, etc… But find to do that, I need to create a NodePath which to attach my subclass to, and attach most of the above to that. However, the ActorNode subclass that is returned after construction, isn’t enough by itself to do things like setting position, etc… And it’d be nice to have the NodePath that was created in the constructor, but I really don’t want to store that in my ActorNode subclass. So, long paragraph short, this approach was getting ugly.

However, if I subclassed the NodePath, all the previous paragraph’s problems would go away, though I’d have the one you mentioned above… Decisions decisions. :slight_smile:

Which brings me to my real question, what is the philosophical differences between a NodePath and just a Node? I’d thought of the NodePath as something that is just used for navigation of the scene graph, and doesn’t do much more than hold other Nodes and NodePaths. And that any of the real meat/logic/info should be in the contained Nodes themselves. But what is the real difference between the two?

Thanks very much for your time David, your posts are always enlightening, = )
-Nick

It is a tough decision. We have tended to come down on the side of inheriting from NodePath, since that is the most useful high-level interface into the graph. For instance, we decided to make Actor inherit from NodePath, even though it is really a wrapper around Panda’s Character node. (In fact, I apologize for my confusion in my previous post; I’d thought you were suggesting inheriting from Actor–I didn’t realize you’d said ActorNode. Curse these similarly-named classes!)

Note that there is already a handy NodePath interface for marking your special node in the graph, and for storing simple properties on a node that can be described with a string, like preferred color, for instance; so that for many objects you may not even need to subclass at all. See NodePath.setTag(), getTag(), getNetTag().

Ah, the difference between a NodePath and a Node. There has historically been a lot of confusion between a PandaNode and a NodePath. The fact of the matter is almost exactly as you say: the scene graph itself is a connected graph of PandaNodes (or things derived from PandaNode). NodePaths do not themselves actually appear anywhere in the graph; a NodePath is just a high-level interface for the fundamental scene graph operations, and each NodePath serves as a handle to one particular PandaNode.

By a remarkable coincidence, Josh has just now finished rewriting the part of the Panda manual that describes nodes and NodePaths, and I think he has done a stunning job: https://www.panda3d.org/manual/index.php/The_Scene_Graph

David

Hola David! :slight_smile:

I like what you have said. I ended up just creating a module method that created my derived class (from ActorNode), and stored it and the other items mentioned above, on a NodePath. And then just returned the NodePath. Nice to see that fits in with the way things are done. :slight_smile:

Re: ActorNode -> Actor confusion. Not a prob, I saw that you prolly misread, and I certainly learned another way of doing things. = ) (I know I’ve had 3 tabs on Actor, ActorNode and NodePath API defs, so I can get an idea of which does what :slight_smile:

Hey! Great rewrite! I like!

Thanks! As insightful and helpful as always! = )
-Nick

I think I ran into what you were talking about above, with not getting the python object out. If I create a subclass of ActorNode called Ball, and do this:

ent = Ball( “ball1” )
np = NodePath( ent )
print np.node().class.name

The 3rd line will print “ActorNode” instead of “Ball”, correct?

Thanks for your time,
-Nick

Right. In the case of an object inherited from some kind of PandaNode, you can map the C++ node back to your Python object with a dictionary on the node’s “this” member, e.g.:


myDict[ent.this] = ent

Then later:


ent = myDict[np.node().this]

David

Hello All,

Sorry to interrupt in. i’m currently facing the issue of linking my own object to the Panda scenegraph elements.

My dream was to have a setUserObj(myObj) in panda.
But i know its doesn’t exist.
Also setTag only accept string value .

I’ve heard of a pickle solution? Can some explain it to me?

is it storing the pickled object in the setTag ? Also can panda objects
like nodepath and node be stored via Pickle?

(PS: i’m trying to find out a python side solution. Currently i’m using a Registry and store the registry key in setTag).

This has actually been solved already, in the version of Panda on the head of the CVS trunk (it’s called setPythonTag()). If you wanted to, you could use cvs to download the current version of Panda and do your development on that. (Note that this code is still in development, and you it is possible that you will encounter bugs–although in general, it is likely to be stable.)

The pickle solution is to use Python’s pickle module to make an object into a string, and then store the string via the setTag() interface. That won’t work with Panda objects like NodePath, though. Also, it wouldn’t store the object itself, just a copy of the object, so it’s not quite the same thing.

A Python-side solution would be perfectly workable. You would use nodePath.getKey() to store any data you like in a separate, global dictionary. Since nodePath.getKey() always returns the same value for a given NodePath, you could then retrieve this data using this key later. It sounds like that is the solution you are working on.

David

I suppose there is no planned released before the end of this week.
So i may have to download the CVS version :slight_smile:
(because after this week i’m out of internet for one month, getting married)…

Félicitations!

But no, I highly doubt that we will have that release ready before the end of the week. :frowning:

David

Just a dumb question, where are the infos for connecting to the cvs?
(repository name, etc???)

The CVS repository is stored on SourceForge, under the project name “panda3d”. Therefore, the cvs root is :pserver:anonymous@cvs.sourceforge.net:/cvsroot/panda3d and the tree name is “panda3d”. More information can be found on the site docs section of sourceforge.net.

David

Ok after using the port option (for computer behind a firewall) it work perfectly :slight_smile:.
Next time is compiling panda/rebuilding it :frowning:

Is there a way not to need directX9 sdk?
I do not use directX renderer at all.

I don’t think you can disable this with the makepanda script.

If you are using the ppremake system, you can define:


#define HAVE_DX

to turn off the building of DirectX interfaces. However, it’s possible that the DirectX API might still be required in order to build some of the basic window operations handled by OpenGL–I’m not honestly sure.

David