Hmmm, actually I just realised that in the GNOME desktop anyway, when you’re dragging an object, it’s whether the mouse pointer is over a drop location that counts, not whether the object being dragged intersects a drop location. Implementing it that way makes the code simpler, and gets rid of the highlight bug when you try to successively drop multiple objects on top of each other.
import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.task import Task
import sys
cm = CardMaker('cm')
left,right,bottom,top = 0,2,0,-2
width = right - left
height = top - bottom
cm.setFrame(left,right,bottom,top)
# Colours.
normal = (1,1,1,1)
highlight = (.7,.7,.7,1)
node = aspect2d.attachNewNode('')
node.setPos(-1.2,0,0.9)
cards = []
for i in range(3):
for j in range(3):
card = node.attachNewNode(cm.generate())
card.setScale(.2)
card.setPos(i/2.0,0,-j/2.0)
card.setColor(*normal)
card.setCollideMask(BitMask32.bit(3))
cards.append(card)
class DragNDrop:
def __init__(self):
base.accept("escape",sys.exit)
base.accept('mouse1',self.drag)
base.accept('mouse1-up',self.drop)
cn = CollisionNode('')
cn.addSolid(CollisionRay(0,-100,0, 0,1,0))
cn.setFromCollideMask(BitMask32.bit(3))
cn.setIntoCollideMask(BitMask32.allOff())
self.cnp = aspect2d.attachNewNode(cn)
self.ctrav=CollisionTraverser()
self.queue = CollisionHandlerQueue()
self.ctrav.addCollider(self.cnp,self.queue)
# self.ctrav.showCollisions(aspect2d)
taskMgr.add(self.rolloverTask,'rolloverTask')
self.rollover = None
self.draggee = None
self.difference = None
def rolloverTask(self,t):
"""Move the mouse CollisionRay to the position of the mouse
pointer, check for collisions, and update self.rollover.
"""
if not base.mouseWatcherNode.hasMouse():
return Task.cont
if self.rollover is not None:
self.rollover.setColor(*normal)
mpos = base.mouseWatcherNode.getMouse()
if self.draggee is not None:
self.draggee.setPos(render2d,mpos[0]+self.difference[0],0,mpos[1]+self.difference[1])
self.cnp.setPos(render2d,mpos[0],0,mpos[1])
self.ctrav.traverse(aspect2d)
self.queue.sortEntries()
if self.queue.getNumEntries():
self.rollover = self.queue.getEntry(self.queue.getNumEntries()-1).getIntoNodePath()
self.rollover.setColor(*highlight)
else:
self.rollover = None
return Task.cont
def drag(self):
if self.rollover is not None:
self.draggee = self.rollover
self.draggee.setCollideMask(BitMask32.allOff())
mpos = base.mouseWatcherNode.getMouse()
self.difference = (self.draggee.getX(render2d)-mpos[0],self.draggee.getZ(render2d)-mpos[1])
def drop(self):
if self.draggee is not None:
if self.rollover is not None:
self.draggee.setPos(self.rollover.getPos())
self.draggee.setCollideMask(BitMask32.bit(3))
self.draggee = None
self.difference = None
d = DragNDrop()
run()