Panda3d.ai AssertionError: !is_empty() at line 1041 of panda/src/pgraph/nodePath.cxx

import direct.directbase.DirectStart
from panda3d.core import *
from direct.showbase.DirectObject import DirectObject
from direct.task import Task
#for Pandai
from panda3d.ai import *

class World(DirectObject):

    def __init__(self):
        base.cam.setPosHpr(0,0,55,0,-90,0)
        self.loadModels()
        self.setAI()

    def loadModels(self):
        # smiley
        self.smiley = loader.loadModel('smiley')
        self.smiley.reparentTo(render)
        self.smiley.setPos(0, 0, 0)
        # Obstacle 1
        self.obstacle1 = loader.loadModel('frowney')
        self.obstacle1.setPos(0,0,0)
        self.obstacle1.reparentTo(render)
        # Obstacle 2
        self.obstacle2 = loader.loadModel('frowney')
        self.obstacle2.setPos(5,0,0)
        self.obstacle2.reparentTo(render)

    def AIUpdate(self,task):
        self.AIworld.update()
        return Task.cont
    
    def setAI(self):
        self.AIworld = AIWorld(render)
        self.smileyAIchar = AICharacter("smiley",self.smiley, 100, 0.05, 5)
        self.AIworld.addAiChar(self.smileyAIchar)
        self.smileyAIbehaviors = self.smileyAIchar.getAiBehaviors()        
        self.smileyAIbehaviors.obstacleAvoidance(1.0)
        taskMgr.add(self.AIUpdate,"AIUpdate")             
        
        # comment both addObstacles to induce the AssertionError
        # comment only the last addObstacle to induce an AssertionError
        self.AIworld.addObstacle(self.obstacle1)
        self.AIworld.addObstacle(self.obstacle2)

w = World()
run()

I’ve struggling to get panda3d.ai working. The example works fine, but every time I try using it in a game prototype it doesnt work anymore. The above code snippet is the best narrowing down that I could do for AssertionError: !is_empty() at line 1041 of panda/src/pgraph/nodePath.cxx Commenting or uncommenting the addObstacle near the end induces the AssertionError.

Based on what is required to induce the error, my guess is that the panda3d.ai system ignores obstacles that have the exact same position as the aiChar and throws the AssertionError when the list of obstacles is empty.

Is my assumption of what’s going on correct?

All in all, if my assumption is correct, that’s easy to fix, could just put an obstacle somewhere outside of the walkable area so the list cant be empty or do a check every frame and do a small nudge so it’s off by 0.1 instead of exactly overlapping.

That assertionError is quite an abstract thing to get, took me some trial and error to figure out what it might mean. It would be nice if it could throw a more explainatory message.

Based on the error, I don’t think that you’re correct.

At a glance, this looks to be a not-uncommon error produced when a NodePath is “empty”–i.e. it holds no node.

Quite what’s causing it I don’t know–could you show the full error, please, so that we can get an idea of where in the code it’s happening?

Just run the snippet and see for yourself. Commenting or uncommenting the obstacles is what induces the AssertionError

full error:

Using deprecated DirectStart interface.
Known pipe types:
wglGraphicsPipe
(all display modules loaded.)
:ShowBase(warning): run() is deprecated, use base.run() instead
Assertion failed: !is_empty() at line 1041 of panda/src/pgraph/nodePath.cxx
Traceback (most recent call last):
File “E:.…\narrowedDown.py”, line 30, in AIUpdate
self.AIworld.update()
AssertionError: !is_empty() at line 1041 of panda/src/pgraph/nodePath.cxx
:task(error): Exception occurred in PythonTask AIUpdate
Traceback (most recent call last):
File “E:.…\narrowedDown.py”, line 47, in
run()
File “C:\Users.…\AppData\Roaming\Python\Python37\site-packages\direct\showbase\ShowBaseGlobal.py”, line 67, in run
base.run()
File “C:.…\AppData\Roaming\Python\Python37\site-packages\direct\showbase\ShowBase.py”, line 3325, in run
self.taskMgr.run()
File “C:\Users.…\AppData\Roaming\Python\Python37\site-packages\direct\task\Task.py”, line 546, in run
self.step()
File “C:\Users.…\AppData\Roaming\Python\Python37\site-packages\direct\task\Task.py”, line 500, in step
self.mgr.poll()
File “E:.…\narrowedDown.py”, line 30, in AIUpdate
self.AIworld.update()
AssertionError: !is_empty() at line 1041 of panda/src/pgraph/nodePath.cxx

Hmm, it does indeed seem to be that some NodePath is ending up “empty”–and it looks like it’s a NodePath that’s handled by the AI system.

Since it appears to happen in AIWorld’s “update” method, and since that method updates AI-characters, I’m guessing that the problem lies with one of those.

You set the length of the feeler to 1, but did not let it work to find the obstacle, so you initialize the obstacle and the character in the same place. Accordingly, AIworld began an iteration of searching from an empty list of nodes.
https://docs.panda3d.org/1.10/python/programming/pandai/steering-behaviors/obstacle-avoidance

In bullet, if you place all the objects at one point, an explosion will occur, and there is no mistake about it.

Just don’t create two conditions.

I think in the source code only need to add a condition to check if the node is empty.

I just tried the code given in the first post above, and… it works without crash.

So, my next question is this: What version of Panda3D are you using? If it’s not the latest, then perhaps you’re bumping into a bug that has been fixed. If it’s a development version, perhaps a regression has been introduce.

Either way, it might be worth trying your code with the latest stable version of Panda.

You haven’t read the post carefully. Here is a minimal example.

from direct.showbase.ShowBase import ShowBase
from panda3d.ai import AIWorld, AICharacter

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

        self.smiley = loader.load_model('smiley')
        self.smiley.reparent_to(render)
        #self.smiley.set_pos(5, 0, 0)

        self.obstacle1 = loader.load_model('frowney')
        self.obstacle1.reparent_to(render)
        #self.obstacle1.set_pos(0, 0, 0)

        self.AIworld = AIWorld(render)
        self.smileyAIchar = AICharacter("smiley", self.smiley, 100, 0.05, 5)
        self.AIworld.add_ai_char(self.smileyAIchar)

        self.smileyAIbehaviors = self.smileyAIchar.get_ai_behaviors()
        self.smileyAIbehaviors.obstacle_avoidance(1.0)

        self.AIworld.add_obstacle(self.obstacle1)
        self.AIworld.update()

app = MyApp()
app.run()

Ah, you’re right–I missed the bit about the commenting. (In my defence, I was pretty tired. ^^; )

And trying that new version, it does seem that it has something to do with having the obstacle in the same place as the AI-character, as you previously suggested–which seems like a bug in the AI system, to me.

I should have pasted down the error having version and not the ‘comment this to create the error’. My bad.

1 Like