Empty NodePath problem

Hi,

in my script I am creating a grid made out of LineNodePaths which are parented to the main GridNodePath and this is parented to the RootNodePath of my application. I have a switch routine in my Grid class which toggles the display of the grid by reparenting main GridNodePath to the RootNodePath or to hidden.

Now I have a situation where I need to clear the entire scenegraph and create a new one. I do RootNodePath.removeNode() and recreate everything. However, it seems that switch routine of my Grid still has the old RootNodePath because when i try reparenting to it, I get AssertionError: other._error_type == ET_ok at line 680 of panda/src/pgraph/nodePath.cxx. Checking isEmpty on the given nodepath returns 1.

This is a minimal sample of the code, please ignore the ugly coding style, I just wanted to recreate the situation as quickly as possible :slight_smile:. I know I am missing something really trivial here, any help is much appreciated. Clicking ‘G’ switches grid display. Try clicking ‘B’ which should recreate RootNodePath and the whole grid, and then clicking ‘G’ which reparents grid to the new RootNodePath.

from direct.directbase import DirectStart
from direct.showbase import DirectObject
from panda3d.core import NodePath, Vec4
from direct.directtools.DirectGeometry import LineNodePath

class Grid(DirectObject.DirectObject):
    def __init__(self, node):
        self.GridNodePath = NodePath('gridnode')
        self.linenodepath = LineNodePath(self.GridNodePath, 'lnp', 4, Vec4(.2, .2, .2, 0))
        self.linenodepath.drawLines([[(0,2,0), (1,3,0)], [(0,4,0), (1,4,0)] ])
        self.linenodepath.create()
        #self.mynode.flattenStrong()
        self.GridNodePath.reparentTo(node)
        self.accept('g', self.switch, [node])
        self.visible = True
    
    def switch(self, node):
        if self.visible == False:
            self.GridNodePath.reparentTo(node)
            self.visible = True
        elif self.visible == True:
            self.GridNodePath.reparentTo(hidden)
            self.visible = False 

def recreate():
    base.RootNodePath.removeNode()
    base.RootNodePath = NodePath('master')
    del base.grid
    base.grid = Grid(base.RootNodePath)
    base.RootNodePath.reparentTo(render)
    
base.RootNodePath = NodePath('master')
base.grid = Grid(base.RootNodePath)
base.RootNodePath.reparentTo(render)
base.accept('b', recreate)
run()

Something tells me you can’t overwrite the DirectObject while in use - so maybe you could separate your graphics from your game logic? I mean, to recreate the graphics logic, call .removeNode and then make a new NodePath. To recreate your game logic, you can delete the grid then create a new one.

from direct.directbase import DirectStart
from direct.showbase import DirectObject
from panda3d.core import NodePath, Vec4
from direct.directtools.DirectGeometry import LineNodePath

class World(DirectObject.DirectObject):

    def __init__(self):
        self.RootNodePath = NodePath('master')
        self.RootNodePath.reparentTo(render)
        self.grid = Grid(self.RootNodePath)
        self.accept('b', self.recreate)

        self.GridNodePath = NodePath('gridnode')
        self.linenodepath = LineNodePath(self.GridNodePath, 'lnp', 4, Vec4(.2, .2, .2, 0))
        self.linenodepath.drawLines([[(0,2,0), (1,3,0)], [(0,4,0), (1,4,0)] ])
        self.linenodepath.create()
        #self.mynode.flattenStrong()
        self.GridNodePath.reparentTo(self.RootNodePath)
        self.accept('g', self.switch)
        self.visible = True

    def switch(self):
        print 'switching'
        if self.visible == False:
            self.GridNodePath.reparentTo(self.RootNodePath)
            self.visible = True
        elif self.visible == True:
            self.GridNodePath.reparentTo(hidden)
            self.visible = False

    def recreate(self):
        print 'recreating'
        self.RootNodePath.removeNode()
        self.RootNodePath = NodePath('master')
        del self.grid
        self.grid = Grid(self.RootNodePath)
        self.RootNodePath.reparentTo(render)


class Grid():

    def __init__(self, node):
        self.node = node


world = World()
run()

Ah yes, that will totally work. Just needed a fresh perspective :slight_smile:

Thanks a lot bluskies!