Hi guys,
I’m working on a project that allows the user to place models on terrain. Right now, I can’t seem to be able to detect collisions between the mouse and the objects.
I’m using parts of the code from the Chessboard tutorial. Here are the relevant parts of the code:
class World(DirectObject):
def __init__(self):
print "initializing world"
self.keys = {"cube": 0}
self.mouse = {"holding-obj": 0}
#collision detection, from the Chessboard tutorial
self.picker = CollisionTraverser() # make a traverser
self.pq = CollisionHandlerQueue() # make an handler
self.pickerNode = CollisionNode('mouseRay') # make a collision node for our picker ray
self.pickerNP = camera.attachNewNode(self.pickerNode) # attach that node to the camera since the ray will need to be positioned
# relative to the camera
self.pickerNode.setFromCollideMask(BitMask32.bit(1)) # everything to be picked will use bit 1. This way if we're detecting other
# collisions we can use other bits
self.pickerRay = CollisionRay() # make our collision ray!
self.pickerNode.addSolid(self.pickerRay) # add it to the node
self.picker.addCollider(self.pickerNP, self.pq) # register the ray as something that can cause collisions
self.cubes = render.attachNewNode("cubes") #list of objects
#binds keys to actions
self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
self.accept('mouse1', self.testObj) # Left click -> if mouse is not holding an object, it will grab the object on the cursor.
# If mouse already has something on it, it will attempt to put the object down.
self.accept('space', self.setKey, ["cube", 1]) # TEST FUNCTION: Space bar -> Generates a cube
#Other parts of __init__ are mainly camera controls (using keyboard with base.disableMouse(), and generating the terrain.
When the space bar is pressed, createCube() (which is also in class World) is executed. createCube() generates a cube with random size and places it randomly on the map:
def createCube(self):
cube = loader.loadModel("models/box")
cube.reparentTo(self.cubes)
x = random.randint(20,self.width-20)
z = random.randint(20,self.height-20)
s = random.randint(0, 15)
cube_coord_lower_left = [float(x), float(self.height_data[self.width*z+x]/16.0-s), float(z)]
cube_coord_lower_right = [float(x+s), float(self.height_data[self.width*z+x+s]/16.0-s), float(z)]
cube_coord_upper_left = [float(x), float(self.height_data[self.width*(z-s)+x]/16.0-s), float(z-s)]
#don't need upper right, since we just need to calculate x-tilt (upper left - lower left) and z-tilt (lower right - lower left)
cube_tilt = [0, cube_coord_upper_left[1] - cube_coord_lower_left[1], cube_coord_lower_right[1] - cube_coord_lower_left[1]]
cube.setTag('cube', str(self.cube_count))
cube.setScale(s, s, s)
cube.setPos(float(x), float(self.height_data[self.width*z+x]/16.0)-s, float(z))
cube.setHpr(cube_tilt[0], cube_tilt[1], cube_tilt[2]) #tilts the cube according to the terrain (ie. start and end points of the cube
# doesn't really work yet
# because, it needs the angles in RADIANS. Need to find a way to convert gradient into radians
#set up cube collision
bounds = cube.getBounds()
cSphere = CollisionSphere(bounds.getCenter(), bounds.getRadius())
cNode = CollisionNode('cube')
cNode.setIntoCollideMask(BitMask32.bit(1))
cNode.addSolid(cSphere)
cube.attachNewNode(cNode)
print self.cube_count
mouseTask is currently empty, as the mouse is checked only when the user clicks the LMB.
def mouseTask(self, task):
return Task.cont
def testObj(self):
if self.mouse["holding-obj"]:
self.putObj()
else:
self.holdObj()
Most of this taken from the Chessboard tutorial. printing self.pickerRay and self.pq are just test functions to see everything is working correctly.
def holdObj(self):
if base.mouseWatcherNode.hasMouse():
mpos = base.mouseWatcherNode.getMouse() #gets mouse position
#Set the position of the ray based on the mouse position
self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
print self.pickerRay
if self.mouse["holding-obj"] == 0:
#self.picker.traverse(self.cube_list)
self.picker.traverse(self.cubes)
print self.pq
if self.pq.getNumEntries() > 0:
self.pq.sortEntries()
i = int(self.pq.getEntry(0).getIntoNode().getTag('cube'))
print i
Sample outputs of print self.pickerRay and print self.pq:
ray, o (0.00562693 1 -0.162556), d (56.2121 998.983 -162.361)
CollisionHandlerQueue, 0 entries:
I’m using Panda 1.4.2. Am I going in the right direction in implementing this, or is there something I missed out?
Thanks.