AssertionError: _has_mouse in picking test program

Hi,

I’m trying to create a small test program that would do picking and object highlighting but I’m having problems running it. I’ve had many error messages but this one I have been unable to solve:


File “picktest.py”, line 87, in hiliteTask
mousePicker.getObjHit(base.mouseWatcherNode.getMouse())
AssertionError: _has_mouse at line 55 of c:\temp\mkpr\panda3d-1.1.0\panda\src\tform\mouseWatcher.I

I’d appreciate it if anyone could help me with this. Here’s the code I’m using if you want to give it a try:


import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.gui.DirectGui import *
from direct.task import Task

# Globals:
HILITECOL = Vec4(1, 1, 1, 1)        # Vertex color of objects when highlighted
NORMCOL = Vec4(0.8, 0.8, 0.8, 1)    # Vertex color of objects when not highlighted

ballModel = loader.loadModel('models/misc/sphere')
ballModel.reparentTo(render)
ballModel.setColor(NORMCOL)

#The class that handles the picking
class Picker:
    def __init__(self):
        self.picker = CollisionTraverser()
        self.queue = CollisionHandlerQueue()

        self.pickerNode = CollisionNode('mouseRay')
        self.pickerNP = camera.attachNewNode(self.pickerNode)

        self.pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())

        self.pickerRay = CollisionRay()

        self.pickerNode.addSolid(self.pickerRay)

        self.collisionNP = ballModel.attachNewNode(self.pickerNode)

        self.picker.addCollider(self.collisionNP, self.queue)

        self.pickedObj = None

    def makePickable(self, newObj):
        newObj.setTag('pickable', 'true')

    def getObjHit(self, mpos):
        self.pickedObj = None
        self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
        self.picker.traverse(render)
        if self.queue.getNumEntries() > 0:
            self.queue.sortEntries()
            self.pickedObj = self.queue.getEntry(0).getIntoNodePath()

            parent = self.pickedObj.getParent()
            self.pickedObj = None

            while parent != render:
                if parent.getTag('pickable') == 'true':
                    self.pickedObj = parent
                    return parent
                else: parent = parent.getParent()
        return None

    def getPickedObj(self):
        return self.pickedObj

mousePicker = Picker()
mousePicker.makePickable(ballModel)

#The last object that was highlighted
lastHiliteObj = None

#This function highlights an object that has been picked
def hiliteObj(pickedObj):
    pickedObj.getParent().setColor(HILITE)
    lastHiliteObj = pickedObj

def unhiliteObj():
    lastHiliteObj.getParent().setColor(NORMCOL)
    lastHiliteObj = None    

def hiliteTask(task):
    if lastHiliteObj == True:
        unhiliteObj()
    else:
        mousePicker.getObjHit(base.mouseWatcherNode.getMouse())
        hiliteObj(mousePicker.getPickedObj())

    return Task.cont        

#Our application class
class World(DirectObject):
    def __init__(self):
        taskMgr.add(hiliteTask, 'hiliteTask')

w = World()
run()

Oh, sorry, this was a dump question. I solved that error. All I had to do was add “if base.mouseWatcherNode.getMouse():” before I call the mousePicker.getObjHit(…) method. Well maybe this thread can still be useful to someone. If anyone is trying to get this code working (I still get errors) could you please post the final working version if you manage to get it to work correctly before I do.

Allright. Now I got it to run. I put the getMouse() calls inside a try-except block and it works. Only thing that bothers me is that if, while the program is running, the mouse is moved outside the Panda3d window area I get a long list of AssertionFailed: _has_mouse messages. I guess this is not a big deal, I got the program running after all. Now I just need to get the model to show up and see if it gets highlighted when the mouse howers over it.

From the generated API documentation for MouseWatcher:

Thus, you should ensure that base.mouseWatcherNode.hasMouse() returns True before you attempt to call base.mouseWatcherNode.getMouse(), for instance:

mouse = None
if base.mouseWatcherNode.hasMouse():
    mouse = base.mouseWatcherNode.getMouse()

David

Thankyou David. I finally managed to get this program to work. Here’s the final version of the code if anyone is interested, it does the picking and then highlights the picked object in green:


import direct.directbase.DirectStart 
#for the events 
from direct.showbase import DirectObject 
#for collision stuff 
from pandac.PandaModules import *
from direct.task import Task


class Picker(DirectObject.DirectObject): 
   def __init__(self): 
      #setup collision stuff 

      self.picker= CollisionTraverser() 
      self.queue=CollisionHandlerQueue() 

      self.pickerNode=CollisionNode('mouseRay') 
      self.pickerNP=camera.attachNewNode(self.pickerNode) 

      self.pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) 

      self.pickerRay=CollisionRay() 

      self.pickerNode.addSolid(self.pickerRay)

      self.pickerNP = camera.attachNewNode(self.pickerNode)

      self.picker.addCollider(self.pickerNP, self.queue) 

      #this holds the object that has been picked 
      self.pickedObj=None 

   #this function is meant to flag an object as being somthing we can pick 
   def makePickable(self,newObj): 
      newObj.setTag('pickable','true') 

   #this function finds the closest object to the camera that has been hit by our ray 
   def getObjectHit(self, mpos): #mpos is the position of the mouse on the screen 
      self.pickedObj=None #be sure to reset this 
      self.pickerRay.setFromLens(base.camNode, mpos.getX(),mpos.getY()) 
      self.picker.traverse(render) 
      if self.queue.getNumEntries() > 0: 
         self.queue.sortEntries() 
         self.pickedObj=self.queue.getEntry(0).getIntoNodePath() 

         parent=self.pickedObj.getParent() 
         self.pickedObj=None 

         while parent != render: 
            if parent.getTag('pickable')=='true': 
               self.pickedObj=parent 
               return parent 
            else: 
               parent=parent.getParent() 
      return None 

   def getPickedObj(self): 
         return self.pickedObj 

mousePicker=Picker() 

HILITECOL = Vec4(0.7,1,0.7,1)
NORMCOL = Vec4(1,1,1,1)

#load thest models 
panda=loader.loadModel('panda') 
teapot=loader.loadModel('teapot') 
box=loader.loadModel('box') 

#put them in the world 
panda.reparentTo(render) 
panda.setPos(camera, 0, 100,0)
panda.setColor(NORMCOL)

teapot.reparentTo(render) 
teapot.setPos(panda, -30, 0, 0)
teapot.setColor(NORMCOL)

box.reparentTo(render) 
box.setPos(panda, 30,0,0)
box.setColor(NORMCOL)

mousePicker.makePickable(panda) 
mousePicker.makePickable(teapot) 
mousePicker.makePickable(box)

lastHiliteObj = []

def setHiliteCol(pickObj):
    pickObj.setColor(HILITECOL)
    lastHiliteObj.append(pickObj)

def setNormCol():
    lastHiliteObj[0].setColor(NORMCOL)
    lastHiliteObj.pop()

def hiliteTask(task):
    if lastHiliteObj != []:
        setNormCol()

    if base.mouseWatcherNode.hasMouse() == True:
        if mousePicker.getObjectHit(base.mouseWatcherNode.getMouse()) != None:
            setHiliteCol(mousePicker.getPickedObj())

    return Task.cont            

taskMgr.add(hiliteTask,'hiliteTask')
run()