aiBehaviors 'leaking' Panda nodes

Hi, my app features a few actors moving around a map all the time. I use aiBehaviors for path following, and noticed the framerate dropping significantly with time (300+ fps -> 50 fps in a matter of minutes). While debugging, I could only pinpoint a huge, growing list of Panda nodes called ‘dummy’ when using render.ls().

I pinpointed the problem to aiBehaviors, that seem to use this dummy node to set a final destination for the path or something. Every time a new path is to be followed, a new dummy node is created - but never destroyed. Is this a bug? Or am I not handling arrival or something wrong?

I recreated the problem in the following code. Tapping F12 shows dummy nodes being added at the bottom of the render.ls() list in the console.

from direct.showbase.ShowBase import ShowBase
from panda3d.core import Vec3, Vec4
from panda3d.core import AmbientLight, DirectionalLight
from panda3d.ai import *


class Game(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)

        # load a model, any model
        self.np = loader.loadModel('resources/models/block')
        self.np.reparentTo(render)
        # scene setup
        self.setBackgroundColor((0, 0, 0, 1))
        render.setShaderAuto()
        # some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.4, .4, .35, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0, 8, -2.5))
        directionalLight.setColor((0.9, 0.8, 0.9, 1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(ambientLight))
        # camera
        base.disableMouse()
        camera.setPos(0, -25, 5)
        camera.lookAt(0, 0, 0)
        # Create AI world, character and behaviors
        self.aiWorld = AIWorld(render)
        self.aiChar = AICharacter(model_name="GameActor",
                                  model_np=self.np,
                                  mass=20,
                                  movt_force=0.025,
                                  max_force=1.0)
        self.aiWorld.addAiChar(self.aiChar)
        self.aiBehaviors = self.aiChar.getAiBehaviors()
        self.doPath()
        # run updates
        taskMgr.add(self.update, 'update')

        # accept f12 for debugging
        self.accept('f12-up', self.debugNodes)

    def doPath(self):
        # set up a path to follow
        self.aiBehaviors.pathFollow(1.0)
        self.aiBehaviors.addToPath(Vec3(0, 0, 0))
        self.aiBehaviors.addToPath(Vec3(-2, 15, 0))
        self.aiBehaviors.addToPath(Vec3(-15, -2, 0))
        self.aiBehaviors.addToPath(Vec3(-6, -15, 0))
        self.aiBehaviors.addToPath(Vec3(2, -15, 0))
        self.aiBehaviors.startFollow()

    def update(self, task):
        self.aiWorld.update()
        if self.aiBehaviors.behaviorStatus('pursue') == 'done':
            self.doPath()
        return task.cont

    def debugNodes(self):
        render.ls()

app = Game()
app.run()

I’d appreciate help with this. Like I said, with a bunch of actors moving around all the time, these dummy nodes quickly become a huge problem for performance.

Jeroen

Also checked: if the first path.append is anything else than Vec3(0, 0, 0), the dummy node is set to that first coordinate. Seeing the path is followed in reverse, the dummy node seems to hold the final destination.

Also, further digging (render.analyze()) shows not only nodes adding up, but also transforms.

If anyone runs into the same problem, I’ve got a workaround for now. Right after invoking aiBehaviors.startFollow(), it seems to be safe to remove the dummy node from render:

render.find('dummy').removeNode()