I solved the off-window issue so we gotta a final release I guess
'''
by: mavasher
revisers: crossedgun, ynjh_jo, pro_rsoft, astelix
'''
from pandac.PandaModules import *
from direct.directbase.DirectStart import *
from direct.showbase.DirectObject import DirectObject
from direct.task import Task
import random
class World(DirectObject):
def __init__(self):
for i in range(10):
ball = loader.loadModel("smiley")
ball.reparentTo(render)
ball.setTag('click', '1')
ball.setPos(random.randint(-4,4),random.randint(-4,4),random.randint(-4,4))
cs = CollisionSphere(0, 0, 0, 1)
cnodePath = ball.attachNewNode(CollisionNode('cnode'))
cnodePath.node().addSolid(cs)
cnodePath.node().setIntoCollideMask(BitMask32.allOff())
self.accept("mouse1", self.click)
#-----------------------------------------
def click(self):
if not base.mouseWatcherNode.hasMouse():
return
self.click_start = Point2(base.mouseWatcherNode.getMouseX(),base.mouseWatcherNode.getMouseY())
cmfg = CardMaker('fg')
cmfg.setFrame(0, 1, -1, 0)
self.bar = render2d.attachNewNode(cmfg.generate())
self.bar.setPos(self.click_start[0],1,self.click_start[1])
self.bar.setColor(0,1,0,.5)
self.bar.setTransparency(1)
taskMgr.add(w.update_rect, "update_rect")
self.acceptOnce("mouse1-up", self.release_click)
#-----------------------------------------
def update_rect(self, task):
if not base.mouseWatcherNode.hasMouse(): #check for mouse first, in case the mouse is outside the Panda window
return Task.cont
sx = base.mouseWatcherNode.getMouseX() - self.click_start[0]
sy = self.click_start[1] - base.mouseWatcherNode.getMouseY()
self.bar.setScale(sx if sx else .0001, 1, sy if sy else .0001)
return Task.cont
#-----------------------------------------
def release_click(self):
taskMgr.remove("update_rect")
click_start=Point2(self.bar.getTightBounds()[0][0], self.bar.getTightBounds()[0][2])
click_end=Point2(self.bar.getTightBounds()[1][0], self.bar.getTightBounds()[1][2])
self.bar.removeNode()
if click_end == click_start: #Fudge the numbers a bit to avoid the degenerate case of no rectangle
click_end = Point2(click_end[0]+.00001, click_end[1]+.00001)
#I would have used the simpler PickerRay method, but the collision masks on the objects are reversed
pt = Point3()
junk_pt = Point3()
base.camLens.extrude(click_start, junk_pt, pt) #calculate a point in 3d space from the mouse position
click_start3 = pt #Use the point farthest away from the camera for the best precision
click_end3 = Point3()
base.camLens.extrude(click_end, junk_pt, click_end3)
left = CollisionPlane(Plane(camera.getPos(),Point3(click_start3[0],1000,click_end3[2]), click_start3 )) #Create the 4 sides with planes
right=CollisionPlane(Plane(camera.getPos(),Point3(click_end3[0],1000,click_start3[2]),click_end3 )) #They should all 'face' inward: i.e.
bot = CollisionPlane(Plane(camera.getPos(), click_end3, Point3(click_start3[0],1000,click_end3[2]))) #Collisions are inside
top = CollisionPlane(Plane(camera.getPos(), click_start3, Point3(click_end3[0],1000,click_start3[2])))
pyramid = render.attachNewNode(CollisionNode('pyramid'))
pyramid.node().addSolid(left)
pyramid.node().addSolid(top)
pyramid.node().addSolid(right)
pyramid.node().addSolid(bot)
click_traverser = CollisionTraverser('click_enabler')
click_handler = CollisionHandlerQueue()
for ci in render.findAllMatches("=click").asList():
click_traverser.addCollider(ci.find("+CollisionNode"), click_handler)
click_traverser.traverse(render)
hits = []
for i in range(click_handler.getNumEntries()):
hits.append(click_handler.getEntry(i).getFromNodePath().getParent()) #this actually includes all clickable items since the planes cover everything.
# If the object is within the rectangle, it collides with all 4 planes
# Use set to remove 3 duplicates of each selected object
sel=set(filter(lambda i: hits.count(i) == 4, hits))
print len(sel),'selected'
all=render.findAllMatches("**/smiley*")
for i in range(all.getNumPaths()): all[i].clearColor()
for i in sel:
i.setColor(random.random(),random.random(),random.random())
click_traverser.clearColliders()
click_handler.clearEntries()
pyramid.removeNode()
camera.setPos(0, -25, 5)
base.disableMouse()
w = World()
run()