i have put together a sample how i would make it:
it’s currently missing highlighting, but that’s easy to add. also creating a different type of drag/drop object would be quite easy. You may want to change the way the collidemask off method works (save the old collide mask and apply it on release again)
import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.task import Task
import sys,random
# Collision mask worn by all draggable objects.
dragMask = BitMask32.bit(1)
# Collision mask worn by all droppable objects.
dropMask = BitMask32.bit(1)
highlight = VBase4(.3,.3,.3,1)
class objectMangerClass:
def __init__( self ):
self.objectIdCounter = 0
self.objectDict = dict()
def tag( self, objectNp, objectClass ):
self.objectIdCounter += 1
objectTag = str(self.objectIdCounter)
objectNp.setTag( 'objectId', objectTag )
self.objectDict[objectTag] = objectClass
def get( self, objectTag ):
if objectTag in self.objectDict:
return self.objectDict[objectTag]
return None
objectManger = objectMangerClass()
class dragDropObjectClass:
def __init__( self, np ):
self.model = np
self.previousParent = None
self.model.setCollideMask(dragMask)
objectManger.tag( self.model, self )
def onPress( self, mouseNp ):
self.previousParent = self.model.getParent()
self.model.wrtReparentTo( mouseNp )
self.model.setCollideMask(BitMask32.allOff())
def onRelease( self ):
self.model.wrtReparentTo( self.previousParent )
self.model.setCollideMask(dragMask)
def onCombine( self, otherObj ):
self.model.setPos( otherObj.model.getPos() )
class mouseCollisionClass:
def __init__(self):
base.accept("escape",sys.exit)
base.accept('mouse1',self.onPress)
base.accept('mouse1-up',self.onRelease)
self.draggedObj = None
self.setupCollision()
taskMgr.add( self.mouseMoverTask, 'mouseMoverTask' )
def setupCollision( self ):
# Initialise the collision ray that is used to detect which draggable
# object the mouse pointer is over.
cn = CollisionNode('')
cn.addSolid( CollisionRay(0,-100,0, 0,1,0) )
cn.setFromCollideMask(dragMask)
cn.setIntoCollideMask(BitMask32.allOff())
self.cnp = aspect2d.attachNewNode(cn)
self.ctrav = CollisionTraverser()
self.queue = CollisionHandlerQueue()
self.ctrav.addCollider(self.cnp,self.queue)
self.cnp.show()
def mouseMoverTask( self, task ):
if base.mouseWatcherNode.hasMouse():
mpos = base.mouseWatcherNode.getMouse()
self.cnp.setPos(render2d,mpos[0],0,mpos[1])
return task.cont
def collisionCheck( self ):
self.ctrav.traverse(aspect2d)
self.queue.sortEntries()
if self.queue.getNumEntries():
np = self.queue.getEntry( self.queue.getNumEntries()-1 ).getIntoNodePath() #self.queue.getNumEntries()-1
objectId = np.getTag( 'objectId' )
if objectId is None:
objectId = np.findNetTag( 'objectId' )
if objectId is not None:
object = objectManger.get( objectId )
return object
return None
def onPress( self ):
obj = self.collisionCheck()
if obj is not None:
self.draggedObj = obj
obj.onPress( self.cnp )
def onRelease( self ):
obj = self.collisionCheck()
self.draggedObj.onRelease() # self.cnp )
if obj is not None:
self.draggedObj.onCombine( obj )
if __name__ == '__main__':
cm = CardMaker('cm')
left,right,bottom,top = 0,2,0,-2
width = right - left
height = top - bottom
cm.setFrame(left,right,bottom,top)
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(random.random(),random.random(),random.random())
draggable = dragDropObjectClass(card)
cards.append(card)
mouseCollision = mouseCollisionClass()
run()