Class inheritance with nested structure of NodePath

I am trying to create procedural geometry mesh with nested design, that is:
At the top of nested structure is object I call BigTileCluster, which contains several TileCluster, each of which contains several BasicTiles

In what follows I am proving code that should illustrate how those objects are creates, however the code is incomplete, I tried to provide only the necessary pieces.
The BasicTile is created in following manner:

class BasicTile(NodePath):
    def __init__(
        self,
        q, r, center, 
        terrain_color
        ):
        super().__init__("BasicTile")
        self._default_color = terrain_color
        self.q = q
        self.r = r
        self.center = center
        self._highlight_color =    self.set_highlight_color(color_offset)

    def create_tile(
            self,
            ):
        vdata, tris = self.triangulate_mesh(self.get_default_color())
        geom = Geom(vdata)
        geom.add_primitive(tris)
        geom_grid=Geom(vdata_grid)
        geom_grid.add_primitive(tris_grid)
        node = GeomNode("tile")
        node.add_geom(geom)
        node.add_geom(geom_grid)
        self.attachNewNode(node)


    #here are other class methods

While TileCluster are created as follows:


class Cluster(NodePath):
    def __init__(
        self,
        q, 
        r
        ):
        super().__init__("Cluster")
        self.q = q
        self.r = r
        self.cells = self.create_sub_cells_array()

    def create_sub_cells_array(self):
        tiles =np.empty(
            shape=(7),
            dtype=NodePath
            )   
        for i in range(7):
            #here is some code that returns tile_position, q0, r0, terrain_color....
            tiles[i] = \
                BasicTile(q0, r0, tile_position,
                        terrain_color = terrain_color
                        )
            tiles[i].create_tile()
            tiles[i].reparent_to(self)
        return tiles 

    #here are other class methods

BigTileCluster cluster is almost same except in its cells array are TileClusters instead of BasicTiles.

At the end, BigTileCluster is reparented to render.
Now, the issue I am encountering is that while I can navigate this structure by leveraging ‘tiles’ attribute, i.e., BigTileCluster.tiles[0].tiles[0], I am not able to navigate by using NodePath methods.
that is,

 render.getChildren()[0].getChildren()[0].getChildren()[0]

returns object which doesnt have q, r and center attributes, and I cant figure out how to access them.
My guess is that the issue lies with how I use inheritance. I think I dont quite understand all the nuances with NodePaths, PandaNodes and handles.
I would be glad if someone could help me understand how to properly implement such tree like structure of tiles in Panda3d.

Question2:
Is it possible to access combined mesh of TileClusters? I am trying to get outer edge/boundary of TileCluster and BigTileCluster, however I am quite at loss how can this be achieved efficiently. I am bit reluctant to define it by hand…

The short version is that custom sub-classes of NodePath (and PandaNode) are essentially “lost” when they’re passed to the engine: Only the underlying C++ class is actually stored, while the Python class is just a wrapper. This means that a custom sub-class of the Python NodePath class is likewise not stored–just the original underlying C++ class.

(You can get a more-detailed discussion of the issue on this manual page.)

Furthermore, if I’m not much mistaken NodePaths may be constructed on the fly, meaning that the NodePath that you receive from a search may not be the same object–even if it refers to the same node–as the one that you expect.

Now, to address this:

If you weren’t planning on searching the scene-graph for your custom classes, I might suggest just… not sub-classing NodePath, and instead creating a custom class that stores the relevant NodePath as an instance member.

However, either way, if you want to retrieve your custom class via a scene-graph search, you’ll presumably want some way of associating the NodePath that your search returns with your custom class.

To this end, Panda allows one to store an arbitrary Python object in a node via the “pythonTag” suite of methods provided by the NodePath class. Simply use “setPythonTag” to store your object, referenced by the ID of your choice, and then when you retrieve the node via a search, use “getPythonTag” to retrieve it.

(This is again covered in more detail on the manual page to which I linked above.)

However, beware! Doing this can create a cyclic dependency which may interfere with Python’s garbage detection!

To address this, simply make sure that when you clean up your nodes, you clear the relevant Python-tag.

1 Like