Search code examples
panda3d

Not able to click 3d objects and move them


I want to click on the loaded models and move them around. I used the code from chess sample examples and panda 3d tutorial without any success. Can someone figure out whats wrong with the code.

Thanks

from math import pi, sin, cos
import sys
from direct.showbase.ShowBase import ShowBase
import direct.directbase.DirectStart
from direct.task import Task
from panda3d.core import TextNode
from direct.gui.OnscreenText import OnscreenText
from panda3d.core import CollisionTraverser, CollisionNode
from panda3d.core import CollisionHandlerQueue, CollisionRay
from panda3d.core import Point3, Vec3, Vec4, BitMask32
from direct.showbase.DirectObject import DirectObject
from panda3d.core import AmbientLight, DirectionalLight, LightAttrib


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

        # quit when esc is pressed
        self.accept('escape', sys.exit)

        #base.disableMouse()

        # load the box model
        self.box = self.loader.loadModel("models/xbox")
        self.box.reparentTo(camera)
        self.box.setScale(2.0, 2.0, 2.0)
        self.box.setPos(8, 50, 0)

        self.keyMap = {
            "w" :False ,
            "s" :False,
            "a": False,
            "d": False,
            "mouse1": False,
            "mouse3": False,
        }

        # CollisionTraverser  and a Collision Handler is set up
        self.picker = CollisionTraverser()
        self.pq = CollisionHandlerQueue() 

        self.pickerNode = CollisionNode('mouseRay')
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.box.setCollideMask(BitMask32.bit(1)) 
        
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        self.picker.addCollider(self.pickerNP, self.pq)

        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
        self.accept("mouse1", self.setKey, ["mouse1", True])
        

    def mouseTask(self,task):
        # check if we have access to the mouse
        if base.mouseWatcherNode.hasMouse():

            # get the mouse position
            mpos = base.mouseWatcherNode.getMouse()

            # set the position of the ray based on the mouse position
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            self.picker.traverse(render)
            # if we have hit something sort the hits so that the closest is first and highlight the node
            if self.pq.getNumEntries() > 0:
                self.pq.sortEntries()
                pickedObj = self.picker.getEntry(0).getIntoNodePath()
    

    def setKey(self,key,value):
        self.keyMap[key] = value
 
   
app = MyApp()
app.run()

Solution

  • I was just trying to do the same thing, when I found your question. Thanks for your code, it help me to start!

    I've manage to get it working :)

    Just a remark: you use a task, with no return, this make the task run once. You should have used: return task.cont

    Anyway, here my working code for panda3d devel (1.8.0+):

    import sys
    from direct.showbase.ShowBase import ShowBase
    from pandac.PandaModules import *
    
    
    class MyApp(ShowBase):
        def __init__(self):
            ShowBase.__init__(self)
    
    
            # quit when esc is pressed
            self.accept('escape',sys.exit)
    
            #base.disableMouse()
    
    
            # load the box model
            box = self.loader.loadModel("models/box")
            box.reparentTo(render)
            box.setScale(2.0, 2.0, 2.0)
            box.setPos(8, 50, 0)
    
            panda = base.loader.loadModel("models/panda")
            panda.reparentTo(render)
            panda.setPos(0, 10, 0)
            panda.setScale(0.1, 0.1, 0.1)
            cNodePanda = panda.attachNewNode(CollisionNode('cnode_panda'))
            cNodePanda.node().addSolid(CollisionSphere(0,0,5,5))
            cNodePanda.show()
    
            # CollisionTraverser  and a Collision Handler is set up
            self.picker = CollisionTraverser()
            self.picker.showCollisions(render)
            self.pq = CollisionHandlerQueue() 
    
            self.pickerNode = CollisionNode('mouseRay')
            self.pickerNP = camera.attachNewNode(self.pickerNode)
            self.pickerNode.setFromCollideMask(BitMask32.bit(1))
            box.setCollideMask(BitMask32.bit(1)) 
            panda.setCollideMask(BitMask32.bit(1))
    
            self.pickerRay = CollisionRay()
            self.pickerNode.addSolid(self.pickerRay)
            self.picker.addCollider(self.pickerNP,self.pq)
    
            self.accept("mouse1",self.mouseClick)
    
    
        def mouseClick(self):
            print('mouse click')
            # check if we have access to the mouse
            if base.mouseWatcherNode.hasMouse():
    
                # get the mouse position
                mpos = base.mouseWatcherNode.getMouse()
    
                # set the position of the ray based on the mouse position
                self.pickerRay.setFromLens(base.camNode,mpos.getX(),mpos.getY())
                self.picker.traverse(render)
                # if we have hit something sort the hits so that the closest is first and highlight the node
                if self.pq.getNumEntries() > 0:
                    self.pq.sortEntries()
                    pickedObj = self.pq.getEntry(0).getIntoNodePath()
                    print('click on ' + pickedObj.getName())
    
    app = MyApp()
    app.run()