def getMouseRay(self, collRay=False): ray = CollisionRay() ray.setFromLens(self.camNode, self.getMouse()) if collRay: return ray else: return Ray(ray.getOrigin(), ray.getDirection())
class MouseCollision: def __init__(self, game): self.game = game self.c_trav = CollisionTraverser() self.mouse_groundHandler = CollisionHandlerQueue() self.mouse_ground_ray = CollisionRay() self.mouse_ground_col = CollisionNode('mouseRay') self.mouse_ground_ray.setOrigin(0, 0, 0) self.mouse_ground_ray.setDirection(0, -1, 0) self.mouse_ground_col.addSolid(self.mouse_ground_ray) self.mouse_ground_col.setFromCollideMask(CollideMask.bit(0)) self.mouse_ground_col.setIntoCollideMask(CollideMask.allOff()) self.mouse_ground_col_np = self.game.camera.attachNewNode( self.mouse_ground_col) self.c_trav.addCollider(self.mouse_ground_col_np, self.mouse_groundHandler) self.game.taskMgr.add(self.update, 'updateMouse') def update(self, task): if self.game.mouseWatcherNode.hasMouse(): if self.game.ship.model: mouse_pos = self.game.mouseWatcherNode.getMouse() self.mouse_ground_ray.setFromLens(self.game.camNode, mouse_pos.getX(), mouse_pos.getY()) near_point = render.getRelativePoint( self.game.camera, self.mouse_ground_ray.getOrigin()) near_vec = render.getRelativeVector( self.game.camera, self.mouse_ground_ray.getDirection()) self.game.ship.shipPoint.setPos( self.PointAtY(self.game.ship.model.getY(), near_point, near_vec)) return task.cont def PointAtY(self, y, point, vec): return point + vec * ((y - point.getY()) / vec.getY())
class MouseCollision: def __init__(self, game): self.game = game self.c_trav = CollisionTraverser() self.mouse_groundHandler = CollisionHandlerQueue() self.mouse_ground_ray = CollisionRay() self.mouse_ground_col = CollisionNode('mouseRay') self.mouse_ground_ray.setOrigin(0, 0, 0) self.mouse_ground_ray.setDirection(0, -1, 0) self.mouse_ground_col.addSolid(self.mouse_ground_ray) self.mouse_ground_col.setFromCollideMask(CollideMask.bit(0)) self.mouse_ground_col.setIntoCollideMask(CollideMask.allOff()) self.mouse_ground_col_np = self.game.camera.attachNewNode(self.mouse_ground_col) self.c_trav.addCollider(self.mouse_ground_col_np, self.mouse_groundHandler) self.game.taskMgr.add(self.update, 'updateMouse') def update(self, task): if self.game.mouseWatcherNode.hasMouse(): if self.game.ship.model: mouse_pos = self.game.mouseWatcherNode.getMouse() self.mouse_ground_ray.setFromLens(self.game.camNode, mouse_pos.getX(), mouse_pos.getY()) near_point = render.getRelativePoint(self.game.camera, self.mouse_ground_ray.getOrigin()) near_vec = render.getRelativeVector(self.game.camera, self.mouse_ground_ray.getDirection()) self.game.ship.shipPoint.setPos(self.PointAtY(self.game.ship.model.getY(), near_point, near_vec)) return task.cont def PointAtY(self, y, point, vec): return point + vec * ((y - point.getY()) / vec.getY())
def _get_collision(self, node, debug=False): mx = self.mouseWatcherNode.getMouseX() my = self.mouseWatcherNode.getMouseY() if debug: print "mouse:", (mx, my) # get the origin and direction of the ray extending from the # camera to the mouse pointer cm = np.array(self.cam.getNetTransform().getMat()) cr = CollisionRay() cr.setFromLens(self.cam.node(), (mx, my)) cp = np.hstack([cr.getOrigin(), 1]) cd = np.hstack([cr.getDirection(), 0]) cp = np.dot(cm.T, cp)[:3] cd = np.dot(cm.T, cd)[:3] if cd[2] > -1: cd[2] = -1 if debug: print "direction:", cd print "origin:", cp # point on the plane, z-axis pz = node.getPos(self.render)[2] sz = node.getScale(self.render)[2] / 2.0 p0 = np.array([0, 0, pz + sz]) if debug: print "p0:", p0 # this is the intersection equation that we want to solve, # where s is the point on the line that intersects # e_z(cp + s*cd - p0) = 0 s = (p0[2] - cp[2]) / cd[2] if debug: print "s:", s # transform the collision point from line coordinates to world # coordinates cv = cp + s * cd if debug: print "collision:", cv return cv
def _get_collision(self, node, debug=False): mx = self.mouseWatcherNode.getMouseX() my = self.mouseWatcherNode.getMouseY() if debug: print "mouse:", (mx, my) # get the origin and direction of the ray extending from the # camera to the mouse pointer cm = np.array(self.cam.getNetTransform().getMat()) cr = CollisionRay() cr.setFromLens(self.cam.node(), (mx, my)) cp = np.hstack([cr.getOrigin(), 1]) cd = np.hstack([cr.getDirection(), 0]) cp = np.dot(cm.T, cp)[:3] cd = np.dot(cm.T, cd)[:3] if cd[2] > -1: cd[2] = -1 if debug: print "direction:", cd print "origin:", cp # point on the plane, z-axis pz = node.getPos(self.render)[2] sz = node.getScale(self.render)[2] / 2.0 p0 = np.array([0, 0, pz + sz]) if debug: print "p0:", p0 # this is the intersection equation that we want to solve, # where s is the point on the line that intersects # e_z(cp + s*cd - p0) = 0 s = (p0[2] - cp[2]) / cd[2] if debug: print "s:", s # transform the collision point from line coordinates to world # coordinates cv = cp + s * cd if debug: print "collision:", cv return cv
class World(DirectObject): def __init__(self): #This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Panda3D: Tutorial - Mouse Picking", style=1, fg=(1, 1, 1, 1), pos=(0.8, -0.95), scale=.07) self.escapeEvent = OnscreenText( text="ESC: Quit", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.95), align=TextNode.ALeft, scale=.05) self.mouse1Event = OnscreenText( text="Left-click and drag: Pick up and drag piece", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.90), align=TextNode.ALeft, scale=.05) self.accept('escape', sys.exit) #Escape quits base.disableMouse() #Disble mouse camera control camera.setPosHpr(0, -13.75, 6, 0, -25, 0) #Set the camera self.setupLights() #Setup default lighting #Since we are using collision detection to do picking, we set it up like #any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() #Make a traverser self.pq = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') #Attach that node to the camera since the ray will need to be positioned #relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() #Make our ray self.pickerNode.addSolid(self.pickerRay) #Add it to the collision node #Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) #self.picker.showCollisions(render) #Now we create the chess board and its pieces #We will attach all of the squares to their own root. This way we can do the #collision pass just on the sqaures and save the time of checking the rest #of the scene self.squareRoot = render.attachNewNode("squareRoot") #For each square self.squares = [None for i in range(64)] self.pieces = dict((i, None) for i in range(64)) #MOD for i in range(64): #Load, parent, color, and position the model (a single square polygon) self.squares[i] = loader.loadModel("models/square") self.squares[i].reparentTo(self.squareRoot) self.squares[i].setPos(SquarePos(i)) self.squares[i].setColor(SquareColor(i)) #Set the model itself to be collideable with the ray. If this model was #any more complex than a single polygon, you should set up a collision #sphere around it instead. But for single polygons this works fine. self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) #Set a tag on the square's node so we can look up what square this is #later during the collision pass self.squares[i].find("**/polygon").node().setTag('square', str(i)) #We will use this variable as a pointer to whatever piece is currently #in this square #The order of pieces on a chessboard from white's perspective. This list #contains the constructor functions for the piece classes defined below pieceOrder = (Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook) for i in range(8, 16): #Load the white pawns self.pieces[i] = Pawn(i, WHITE) for i in range(48, 56): #load the black pawns self.pieces[i] = Pawn(i, PIECEBLACK) for i in range(8): #Load the special pieces for the front row and color them white self.pieces[i] = pieceOrder[i](i, WHITE) #Load the special pieces for the back row and color them black self.pieces[i + 56] = pieceOrder[i](i + 56, PIECEBLACK) #This will represent the index of the currently highlited square self.hiSq = False #This wil represent the index of the square where currently dragged piece #was grabbed from self.dragging = False #Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') self.accept("mouse1", self.grabPiece) #left-click grabs a piece self.accept("mouse1-up", self.releasePiece) #releasing places it #This function swaps the positions of two pieces def swapPieces(self, fr, to): temp = self.pieces[fr] self.pieces[fr] = self.pieces[to] self.pieces[to] = temp if self.pieces[fr]: self.pieces[fr].square = fr self.pieces[fr].obj.setPos(SquarePos(fr)) if self.pieces[to]: self.pieces[to].square = to self.pieces[to].obj.setPos(SquarePos(to)) def mouseTask(self, task): #This task deals with the highlighting and dragging based on the mouse #First, clear the current highlight if self.hiSq is not False: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = False #Check to see if we can access the mouse. We need it to do anything else 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()) #If we are dragging something, set the position of the object #to be at the appropriate point over the plane of the board if self.dragging is not False: #Gets the point described by pickerRay.getOrigin(), which is relative to #camera, relative instead to render nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin()) #Same thing with the direction of the ray nearVec = render.getRelativeVector(camera, self.pickerRay.getDirection()) self.pieces[self.dragging].obj.setPos( PointAtZ(.5, nearPoint, nearVec)) #Do the actual collision pass (Do it only on the squares for #efficiency purposes) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: #if we have hit something, sort the hits so that the closest #is first, and highlight that node self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) #Set the highlight on the picked square self.squares[i].setColor(HIGHLIGHT) self.hiSq = i return Task.cont def grabPiece(self): #If a square is highlighted and it has a piece, set it to dragging mode if (self.hiSq is not False and self.pieces[self.hiSq]): self.dragging = self.hiSq self.hiSq = False def releasePiece(self): #Letting go of a piece. If we are not on a square, return it to its original #position. Otherwise, swap it with the piece in the new square if self.dragging is not False: #Make sure we really are dragging something #We have let go of the piece, but we are not on a square if self.hiSq is False: self.pieces[self.dragging].obj.setPos( SquarePos(self.dragging)) else: #Otherwise, swap the pieces self.swapPieces(self.dragging, self.hiSq) #We are no longer dragging anything self.dragging = False def setupLights(self): #This function sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.8, .8, .8, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(0, 45, -45)) directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight))
class MouseHandler (DirectObject): def __init__(self): self.accept('mouse1', self.onMouse1Down, []) # Left click self.accept('mouse1-up', self.onMouse1Up, []) self.accept('mouse3', self.onMouse3Down, []) # Right click self.showCollisions = False pickerNode = CollisionNode('mouseRay') pickerNP = camera.attachNewNode(pickerNode) pickerNode.setFromCollideMask(cardBuilder.cardCollisionMask) self.pickerRay = CollisionRay() pickerNode.addSolid(self.pickerRay) base.cTrav.addCollider(pickerNP, base.handler) if self.showCollisions: base.cTrav.showCollisions(render) base.disableMouse() self.activeCard = None self._targeting = False self._dragging = None # Counts down between clicks to detect double click self.doubleClickTimer = -1.0 self.doubleClickInterval = 1.0 self.line = attackLine.Line() @property def targeting(self): return self._targeting @targeting.setter def targeting(self, value): self._targeting = value if self._targeting: base.guiScene.showTargeting() else: base.guiScene.hideTargeting() def startTargeting(self, targetDesc, callback=None): base.targetDesc = targetDesc self.targeting = True if callback is not None: base.targetCallback = callback def getObjectClickedOn(self): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) base.cTrav.traverse(render) if (base.handler.getNumEntries() > 0): base.handler.sortEntries() pickedObj = base.handler.getEntry(0).getIntoNodePath() pickedObj = pickedObj.findNetPythonTag('zone') if pickedObj == self.dragging and base.handler.getNumEntries() > 1: for entry in base.handler.getEntries(): n = entry.getIntoNodePath().findNetPythonTag('zone') if n != self.dragging and n.parent != self.dragging: return n # If we don't find another object, do nothing # TODO: Every object should only have 1 collider to make this easier return pickedObj def doClick(self): pickedObj = self.getObjectClickedOn() if self.dragging: return if self.targeting and pickedObj is not None: base.targetCallback(pickedObj) elif pickedObj and not pickedObj.isEmpty(): zone = pickedObj.getPythonTag('zone') if zone is base.player.hand and not base.gameState.hasMulliganed: c = pickedObj.getPythonTag('card') if c in base.toMulligan: base.toMulligan.remove(c) base.audioMaster.mulliganSelectSound.play() else: base.toMulligan.append(c) base.audioMaster.mulliganDeselectSound.play() base.zoneMaker.makeMulliganHand() elif zone is base.player.hand: self.dragging = pickedObj elif zone is base.player.facedowns: c = pickedObj.getPythonTag('card') if self.activeCard: self.activeCard = None elif c.requiresTarget: self.startTargeting(c.targetDesc) def callback(target): base.revealFacedown(pickedObj, target) base.finishTargeting() base.targetCallback = callback else: base.revealFacedown(pickedObj) elif zone is base.player.faceups: c = pickedObj.getPythonTag('card') if not c.hasAttacked: self.activeCard = pickedObj elif zone is base.enemy.facedowns and self.activeCard: base.attack(self.activeCard, pickedObj) self.activeCard = None elif zone == base.enemy.faceups and self.activeCard: base.attack(self.activeCard, pickedObj) self.activeCard = None elif zone is base.enemy.face and self.activeCard: base.attack(self.activeCard, pickedObj) self.activeCard = None else: self.activeCard = None @property def dragging(self): return self._dragging @dragging.setter def dragging(self, obj): if obj is None: self._dragging.removeNode() base.zoneMaker.makePlayerHand() # Put the card back else: obj.reparentTo(base.zoneMaker.scene) obj.setHpr(0, -90, 0) self._dragging = obj def stopDragging(self): """ Stop dragging the card and play it if it's in the drop zone """ # Borders of the drop zone # If you drop the card outside the drop zone, # the action is cancelled pos = self._dragging.getPos() if inDropZone(pos): try: target = None c = self.dragging.getPythonTag('card') if c.fast: pickedObj = self.getObjectClickedOn() if pickedObj is not None and pickedObj != self.dragging: target = pickedObj elif c.requiresTarget: # don't fizzle if no valid target self.dragging = None return base.playCard(self._dragging, target) except IllegalMoveError as e: print(e) self.dragging = None def onMouse1Down(self): if self._dragging is not None: self.stopDragging() self.doubleClickTimer = -1 elif self.doubleClickTimer <= 0: self.doubleClickTimer = 0.2 try: self.doClick() except IllegalMoveError as e: print(e) def onMouse1Up(self): if self._dragging and self.doubleClickTimer <= 0: self.stopDragging() def onMouse3Down(self): if self.targeting: base.targetCallback(None) if self.dragging: self.dragging = None def mouseToXYPlane(self): mpos = base.mouseWatcherNode.getMouse() # See the Panda3d chess example self.pickerRay.setFromLens( base.camNode, mpos.getX(), mpos.getY()) # Get a vector relative to the camera position nearPoint = render.getRelativePoint( camera, self.pickerRay.getOrigin()) nearVec = render.getRelativeVector( camera, self.pickerRay.getDirection()) return PointAtZ(.5, nearPoint, nearVec) def mouseOverTask(self): if base.mouseWatcherNode.hasMouse(): if self.doubleClickTimer > 0: # Count down based on how long it took to draw the last frame self.doubleClickTimer -= globalClock.getDt() if hasattr(self, '_activeObj') and self._activeObj is not None: zone = self._activeObj.getPythonTag('card').zone if zone is base.player.facedowns or zone is base.enemy.facedowns: zoneMaker.hideCard(self._activeObj) base.zoneMaker.unfocusCard() self._activeObj = None if self.dragging is not None: # Drag the card in the XY plane self.dragging.setPos(self.mouseToXYPlane()) elif base.gameState.hasMulliganed: pickedObj = self.getObjectClickedOn() if pickedObj: card = pickedObj.getPythonTag('card') if card is not None and not pickedObj.getPythonTag('disableFocus'): self._activeObj = pickedObj if card.zone in ( base.enemy.hand, base.player.facedowns, base.enemy.facedowns): zoneMaker.showCard(pickedObj) base.zoneMaker.focusCard(pickedObj) if self.activeCard: basePos = (pickedObj.getPos(base.render) if pickedObj is not None and not pickedObj.isEmpty() else self.mouseToXYPlane()), self.line.draw( start=self.activeCard.getPos(base.render), end=basePos) else: self.line.clear()
class LocationSeeker: def __init__(self, avatar, minDistance, maxDistance, shadowScale=1): self.dropShadowPath = 'phase_3/models/props/square_drop_shadow.bam' self.rejectSoundPath = 'phase_4/audio/sfx/ring_miss.ogg' self.moveShadowTaskName = 'Move Shadow' self.locationSelectedName = 'Location Selected' self.dropShadow = None self.shadowScale = shadowScale self.rejectSfx = loader.loadSfx(self.rejectSoundPath) self.avatar = avatar self.cameraNode = None self.cameraRay = None self.cameraNP = None self.shadowNP = None self.shadowRay = None self.minDistance = minDistance self.maxDistance = maxDistance self.legacyMode = False self.collHdlFl = CollisionHandlerQueue() self.moveShadowEventName = 'LocationSeeker-MoveShadow' return def startSeeking(self): if not self.avatar: return self.cleanupShadow() self.buildShadow() scale = self.dropShadow.getScale() if scale < 1.0: self.maxDistance += 40 x, y, z = self.avatar.getPos(render) self.dropShadow.reparentTo(render) self.dropShadow.setPos(x, y + 5, z + 2) self.cameraNode = CollisionNode('coll_camera') self.cameraNode.setFromCollideMask(CIGlobals.WallBitmask) self.cameraRay = CollisionRay() self.cameraNode.addSolid(self.cameraRay) self.cameraNP = camera.attachNewNode(self.cameraNode) base.cTrav.addCollider(self.cameraNP, CollisionHandlerQueue()) if not self.legacyMode: shadowNode = CollisionNode('coll_shadow') self.shadowRay = CollisionRay(0, 0, 6, 0, 0, -1) shadowNode.addSolid(self.shadowRay) shadowNode.setFromCollideMask(CIGlobals.FloorBitmask) self.shadowNP = self.dropShadow.attachNewNode(shadowNode) base.cTrav.addCollider(self.shadowNP, self.collHdlFl) base.taskMgr.add(self.__moveShadow, self.moveShadowTaskName) self.avatar.acceptOnce('mouse1', self.locationChosen) def stopSeeking(self): base.taskMgr.remove(self.moveShadowTaskName) def __moveShadow(self, task): if base.mouseWatcherNode.hasMouse(): prevPos = self.dropShadow.getPos(render) def PointAtZ(z, point, vec): if vec.getZ() != 0: return point + vec * ((z - point.getZ()) / vec.getZ()) return self.getLocation() mouse = base.mouseWatcherNode.getMouse() self.cameraRay.setFromLens(base.camNode, mouse.getX(), mouse.getY()) nearPoint = render.getRelativePoint(camera, self.cameraRay.getOrigin()) nearVec = render.getRelativeVector(camera, self.cameraRay.getDirection()) self.dropShadow.setPos(PointAtZ(0.5, nearPoint, nearVec)) if (prevPos - self.dropShadow.getPos(render)).length() >= 0.25: messenger.send(self.moveShadowEventName) if self.legacyMode: self.dropShadow.setZ(base.localAvatar.getZ(render) + 0.5) elif self.collHdlFl.getNumEntries() > 0: self.dropShadow.setZ( self.collHdlFl.getEntry(0).getSurfacePoint(render).getZ() + 0.5) return Task.cont def locationChosen(self): base.taskMgr.remove(self.moveShadowTaskName) distance = self.avatar.getDistance(self.dropShadow) x, y, z = self.getLocation() if distance >= self.minDistance and distance <= self.maxDistance: gag = self.avatar.getBackpack().getActiveGag() self.avatar.sendUpdate('setDropLoc', [gag.getID(), x, y, z]) messenger.send(self.locationSelectedName) else: self.rejectSfx.play() self.avatar.acceptOnce('mouse1', self.locationChosen) base.taskMgr.add(self.__moveShadow, self.moveShadowTaskName) def buildShadow(self): self.cleanupShadow() if not self.dropShadowPath or not self.avatar: return self.dropShadow = loader.loadModel(self.dropShadowPath) self.dropShadow.setScale(self.shadowScale) self.dropShadow.setName('LocationSeeker_Shadow') def setShadowType(self, isCircle=False, scale=1): if not isCircle: self.dropShadowPath = 'phase_3/models/props/square_drop_shadow.bam' else: self.dropShadowPath = 'phase_3/models/props/drop_shadow.bam' self.shadowScale = scale def getDropShadow(self): return self.dropShadow def getLocation(self): if self.dropShadow: return self.dropShadow.getPos(render) return self.avatar.getPos(render) def getLocationSelectedName(self): return self.locationSelectedName def getShadowMovedName(self): return self.moveShadowEventName def cleanupShadow(self): if self.dropShadow: self.dropShadow.removeNode() self.dropShadow = None if self.cameraNode: self.cameraNP.removeNode() self.cameraNP = None self.cameraNode = None self.cameraRay = None self.shadowNP.removeNode() self.shadowRay = None self.shadowNP = None self.shadowSphNP = None return def cleanup(self): if self.avatar: base.taskMgr.remove(self.moveShadowTaskName) self.avatar.ignore('mouse1') self.cleanupShadow() self.rejectSfx.stop() self.rejectSfx = None self.avatar = None self.dropShadowPath = None self.rejectSoundPath = None self.locationSelectedName = None self.moveShadowTaskName = None self.moveShadowEventName = None self.collHdlFl = None del self.collHdlFl del self.minDistance del self.maxDistance del self.legacyMode del self.dropShadow del self.cameraNP del self.cameraNode del self.cameraRay del self.shadowNP del self.shadowRay del self.shadowSphNP del self.shadowScale del self.rejectSfx del self.avatar del self.dropShadowPath del self.rejectSoundPath del self.locationSelectedName del self.moveShadowTaskName del self.moveShadowEventName return
class World(DirectObject): mySound = base.loader.loadSfx("trial.mp3") #Used for adding a virus at a randomly generated position def random_vgen(self): print 'I am in random' for i in range(0,5): self.a[random.randint(0,7)][random.randint(0,7)] = 1 def initializer(self,level): self.turns = 0 ## Level Definition def levelone(): self.a[4][4] = 1 self.a[4][5] = 1 self.a[4][6] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[4][6] = 1 self.a[5][5] = 1 def leveltwo(): self.a[4][3] = 1 self.a[4][5] = 1 self.a[4][7] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[2][2] = 1 self.a[5][3] = 1 self.a[1][2] = 1 def levelthree(): self.a[4][4] = 1 self.a[4][5] = 1 self.a[4][6] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[4][6] = 1 self.a[5][5] = 1 self.a[4][3] = 1 self.a[4][5] = 1 self.a[4][7] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[2][2] = 1 self.a[5][3] = 1 options = {1: levelone, 2: leveltwo, 3: levelthree } options[level]() print self.a temp = [] count = 0 for element in reversed(self.a): for ele in element: #print 'cheking element is 1 : ' + str(ele) if ele == 1: temp.append(count) self.pieces[count] = Monster(count,WHITE) #self.squares[count].setColor(HIGHLIGHT) count = count + 1 self.list=temp def showscore(self): try: self.score.destroy() except: pass self.score = OnscreenText(text = 'Number of Turns : %s'%(self.turns), pos = (0.5, 0.95), scale = 0.07, mayChange = True) def menuscreen(self): # Callback function to set text def setText(): b.destroy() helptext.destroy() # Add button b = DirectButton(text = ("START", "START", "START", "disabled"), scale=0.15, command=setText, pos=(0,0,0.85)) helptext = OnscreenText(text =''' STORY: Hello Mad Scientist! You are so close to finding the cure to aids! You understood the behaviour and can finally manipulate the virus to kill itself! But time is running out! You have a red and white blood cell sample infected with AIDS Virus. INSTRUCTIONS: The AIDS Virus obeys the Conway's Game of Life. Who would have guessed? 1. If virus is surrounded by more than 3 viruses, it dies of suffocation 2. If virus is surrounded by less than 2 viruses, it dies of underpopulation 3. If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned due to breeding. AIM: To kill all the viruses, by moving one of them every turn. ''', pos = (-0.90,0.72),frame = (123,123,123,1), wordwrap = 25, align = TextNode.ALeft, bg = (0.23,0.243,0.13,0.9)) def endscreen(self): def restart(): taskMgr.remove(self.mouseTask) for i in range(64): self.squares[i].setColor(SquareColor(i)) scorecard.destroy() restartb.destroy() end.destroy() nextlevelb.destroy() self.reference.destroy() self.mySound.stop() try: self.score.destroy() except: pass print 'restarting' print self.a print self.list World() def quitgame(): sys.exit() def nextLevel(): self.currlevel = self.currlevel + 1 nextlevelb.destroy() scorecard.destroy() restartb.destroy() end.destroy() self.score.destroy() self.initializer(self.currlevel) # Add button scorecard = OnscreenText(text = 'You finished it in %s turns! '%(self.turns),frame = (123,123,123,0), wordwrap = 25, bg = (0.2,0,0.8,1)) nextlevelb = DirectButton(text = ("NEXT LEVEL", "NEXT LEVEL", "NEXT LEVEL", "disabled"), scale=0.15, command=nextLevel, pos=(0,0,-0.15)) restartb = DirectButton(text = ("RESTART", "RESTART", "RESTART", "disabled"), scale=0.15, command=restart, pos=(0,0,-0.35)) end = DirectButton(text = ("QUIT", "QUIT", "QUIT", "disabled"), scale=0.15, command=quitgame, pos=(0,0,-0.55)) if self.currlevel == self.maxlevel: nextlevelb.destroy() def __init__(self): #music self.mySound.play() print 'I am being initialized' self.menuscreen() self.list = [] self.turns = 0 self.maxlevel = 3 self.currlevel = 1 self.a =[[0 for x in range(8)] for y in range(8)] #This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Game of Life : Help in ending AIDS!", style=1, fg=(1,1,1,1), pos=(0,-0.95), scale = .07) self.escapeEvent = OnscreenText( text="ESC: Quit", style=1, fg=(1,1,1,1), pos=(-1.3, 0.95), align=TextNode.ALeft, scale = .05) ## self.mouse1Event = OnscreenText( ## text="Left-click and drag: Pick up virus and drag it to a new bloodcell", ## style=1, fg=(1,1,1,1), pos=(-1.3, 0.90), ## align=TextNode.ALeft, scale = .05) ## self.accept('escape', sys.exit) #Escape quits base.disableMouse() #Disble mouse camera control camera.setPosHpr(0, -13.75, 6, 0, -25, 0) #Set the camera self.setupLights() #Setup default lighting #Since we are using collision detection to do picking, we set it up like #any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() #Make a traverser self.pq = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') #Attach that node to the camera since the ray will need to be positioned #relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() #Make our ray self.pickerNode.addSolid(self.pickerRay) #Add it to the collision node #Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) #self.picker.showCollisions(render) #We will attach all of the squares to their own root. This way we can do the #collision pass just on the sqaures and save the time of checking the rest #of the scene self.squareRoot = render.attachNewNode("squareRoot") #For each square self.squares = [None for i in range(64)] self.pieces = [None for i in range(64)] for i in range(64): #Load, parent, color, and position the model (a single square polygon) self.squares[i] = loader.loadModel("models/square") self.squares[i].reparentTo(self.squareRoot) self.squares[i].setPos(SquarePos1(i)) self.squares[i].setColor(SquareColor(i)) #Set the model itself to be collideable with the ray. If this model was #any more complex than a single polygon, you should set up a collision #sphere around it instead. But for single polygons this works fine. self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) #Set a tag on the square's node so we can look up what square this is #later during the collision pass self.squares[i].find("**/polygon").node().setTag('square', str(i)) #We will use this variable as a pointer to whatever piece is currently #in this square self.initializer(self.currlevel) #This will represent the index of the currently highlited square self.hiSq = False #This wil represent the index of the square where currently dragged piece #was grabbed from self.dragging = False #Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') #self.trial = taskMgr.add(self.trial,'trial') self.accept("mouse1", self.grabPiece) #left-click grabs a piece self.accept("mouse1-up", self.releasePiece) #releasing places it #This function swaps the positions of two pieces def swapPieces(self, fr, to): temp = self.pieces[fr] self.pieces[fr] = self.pieces[to] self.pieces[to] = temp if self.pieces[fr]: print 'imma swapping' self.pieces[fr].square = fr print fr print SquarePos(fr) try: self.pieces[fr].obj.setPos(SquarePos(fr)) except: pass print 'done' if self.pieces[to]: self.pieces[to].square = to try: self.pieces[to].obj.setPos(SquarePos(to)) except: pass def trial(self): self.turns = self.turns + 1 try: self.reference.destroy() except: pass self.reference = OnscreenText( text=''' Reference: virus is surrounded by more than 3 viruses, it dies virus is surrounded by less than 2 viruses, it dies If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned. ''' , style=1, fg=(1,1,1,1), pos=(-1, 0.95), align=TextNode.ALeft, scale = .05) self.showscore() a = self.a while True: for i in self.list: #insert deletion code print 'imma deleting the sq : ' + str(i) self.pieces[i].obj.delete() self.squares[i].setColor(SquareColor(i)) count = 0 a=[[([[sum(b[y1][x1] for b in [[[((-1<x2+dx<len(a[0])) and (-1<y2+dy<len(a))) and a[y2+dy][x2+dx] or 0 for x2 in range(len(a[0]))] for y2 in range(len(a))] for (dx,dy) in [(dx,dy) for dx in [-1,0,1] for dy in [-1,0,1] if (dy!=0 or dx!=0)]]) for x1 in range(len(a[0]))] for y1 in range(len(a))][y][x]== 3 or ([[sum(c[y3][x3] for c in [[[((-1<x4+dx<len(a[0])) and (-1<y4+dy<len(a))) and a[y4+dy][x4+dx] or 0 for x4 in range(len(a[0]))] for y4 in range(len(a))] for (dx,dy) in [(dx,dy) for dx in [-1,0,1] for dy in [-1,0,1] if (dy!=0 or dx!=0)]]) for x3 in range(len(a[0]))] for y3 in range(len(a))][y][x] == 2 and a[y][x]==1)) and 1 or 0 for x in range(len(a[0]))] for y in range(len(a))] lis = [] #insert a random virus at a probability of 1/5 diceroll = random.randint(0,5) if diceroll == 2: self.random_vgen() for element in reversed(a): for ele in element: #print 'cheking element is 1 : ' + str(ele) if ele == 1: lis.append(count) count = count + 1 print lis self.list = lis self.a = a print self.list for i in self.list: self.pieces[i] = Monster(i,WHITE) #self.squares[i].setColor(HIGHLIGHT) print 'leaving trial' if len(self.list)==0: self.endscreen() break return def mouseTask(self, task): #This task deals with the highlighting and dragging based on the mouse #First, clear the current highlight if self.hiSq is not False: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = False #Check to see if we can access the mouse. We need it to do anything else 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()) #If we are dragging something, set the position of the object #to be at the appropriate point over the plane of the board if self.dragging is not False: #Gets the point described by pickerRay.getOrigin(), which is relative to #camera, relative instead to render nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin()) #Same thing with the direction of the ray nearVec = render.getRelativeVector(camera, self.pickerRay.getDirection()) try: self.pieces[self.dragging].obj.setPos(PointAtZ(.5, nearPoint, nearVec)) except: pass #Do the actual collision pass (Do it only on the squares for #efficiency purposes) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: #if we have hit something, sort the hits so that the closest #is first, and highlight that node self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) #Set the highlight on the picked square self.squares[i].setColor(HIGHLIGHT) self.hiSq = i #print 'selected is ' + str(i) return Task.cont def grabPiece(self): #If a square is highlighted and it has a piece, set it to dragging mode if (self.hiSq is not False and self.pieces[self.hiSq]): self.dragging = self.hiSq self.hiSq = False def releasePiece(self): #Letting go of a piece. If we are not on a square, return it to its original #position. Otherwise, swap it with the piece in the new square if self.dragging is not False: #Make sure we really are dragging something #We have let go of the piece, but we are not on a square if self.hiSq is False: try: self.pieces[self.dragging].obj.setPos(SquarePos(self.dragging)) except: pass else: #Otherwise, swap the pieces self.swapPieces(self.dragging, self.hiSq) #self.draggin is the from print self.list print 'you picked this, so Imma deleting this ' + str(self.dragging) #deletion of i after picking it up. try: self.list.remove(self.dragging) except: pass temp2 = [] temp2 = SquarePosTuple(self.dragging) self.a[temp2[0]][temp2[1]] = 0 i = self.hiSq print self.list print 'highlighted sq is ' + str(i) templis = [] templis = SquarePosTuple(i) print templis self.list.append(i) print self.list print templis self.a[templis[0]][templis[1]] = 1 for line in self.a: print line self.trial() #We are no longer dragging anything self.dragging = False def setupLights(self): #This function sets up some default lighting ambientLight = AmbientLight( "ambientLight" ) ambientLight.setColor( Vec4(.8, .8, .8, 1) ) directionalLight = DirectionalLight( "directionalLight" ) directionalLight.setDirection( Vec3( 0, 45, -45 ) ) directionalLight.setColor( Vec4( 0.2, 0.2, 0.2, 1 ) ) render.setLight(render.attachNewNode( directionalLight ) ) render.setLight(render.attachNewNode( ambientLight ) )
class ChessboardDemo(ShowBase): def calculatePossiblePositions(self, startingPos, movementArray): possibleIndexes = [] multiplierArray = [[7, 8, 9], [-1, 1], [-9, -8, -7]] for i in range(0, 3): for j in range(0, 3): if (i == 1 and j == 2): continue for k in range(1, movementArray[i][j] + 1): possibleIndex = startingPos + k * multiplierArray[i][j] if possibleIndex < 64 and possibleIndex >= 0: possibleIndexes.append(startingPos + k * multiplierArray[i][j]) return list(set(possibleIndexes)) def getAllCollidingPositions(self, startingPos, possibleEndPositions): collisions = [] for possibleEndPosition in possibleEndPositions: if (not isinstance(self.pieces[possibleEndPosition], type(None))): if (self.pieces[possibleEndPosition].obj.getColor() == self.turn): collisions.append(possibleEndPosition) return collisions def getDirectionMultiplier(self, startingPos, endPos): temp = endPos - startingPos if temp < 0: if temp % -8 == 0: return -8 elif temp % -9 == 0: return -9 elif temp % -7 == 0: return -7 else: return -1 else: if temp % 8 == 0: return 8 elif temp % 7 == 0: return 7 elif temp % 9 == 0: return 9 else: return 1 def checkCollisionInLine(self, startingPos, endPos, collidingPositions): if endPos in collidingPositions: return True else: directionalMultiplier = self.getDirectionMultiplier( startingPos, endPos) positionsOnTheLine = [] temp = startingPos + directionalMultiplier while temp != endPos: positionsOnTheLine.append(temp) temp += directionalMultiplier for position in positionsOnTheLine: if (isinstance(self.pieces[position], Piece)): return True return False def checkIfRoutePossible(self, startingPos, endPos, movementArray): if (isinstance(self.pieces[startingPos], Knight)): endPositions = [] for i in movementArray: endPositions.append(startingPos + i) if endPos in endPositions: return True else: return False if (self.turn == PIECEBLACK and isinstance(self.movingPiece, Pawn)): movementArray = list(reversed(movementArray)) listOfPossiblePositions = self.calculatePossiblePositions( startingPos, movementArray) #listOfPossiblePositions.remove(startingPos) listOfCollidingPositions = self.getAllCollidingPositions( startingPos, listOfPossiblePositions) if endPos in listOfPossiblePositions: if not self.checkCollisionInLine(startingPos, endPos, listOfCollidingPositions): return True return False def __init__(self): ShowBase.__init__(self) self.turn = WHITE self.movingPiece = None self.isMovementPossible = False self.escapeEvent = OnscreenText(text="ESC: Quit", parent=base.a2dTopLeft, style=1, fg=(1, 1, 1, 1), pos=(0.06, -0.1), align=TextNode.ALeft, scale=.05) self.mouse1Event = OnscreenText( text="Left-click and drag: Pick up and drag piece", parent=base.a2dTopLeft, align=TextNode.ALeft, style=1, fg=(1, 1, 1, 1), pos=(0.06, -0.16), scale=.05) self.accept('escape', sys.exit) # Escape quits self.disableMouse() # Disble mouse camera control camera.setPosHpr(0, -12, 8, 0, -35, 0) self.setupLights() self.picker = CollisionTraverser() # Make a traverser self.pq = CollisionHandlerQueue() # Make a handler self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() # Make our ray # Add it to the collision node self.pickerNode.addSolid(self.pickerRay) # Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) self.squareRoot = render.attachNewNode("squareRoot") # For each square self.squares = [None for i in range(64)] self.pieces = [None for i in range(64)] for i in range(64): # Load, parent, color, and position the model (a single square # polygon) self.squares[i] = loader.loadModel("models/square") self.squares[i].reparentTo(self.squareRoot) self.squares[i].setPos(SquarePos(i)) self.squares[i].setColor(SquareColor(i)) self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) self.squares[i].find("**/polygon").node().setTag('square', str(i)) pieceOrder = (Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook) for i in range(8, 16): # Load the white pawns self.pieces[i] = Pawn(i, WHITE) for i in range(48, 56): # load the black pawns self.pieces[i] = Pawn(i, PIECEBLACK) for i in range(8): # Load the special pieces for the front row and color them white self.pieces[i] = pieceOrder[i](i, WHITE) # Load the special pieces for the back row and color them black self.pieces[i + 56] = pieceOrder[i](i + 56, PIECEBLACK) # This will represent the index of the currently highlited square self.hiSq = False # This wil represent the index of the square where currently dragged piece # was grabbed from self.dragging = False # Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') self.accept("mouse1", self.grabPiece) # left-click grabs a piece self.accept("mouse1-up", self.releasePiece) # releasing places it # This function swaps the positions of two pieces def swapPieces(self, fr, to): temp = self.pieces[fr] self.pieces[fr] = self.pieces[to] self.pieces[to] = temp if self.pieces[fr]: self.pieces[fr].square = fr self.pieces[fr].obj.setPos(SquarePos(fr)) if self.pieces[to]: self.pieces[to].square = to self.pieces[to].obj.setPos(SquarePos(to)) def trashPiece(self, index): self.pieces[index].obj.setPos(trash()) self.pieces[index] = None def mouseTask(self, task): if self.hiSq is not False: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = False if self.mouseWatcherNode.hasMouse(): # get the mouse position mpos = self.mouseWatcherNode.getMouse() # Set the position of the ray based on the mouse position self.pickerRay.setFromLens(self.camNode, mpos.getX(), mpos.getY()) # If we are dragging something, set the position of the object # to be at the appropriate point over the plane of the board if self.dragging is not False: # Gets the point described by pickerRay.getOrigin(), which is relative to # camera, relative instead to render nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin()) # Same thing with the direction of the ray nearVec = render.getRelativeVector( camera, self.pickerRay.getDirection()) self.pieces[self.dragging].obj.setPos( PointAtZ(.5, nearPoint, nearVec)) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) # Set the highlight on the picked square if (self.dragging != False or (isinstance(self.pieces[i], Piece) and self.pieces[i].obj.getColor() == self.turn)): if (isinstance(self.movingPiece, Piece)): if (isinstance(self.pieces[i], Piece) and self.pieces[i].obj.getColor() != self.turn): movementTable = self.movingPiece.getMovementTableBattle( ) else: movementTable = self.movingPiece.getMovmentTableNoBattle( ) if (self.checkIfRoutePossible(self.movingPieceIndex, i, movementTable)): self.squares[i].setColor(HIGHLIGHT_POSITIVE) self.isMovementPossible = True else: self.squares[i].setColor(HIGHLIGHT_NEGATIVE) self.isMovementPossible = False self.hiSq = i return Task.cont def grabPiece(self): if self.hiSq is not False and self.pieces[self.hiSq]: self.movingPiece = self.pieces[self.hiSq] self.movingPieceIndex = self.hiSq self.dragging = self.hiSq self.hiSq = False def releasePiece(self): if self.dragging is not False: if self.hiSq is False or not self.isMovementPossible or ( isinstance(self.pieces[self.dragging], Piece) and isinstance(self.pieces[self.hiSq], Piece) and self.pieces[self.dragging].obj.getColor() == self.pieces[self.hiSq].obj.getColor()): self.pieces[self.dragging].obj.setPos(SquarePos(self.dragging)) else: # Otherwise, swap the pieces self.swapPieces(self.dragging, self.hiSq) if (isinstance(self.pieces[self.dragging], Piece) and self.dragging != self.hiSq and self.pieces[self.dragging].obj.getColor() != self.pieces[self.hiSq].obj.getColor()): self.trashPiece(self.dragging) print('trashed') if (not isinstance(self.movingPiece, type(None)) and self.movingPiece.isPawn() and self.dragging != self.hiSq): self.movingPiece.setFirstMove(False) self.isCheck(self.hiSq) self.changeTurn() self.dragging = False self.movingPiece = None self.movingPieceIndex = -1 def setupLights(self): # This function sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.8, .8, .8, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(LVector3(0, 45, -45)) directionalLight.setColor((0.2, 0.2, 0.2, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight)) def changeTurn(self): if self.turn == WHITE: self.turn = PIECEBLACK else: self.turn = WHITE def isCheck(self, index): kingIndex = 0 for i in range(0, 64): if (isinstance(self.pieces[i], King) and self.pieces[i].obj.getColor() != self.turn): kingIndex = i for j in range(0, 64): if (isinstance(self.pieces[index], Piece) and self.pieces[index].obj.getColor() == self.turn): if (self.checkIfRoutePossible( index, kingIndex, self.pieces[index].getMovementTableBattle())): global check print("CHECK FOUND") label = "white" if self.turn == WHITE: label = "black" check = OnscreenText(text="Check on " + label + " king", parent=base.a2dTopLeft, align=TextNode.ALeft, style=1, fg=(1, 1, 1, 1), pos=(0.06, -0.26), scale=.05) elif (not isinstance(check, type(None))): print("Should remove now") check.destroy() check = None
class World(DirectObject): def __init__(self, mode, ip=None): if mode==CLIENT and not ip: #Don't let this happen. print "WTF programmer" sys.exit() #current dialog box self.d = None #top-left of screen; contains instructions on how to exit the game. self.quitInstructions = OnscreenText(text='Press ESC to exit.', pos=(-1, 0.95), scale=0.05, fg=(1,1,1,1), bg=(0,0,0,0), mayChange=False) #bottom of screen self.turnIndicator = OnscreenText(text='', pos=(0,-0.8), scale=0.1, fg=(1,1,1,1), bg=(0,0,0,0), mayChange=True) #Saving some values, some default values self.mode = mode self.player = {SERVER: PIECEWHITE, CLIENT: PIECEBLACK}[self.mode] self.ip = ip #Panda3D, by default, allows for camera control with the mouse. base.disableMouse() self.setupMouse() self.setupBoard() self.setupCamera() self.setupPieces() self.setupNetwork() self.setupLights() #some internal state for making clicky moves self.hiSq = None self.dragOrigin = None #keyboard, mouse self.mouseTask = taskMgr.add(self.tskMouse, 'mouseTask') self.accept('mouse1', self.handleClick) self.accept('f2', lambda: base.setFrameRateMeter(True)) self.accept('f3', lambda: base.setFrameRateMeter(False)) self.accept('escape', sys.exit) #first turn self.turn = PIECEWHITE #### INITIALIZATION #### def setupBoard(self): #We will attach all of the squares to their own root. This way we can do the #collision pass just on the sqaures and save the time of checking the rest #of the scene self.squareRoot = render.attachNewNode("squareRoot") #For each square self.squares = dict(((i,j), None) for i in range(8) for j in range(8)) for place in self.squares: #Load, parent, color, and position the model (a single square polygon) self.squares[place] = loader.loadModel("models/square") self.squares[place].reparentTo(self.squareRoot) self.squares[place].setPos(SquarePos(place)) self.squares[place].setColor(SquareColor(place)) #Set the model itself to be collideable with the ray. If this model was #any more complex than a single polygon, you should set up a collision #sphere around it instead. But for single polygons this works fine. self.squares[place].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) #Set a tag on the square's node so we can look up what square this is #later during the collision pass self.squares[place].find("**/polygon").node().setTag('square', ' '.join(map(str,place))) self.squares[place].setTransparency(TransparencyAttrib.MAlpha) def setupPieces(self): #Default dictionaries work decently well as an easy two-dimensional array. self.pieces = defaultdict(lambda: None) #The order of pieces on a chessboard from white's perspective pieceOrder = [Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook] for i in xrange(8): #load white pawns self.pieces[i, 1] = Pawn((i,1), PIECEWHITE) #load black pawns self.pieces[i, 6] = Pawn((i, 6), PIECEBLACK) #load white specials self.pieces[i, 0] = pieceOrder[i]((i,0), PIECEWHITE) #load black specials self.pieces[i, 7] = pieceOrder[i]((i,7), PIECEBLACK) for p in self.pieces.values(): p.obj.setTransparency(TransparencyAttrib.MAlpha) # TODO: Notice when the other side disconnects def setupNetwork(self): if self.mode == CLIENT: self.setupClient(self.ip) else: self.setupServer() # A lot of the below two methods is boilerplate straight from Panda3D documentation. def setupServer(self): self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.oppConnection = None port = 15905 # Chosen by fair dice roll. # Guaranteed to be random. backlog = 1000 tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cListener.addConnection(tcpSocket) def tskListenerPoll(task): if self.cListener.newConnectionAvailable() and not self.oppConnection: rendezvous = PointerToConnection() addr = NetAddress() newCon = PointerToConnection() if self.cListener.getNewConnection(rendezvous, addr, newCon): newConnection = newCon.p() print "Received connection from %s" % newConnection.getAddress() self.oppConnection = newConnection self.cReader.addConnection(newConnection) #server starts the game self.turnIndicator['text'] = 'Your turn!' self.showVisibleSquares() #remove the dialog node from below if self.d: self.d.removeNode() return Task.done if not self.d: self.d = DirectDialog(text="Waiting for client to connect...", buttonTextList=[], buttonValueList=[]) return Task.cont taskMgr.add(tskListenerPoll, "Poll the connection listener") taskMgr.add(self.tskReaderPoll, "Poll the connection reader") def setupClient(self, ip): self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.oppConnection = None port = 15905 timeout = 3000 myConnection = self.cManager.openTCPClientConnection(ip, port, timeout) if myConnection: self.cReader.addConnection(myConnection) self.oppConnection = myConnection taskMgr.add(self.tskReaderPoll, "Poll the connection reader") self.showVisibleSquares() else: self.d = OkDialog(text="Could not connect to server at '%s'" % ip, command=sys.exit) # Makes sure player gets a decent view of the game board, and *not* of the hidden pieces below the board. Shhhh... def setupCamera(self): if self.player == PIECEWHITE: camera.setPos(0, -13.75, 8) camera.lookAt(self.squareRoot) camera.setH(0) else: camera.setPos(0, 13.75, 8) camera.lookAt(self.squareRoot) camera.setH(180) # Adds some ambient lights and a directional light def setupLights(self): #This is one area I know hardly anything about. I really don't know how to get this to behave nicely. #The black pieces are hardly distinguishable. ambientLight = AmbientLight( "ambientLight" ) ambientLight.setColor( Vec4(.8, .8, .8, 1) ) directionalLight = DirectionalLight( "directionalLight" ) directionalLight.setDirection( Vec3( 0, 45, -45 ) ) directionalLight.setColor( Vec4( 0.2, 0.2, 0.2, 1 ) ) render.setLight(render.attachNewNode( directionalLight ) ) render.setLight(render.attachNewNode( ambientLight ) ) # Sets up collision detection for the mouse cursor. def setupMouse(self): #Since we are using collision detection to do picking, we set it up like #any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() #Make a traverser self.pq = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') #Attach that node to the camera since the ray will need to be positioned #relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() #Make our ray self.pickerNode.addSolid(self.pickerRay) #Add it to the collision node #Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) #### TASKS #### # Checks for incoming data on the connection def tskReaderPoll(self, task): if self.cReader.dataAvailable(): datagram = NetDatagram() if self.cReader.getData(datagram): self.receiveData(datagram) return Task.cont # Runs every frame, checks whether the mouse is highlighting something or another def tskMouse(self, task): #This task deals with the highlighting and dragging based on the mouse #First, clear the current highlight if self.hiSq: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = None #Check to see if we can access the mouse. We need it to do anything else 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()) #If we are dragging something, set the position of the object #to be at the appropriate point over the plane of the board if self.dragOrigin: #camera, relative instead to render #Gets the point described by pickerRay.getOrigin(), which is relative to nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin()) #Same thing with the direction of the ray nearVec = render.getRelativeVector(camera, self.pickerRay.getDirection()) self.pieces[self.dragOrigin].obj.setPos( PointAtZ(.5, nearPoint, nearVec)) #Do the actual collision pass (Do it only on the squares for #efficiency purposes) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: #if we have hit something, sort the hits so that the closest #is first, and highlight that node self.pq.sortEntries() p = tuple(map(int, (self.pq.getEntry(0).getIntoNode().getTag('square')).split())) if self.pieces[p] and self.pieces[p].color == self.turn == self.player and not self.dragOrigin or self.dragOrigin and self.pieces[self.dragOrigin].isValidMove(p, self.pieces): #Set the highlight on the picked square self.hiSq = p self.squares[self.hiSq].setColor(HIGHLIGHT) return Task.cont def handleClick(self): # Disabled when a dialog box is on-screen. Pay attention to what I'm telling you, user! if not self.d: if self.dragOrigin: self.releasePiece() else: self.grabPiece() # Comes from handleClick def grabPiece(self): #If a square is highlighted and it has a piece, set it to dragging mode if self.hiSq and self.pieces[self.hiSq] and self.pieces[self.hiSq].color == self.turn: self.dragOrigin = self.hiSq self.hiSq = None def releasePiece(self): #Letting go of a piece. If we are not on a square, return it to its original #position. if self.dragOrigin: #Make sure we really are dragging something if self.hiSq and self.hiSq != self.dragOrigin and self.pieces[self.dragOrigin].isValidMove(self.hiSq, self.pieces): # Verify that this doesn't put the king in check # Make backup of the pieces dictionary oldPieces = self.pieces.copy() self.pieces[self.hiSq] = self.pieces[self.dragOrigin] self.pieces[self.dragOrigin] = None if self.inCheck(self.turn): self.pieces = oldPieces self.pieces[self.dragOrigin].obj.setPos(SquarePos(self.dragOrigin)) print "Invalid move -- King is in check" def closeDialog(): self.d.removeNode() self.d = OkDialog(text="That move would put your King in check!", command=closeDialog) else: self.pieces = oldPieces self.makeMove(self.dragOrigin, self.hiSq, dt=0, callback=self.showVisibleSquares).start() self.sendMove(self.dragOrigin, self.hiSq) self.squares[self.dragOrigin].setColor(SquareColor(self.dragOrigin)) #no longer our turn self.turnIndicator['text'] = '' else: self.pieces[self.dragOrigin].obj.setPos(SquarePos(self.dragOrigin)) print "Invalid move" #We are no longer dragging anything self.dragOrigin = False #### CHESS UPDATES #### # Moves a piece from one space to another. # This should be called to update internal state, whether the piece is already in the correct location or not. # Also handles captures. def makeMove(self, fr, to, dt=1, callback=None): print "Making move %s -> %s" % (str(fr), str(to)) frP = self.pieces[fr] toP = self.pieces[to] if not frP: return False if toP and frP.color == toP.color: return False if not frP.isValidMove(to, self.pieces): return False # Callback function for the movement. # Updates pieces' internal state, as well as the true state of the board (self.pieces) def updateState(): self.destroy(toP) frP.square = to frP.haveMoved = True self.pieces[fr] = None self.pieces[to] = frP self.turn = flip[self.turn] if self.inCheck(self.player): def dismiss(val): self.d.removeNode() self.d = OkDialog(text="You are in check!", command=dismiss) s = Sequence( frP.obj.posInterval(dt, self.squares[to].getPos()), Func(updateState) ) if callback: s.append(Func(callback)) return s # Removes the piece. This method is passed a Piece object, not a location! # Possible improvements: Particle effects! :D def destroy(self, piece): if piece: piece.obj.removeNode() # Determines whether the player specified by "color" is in check at the current time # Future improvements: Calculate the same thing for possible future moves (i.e. if I move here am I therefore in check?) def inCheck(self, color): #find the king kingPlace = [p for p in self.pieces if self.pieces[p] and self.pieces[p].color == color and self.pieces[p].model == "models/king"][0] for p in self.pieces: if self.pieces[p] and self.pieces[p].color != color and self.pieces[p].isValidMove(kingPlace, self.pieces): return True return False # Currently unused, but could be useful in an (extremely primitive) AI in the future. # I ran out of time to put it in this version. def makeRandomMove(self): move = None while not move: chosenPiece = random.choice([(x,y) for (x,y) in self.pieces if 0 <= x < 8 and 0 <= y < 8 and self.pieces[x,y] and self.pieces[x,y].color == self.turn]) if not self.pieces[chosenPiece].validMoves(self.pieces): continue destSquare = random.choice([s for s in self.pieces[chosenPiece].validMoves(self.pieces)]) move = (chosenPiece, destSquare) self.makeMove(*move).start() #### VISIBILITY UPDATES #### def isVisible(self, sq): return self.squares[sq].getColorScale()[3] == 1.0 # The next two methods deal with hiding and showing the squares of the board. def hideSquare(self, sq, dt="default", callback=None): if self.squares[sq] and self.isVisible(sq): if dt == "default": dt = 1.0 par = Parallel( LerpFunctionInterval(self.squares[sq].setAlphaScale, toData=0.0, fromData=1.0, duration=dt), ) if self.pieces[sq]: par.append(LerpFunctionInterval(self.pieces[sq].obj.setAlphaScale, toData=0.0, fromData=1.0, duration=dt)) s = Sequence(par) if callback: s.append(Func(callback)) return s else: s = Sequence() if callback: s.append(Func(callback)) return s def showSquare(self, sq, dt="default", callback=None): if self.squares[sq] and not self.isVisible(sq): if dt == "default": dt = 1.0 par = Parallel( LerpFunctionInterval(self.squares[sq].setAlphaScale, toData=1.0, fromData=0.0, duration=dt), ) if self.pieces[sq]: par.append(LerpFunctionInterval(self.pieces[sq].obj.setAlphaScale, toData=1.0, fromData=0.0, duration=dt)) s = Sequence(par) if callback: s.append(Func(callback)) return s else: s = Sequence() if callback: s.append(Func(callback)) return s # Shows the path that a piece takes on its way IF any part of it is visible to the current player def showPathIfVisible(self, fr, to): if self.pieces[fr]: path = set() showSquareSequences = Parallel() if self.pieces[fr]: path.update(self.pieces[fr].path(to)) if any(self.isVisible(sq) for sq in path): for sq in path: showSquareSequences.append(self.showSquare(sq)) return showSquareSequences else: return Parallel() # Shows the path that a piece takes on its path from its origin to its destination def showPath(self, fr, to): path = set() showSquareSequences = Parallel() if self.pieces[fr]: path.update(self.pieces[fr].path(to)) for sq in path: showSquareSequences.append(self.showSquare(sq)) return showSquareSequences # Updates the board to show only the squares that are visible at the current time. def showVisibleSquares(self, dt="default"): visibles = defaultdict(lambda: False) for p in [(x,y) for (x,y) in self.pieces if 0 <= x < 8 and 0 <= y < 8]: if self.pieces[p]: if self.pieces[p].color == self.player: for s in self.pieces[p].visibleSquares(self.pieces): visibles[s] = True par = Parallel() for s in self.squares: if visibles[s]: par.append(self.showSquare(s, dt)) else: par.append(self.hideSquare(s, dt)) par.start() return par #### NETWORK I/O #### def sendMove(self, fr, to): dg = PyDatagram() dg.addUint8(fr[0]) dg.addUint8(fr[1]) dg.addUint8(to[0]) dg.addUint8(to[1]) print "Sent move (%d, %d) -> (%d, %d)" % (fr[0], fr[1], to[0], to[1]) self.cWriter.send(dg, self.oppConnection) def receiveData(self, dg): dg = PyDatagramIterator(dg) fr = (dg.getUint8(), dg.getUint8()) to = (dg.getUint8(), dg.getUint8()) print "Received move %s -> %s" % (fr, to) def indicate(): self.turnIndicator['text'] = 'Your turn!' self.sfx = loader.loadSfx('audio/ding.wav') self.sfx.play() seq = Sequence() seq.append(self.showPathIfVisible(fr, to)) seq.append(self.makeMove(fr, to)) seq.append(Func(indicate)) seq.append(Func(self.showVisibleSquares)) seq.start()
class ChessboardDemo(): def __init__(self, mission): # Initialize the ShowBase class from which we inherit, which will # create a window and set up everything we need for rendering into it. self.mission = mission self.player = mission.player self.menu = mission.menu self.state = 0 self.frame = DirectFrame(frameColor=(0.1, 0.1, 0.1, 0.5), frameSize=(-2, 2, -2, 2), pos=(0, 0, 0)) self.frame.hide() self.dr2 = base.win.makeDisplayRegion() #self.dr2.setActive(False) # self.frame.attachNewNode(self.dr2.node()) #self.dr2.setActive(False) self.dr2.setClearColorActive(True) self.dr2.setClearColor(VBase4(0.1, 0.1, 0.1, 1)) self.dr2.setClearDepthActive(True) # base.win.setClearColor(VBase4(0.1,0.1,0.1,1)) # base.win.setClearDepthActive() # base.win.setClearDepth(1) self.render2 = NodePath("render2") self.camNode = Camera("cam2") self.cam2 = self.render2.attachNewNode(self.camNode) self.dr2.setCamera(self.cam2) self.cam2.setPosHpr(0, -18, 10, 0, -30, 0) # Escape quits base.disableMouse() # Disble mouse camera control # camera.setPosHpr(0, -12, 8, 0, -35, 0) # Set the camera self.setupLights() # Setup default lighting # Since we are using collision detection to do picking, we set it up like # any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() # Make a traverser self.pq = CollisionHandlerQueue() # Make a handler # Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') # Attach that node to the camera since the ray will need to be positioned # relative to it # self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNP = self.cam2.attachNewNode(self.pickerNode) # Everything to be picked will use bit 1. This way if we were doing other # collision we could separate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() # Make our ray # Add it to the collision node self.pickerNode.addSolid(self.pickerRay) # Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) # self.picker.showCollisions(render) # Now we create the chess board and its pieces # We will attach all of the squares to their own root. This way we can do the # collision pass just on the squares and save the time of checking the rest # of the scene self.squareRoot = self.render2.attachNewNode("squareRoot") # For each square self.squares = [None for i in range(64)] self.pieces = [None for i in range(64)] for i in range(64): # Load, parent, color, and position the model (a single square # polygon) # self.squares[i] = loader.loadModel("../res/models/Scene3/Scene3Cat/hall/square") self.squares[i] = loader.loadModel( "res/models/Scene3/Scene3Cat/hall/square") self.squares[i].reparentTo(self.squareRoot) self.squares[i].setPos(SquarePos(i)) self.squares[i].setColor(SquareColor(i)) # Set the model itself to be collideable with the ray. If this model was # any more complex than a single polygon, you should set up a collision # sphere around it instead. But for single polygons this works # fine. self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) # Set a tag on the square's node so we can look up what square this is # later during the collision pass self.squares[i].find("**/polygon").node().setTag('square', str(i)) # We will use this variable as a pointer to whatever piece is currently # in this square # The order of pieces on a chessboard from white's perspective. This list # contains the constructor functions for the piece classes defined # below pieceOrder = (Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook) self.pieces[40] = Queen(self, 40, WHITE) self.pieces[51] = Bishop(self, 51, PIECEBLACK) self.pieces[33] = Knight(self, 33, PIECEBLACK) self.pieces[9] = Rook(self, 9, PIECEBLACK) self.pieces[20] = Rook(self, 20, PIECEBLACK) # This will represent the index of the currently highlited square self.hiSq = False # This wil represent the index of the square where currently dragged piece # was grabbed from self.dragging = False # self.eight = OnscreenText(text="8", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), # pos=(-0.9, 0.35), scale=.07) # self.seven = OnscreenText(text="7", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), # pos=(-0.93, 0.27), scale=.07) # self.six = OnscreenText(text="6", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), # pos=(-0.97, 0.18), scale=.07) # self.five = OnscreenText(text="5", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), # pos=(-1.02, 0.1), scale=.07) # self.four = OnscreenText(text="4", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), # pos=(-1.06, 0.02), scale=.07) # self.three = OnscreenText(text="3", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), # pos=(-1.12, -0.1), scale=.07) # self.two = OnscreenText(text="2", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), # pos=(-1.16, -0.18), scale=.07) # self.one = OnscreenText(text="1", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), # pos=(-1.23, -0.32), scale=.07) x = -0.91 y = 0.33 dx = 0.04 dy = 0.09 self.eight = OnscreenText(text="8", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(x, y), scale=.07) x -= dx y -= dy self.seven = OnscreenText(text="7", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(x, y), scale=.07) x -= dx y -= dy self.six = OnscreenText(text="6", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(x, y), scale=.07) x -= dx y -= dy self.five = OnscreenText(text="5", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(x, y), scale=.07) x -= dx y -= dy self.four = OnscreenText(text="4", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(x, y), scale=.07) x -= dx y -= dy self.three = OnscreenText(text="3", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(x, y), scale=.07) x -= dx y -= dy self.two = OnscreenText(text="2", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(x, y), scale=.07) x -= dx y -= dy self.one = OnscreenText(text="1", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(x, y), scale=.07) self.A = OnscreenText(text="A", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(-1.05, -0.5), scale=.07) self.B = OnscreenText(text="B", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(-0.75, -0.5), scale=.07) self.C = OnscreenText(text="C", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(-0.45, -0.5), scale=.07) self.D = OnscreenText(text="D", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(-0.15, -0.5), scale=.07) self.E = OnscreenText(text="E", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(0.15, -0.5), scale=.07) self.F = OnscreenText(text="F", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(0.45, -0.5), scale=.07) self.G = OnscreenText(text="G", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(0.75, -0.5), scale=.07) self.H = OnscreenText(text="H", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(1.05, -0.5), scale=.07) self.A.reparentTo(self.frame) self.B.reparentTo(self.frame) self.C.reparentTo(self.frame) self.D.reparentTo(self.frame) self.E.reparentTo(self.frame) self.F.reparentTo(self.frame) self.G.reparentTo(self.frame) self.H.reparentTo(self.frame) self.one.reparentTo(self.frame) self.two.reparentTo(self.frame) self.three.reparentTo(self.frame) self.four.reparentTo(self.frame) self.five.reparentTo(self.frame) self.six.reparentTo(self.frame) self.seven.reparentTo(self.frame) self.eight.reparentTo(self.frame) self.hide() # Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') base.accept("mouse1", self.grabPiece) # left-click grabs a piece base.accept("mouse1-up", self.releasePiece) # releasing places it base.accept("escape", self.hide) def hide(self): self.frame.hide() self.dr2.setActive(False) self.A.hide() self.B.hide() self.C.hide() self.D.hide() self.E.hide() self.F.hide() self.G.hide() self.H.hide() self.one.hide() self.two.hide() self.three.hide() self.four.hide() self.five.hide() self.six.hide() self.seven.hide() self.eight.hide() base.accept("escape", self.menu.game.pauseGame) base.accept("mouse1", self.player.__setattr__, ["LeftButton", 1]) base.accept("mouse1-up", self.player.__setattr__, ["LeftButton", 0]) self.mission.resume() self.player.initTask() def show(self): self.frame.show() self.dr2.setActive(True) self.A.show() self.B.show() self.C.show() self.D.show() self.E.show() self.F.show() self.G.show() self.H.show() self.one.show() self.two.show() self.three.show() self.four.show() self.five.show() self.six.show() self.seven.show() self.eight.show() base.accept("escape", self.hide) # This function swaps the positions of two pieces def swapPieces(self, fr, to): temp = self.pieces[fr] self.pieces[fr] = self.pieces[to] self.pieces[to] = temp if self.pieces[fr]: self.pieces[fr].square = fr self.pieces[fr].obj.setPos(SquarePos(fr)) if self.pieces[to]: self.pieces[to].square = to self.pieces[to].obj.setPos(SquarePos(to)) def mouseTask(self, task): # This task deals with the highlighting and dragging based on the mouse # First, clear the current highlight if self.hiSq is not False: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = False # Check to see if we can access the mouse. We need it to do anything # else 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(self.camNode, mpos.getX(), mpos.getY()) # If we are dragging something, set the position of the object # to be at the appropriate point over the plane of the board if self.dragging is not False: # Gets the point described by pickerRay.getOrigin(), which is relative to # camera, relative instead to render # nearPoint = render.getRelativePoint( # camera, self.pickerRay.getOrigin()) nearPoint = render.getRelativePoint(self.cam2, self.pickerRay.getOrigin()) # Same thing with the direction of the ray # nearVec = render.getRelativeVector( # camera, self.pickerRay.getDirection()) nearVec = render.getRelativeVector( self.cam2, self.pickerRay.getDirection()) self.pieces[self.dragging].obj.setPos( PointAtZ(.5, nearPoint, nearVec)) # Do the actual collision pass (Do it only on the squares for # efficiency purposes) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: # if we have hit something, sort the hits so that the closest # is first, and highlight that node self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) # Set the highlight on the picked square self.squares[i].setColor(HIGHLIGHT) self.hiSq = i return Task.cont def grabPiece(self): # If a square is highlighted and it has a piece, set it to dragging # mode if self.hiSq is not False and self.pieces[self.hiSq]: self.dragging = self.hiSq self.hiSq = False def releasePiece(self): # Letting go of a piece. If we are not on a square, return it to its original # position. Otherwise, swap it with the piece in the new square # Make sure we really are dragging something if self.dragging is not False: # We have let go of the piece, but we are not on a square if self.hiSq is False: self.pieces[self.dragging].obj.setPos(SquarePos(self.dragging)) else: if self.state == 0: if self.dragging == 51 and self.hiSq == 58: self.swapPieces(self.dragging, self.hiSq) self.swapPieces(40, 32) self.state = self.state + 1 self.mission.manager.GoodsIta[ 'studydoor_box'].state = 'unlockedOpen' self.mission.manager.GoodsIta[ 'studydoor_box'].OpenDoor() self.menu.infoDialog.show() self.menu.infoLabel['text'] = '似乎传来咔嚓一声开锁的声音' self.mission.skip() self.hide() else: self.pieces[self.dragging].obj.setPos( SquarePos(self.dragging)) if self.dragging != self.hiSq: self.player.EROSION += 10 self.player.erosionUpdateTemp() elif self.state == 1: if self.dragging == 33 and self.hiSq == 18: self.swapPieces(self.dragging, self.hiSq) self.state = self.state + 1 self.mission.manager.GoodsIta[ 'chessdoor_box'].state = 'unlockedOpen' self.mission.manager.GoodsIta[ 'chessdoor_box'].OpenDoor() self.mission.menu.infoDialog.show() self.mission.menu.infoLabel['text'] = '棋盘上弹出一张纸条「pass。这又不是\n' \ '真的国际象棋,我选择PASS你又能怎样?\n' \ '你是无法将死我的。」' self.mission.skip() self.hide() else: self.pieces[self.dragging].obj.setPos( SquarePos(self.dragging)) if self.dragging != self.hiSq: self.player.EROSION += 10 self.player.erosionUpdateTemp() elif self.state == 2: if self.dragging == 20 and self.hiSq == 36: self.swapPieces(self.dragging, self.hiSq) self.state = self.state + 1 self.mission.manager.GoodsIta[ 'exit_box'].state = 'unlockedOpen' self.mission.menu.infoDialog.show() self.mission.menu.infoLabel[ 'text'] = '可恶 失策了……这里居然…还有一个城堡么…' self.mission.skip() if self.mission.hiddenState: self.mission.end('hiddenEnd') self.hide() else: self.pieces[self.dragging].obj.setPos( SquarePos(self.dragging)) if self.dragging != self.hiSq: self.player.EROSION += 10 self.player.erosionUpdateTemp() elif self.state == 3: self.pieces[self.dragging].obj.setPos( SquarePos(self.dragging)) # We are no longer dragging anything self.dragging = False def setupLights(self): # This function sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.8, .8, .8, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(LVector3(0, 45, -45)) directionalLight.setColor((0.2, 0.2, 0.2, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight)) def initPos(self, state): if state == 0: self.pieces[40] = Queen(self, 40, WHITE) self.pieces[51] = Bishop(self, 51, PIECEBLACK) self.pieces[33] = Knight(self, 33, PIECEBLACK) self.pieces[9] = Rook(self, 9, PIECEBLACK) self.pieces[20] = Rook(self, 20, PIECEBLACK) elif state == 1: self.pieces[32] = Queen(self, 32, WHITE) self.pieces[58] = Bishop(self, 58, PIECEBLACK) self.pieces[33] = Knight(self, 33, PIECEBLACK) self.pieces[9] = Rook(self, 9, PIECEBLACK) self.pieces[20] = Rook(self, 20, PIECEBLACK) elif state == 2: self.pieces[32] = Queen(self, 32, WHITE) self.pieces[58] = Bishop(self, 58, PIECEBLACK) self.pieces[18] = Knight(self, 18, PIECEBLACK) self.pieces[9] = Rook(self, 9, PIECEBLACK) self.pieces[20] = Rook(self, 20, PIECEBLACK) elif state == 3: self.pieces[32] = Queen(self, 32, WHITE) self.pieces[58] = Bishop(self, 58, PIECEBLACK) self.pieces[18] = Knight(self, 18, PIECEBLACK) self.pieces[9] = Rook(self, 9, PIECEBLACK) self.pieces[36] = Rook(self, 36, PIECEBLACK)
class ChessboardDemo(ShowBase): def __init__(self, client): ShowBase.__init__(self) self.client = client # This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Panda3D: Tutorial - Mouse Picking", style=1, fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1), pos=(0.8, -0.95), scale = .07) self.escapeEvent = OnscreenText( text="ESC: Quit", parent=base.a2dTopLeft, style=1, fg=(1, 1, 1, 1), pos=(0.06, -0.1), align=TextNode.ALeft, scale = .05) self.mouse1Event = OnscreenText( text="Left-click and drag: Pick up and drag piece", parent=base.a2dTopLeft, align=TextNode.ALeft, style=1, fg=(1, 1, 1, 1), pos=(0.06, -0.16), scale=.05) self.accept('escape', sys.exit) # Escape quits self.disableMouse() # Disable mouse camera control camera.setPosHpr(0, -12, 8, 0, -35, 0) # Set the camera self.setupLights() # Setup default lighting # Since we are using collision detection to do picking, we set it up # like any other collision detection system with a traverser and a # handler self.picker = CollisionTraverser() # Make a traverser self.pq = CollisionHandlerQueue() # Make a handler # Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') # Attach that node to the camera since the ray will need to be # positioned relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) # Everything to be picked will use bit 1. This way if we were doing # other collisions we could separate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() # Make our ray # Add it to the collision node self.pickerNode.addSolid(self.pickerRay) # Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) # self.picker.showCollisions(render) # Now we create the chess board and its pieces # We will attach all of the squares to their own root. This way we can # do the collision pass just on the squares and save the time of # checking the rest of the scene self.square_root = render.attachNewNode("square_root") # For each square self.squares = [None for i in range(64)] for i in range(64): # Load, parent, color, and position the model (a single square # polygon) self.squares[i] = loader.loadModel("models/square") self.squares[i].reparentTo(self.square_root) self.squares[i].setPos(square_pos(i)) self.squares[i].setColor(square_color(i)) # Set the model itself to be collidable with the ray. If this model # is any more complex than a single polygon, you should set up a # collision sphere around it instead. But for single polygons this # works fine. self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) # Set a tag on the square's node so we can look up what square it is # later during the collision pass self.squares[i].find("**/polygon").node().setTag('square', str(i)) # We will use this variable as a pointer to whatever piece is # currently in this square # This will represent the index of the currently highlighted square self.hiSq = False # Represents the index of the square where currently dragged piece # was grabbed from self.dragging = False # Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') self.accept("mouse1", self.grab_piece) # left-click grabs a piece self.accept("mouse1-up", self.release_piece) # releasing places it def swap_pieces(self, fr, to): # Get the objects from the square references fr_model, fr_do = self.model_at(fr), self.piece_at(fr) to_model, to_do = self.model_at(to), self.piece_at(to) # Handle the from model fr_model.setPos(square_pos(to)) fr_do.square = to self.client._save(fr_do) # Handle the to model if it exists if to_do: to_model.setPos(square_pos(fr)) to_do.square = fr self.client._save(to_do) def mouseTask(self, task): # This task deals with the highlighting and dragging based on the mouse # First, clear the current highlight if self.hiSq is not False: self.squares[self.hiSq].setColor(square_color(self.hiSq)) self.hiSq = False # Check to see if we can access the mouse. We need it to do anything # else if self.mouseWatcherNode.hasMouse(): # get the mouse position mouse_pos = self.mouseWatcherNode.getMouse() # Set the position of the ray based on the mouse position self.pickerRay.setFromLens( self.camNode, mouse_pos.getX(), mouse_pos.getY()) # If we are dragging something, set the position of the object # to be at the appropriate point over the plane of the board if self.dragging is not False: # Gets the point described by pickerRay.getOrigin(), which is # relative to camera, relative instead to render nearPoint = render.getRelativePoint( camera, self.pickerRay.getOrigin()) # Same thing with the direction of the ray nearVec = render.getRelativeVector( camera, self.pickerRay.getDirection()) model = self.model_at(self.dragging) model.setPos( point_at_z(.5, nearPoint, nearVec)) # Do the actual collision pass (Do it only on the squares for # efficiency purposes) # noinspection PyArgumentList self.picker.traverse(self.square_root) if self.pq.getNumEntries() > 0: # if we have hit something, sort the hits so that the closest # is first, and highlight that node self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) # Set the highlight on the picked square self.squares[i].setColor(HIGHLIGHT) self.hiSq = i return Task.cont def piece_at(self, square): for p in self.client.objects: if p.square == square: return p return None def model_at(self, square): for p in self.client.objects: if p.square == square: return self.client.models[p.id] return None def grab_piece(self): # If a square is highlighted and it has a piece, set it to dragging # mode if self.hiSq is not False and self.piece_at(self.hiSq): self.dragging = self.hiSq self.hiSq = False def release_piece(self): # If we are not on a square, return it to its original position. # Otherwise, swap it with the piece in the new square # Make sure we really are dragging something if self.dragging is not False: # We have let go of the piece, but we are not on a square if self.hiSq is False: model = self.model_at(self.dragging) model.setPos( square_pos(self.dragging)) else: # Otherwise, swap the pieces self.swap_pieces(self.dragging, self.hiSq) # We are no longer dragging anything self.dragging = False def setupLights(self): # This function sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.8, .8, .8, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(LVector3(0, 45, -45)) directionalLight.setColor((0.2, 0.2, 0.2, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight))
class World(DirectObject): def __init__(self): #This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Panda3D: Tutorial - Mouse Picking", style=1, fg=(1, 1, 1, 1), pos=(0.8, -0.95), scale=.07) self.escapeEvent = OnscreenText(text="ESC: Quit", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.95), align=TextNode.ALeft, scale=.05) self.mouse1Event = OnscreenText( text="Left-click and drag: Pick up and drag piece", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.90), align=TextNode.ALeft, scale=.05) self.accept('escape', sys.exit) #Escape quits base.disableMouse() #Disble mouse camera control camera.setPosHpr(0, -13.75, 6, 0, -25, 0) #Set the camera self.setupLights() #Setup default lighting #Since we are using collision detection to do picking, we set it up like #any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() #Make a traverser self.pq = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') #Attach that node to the camera since the ray will need to be positioned #relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() #Make our ray self.pickerNode.addSolid(self.pickerRay) #Add it to the collision node #Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) #self.picker.showCollisions(render) #Now we create the chess board and its pieces #We will attach all of the squares to their own root. This way we can do the #collision pass just on the sqaures and save the time of checking the rest #of the scene self.squareRoot = render.attachNewNode("squareRoot") #For each square self.squares = [None for i in range(64)] self.pieces = [None for i in range(64)] for i in range(64): #Load, parent, color, and position the model (a single square polygon) self.squares[i] = loader.loadModel("models/square") self.squares[i].reparentTo(self.squareRoot) self.squares[i].setPos(SquarePos(i)) self.squares[i].setColor(SquareColor(i)) #Set the model itself to be collideable with the ray. If this model was #any more complex than a single polygon, you should set up a collision #sphere around it instead. But for single polygons this works fine. self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) #Set a tag on the square's node so we can look up what square this is #later during the collision pass self.squares[i].find("**/polygon").node().setTag('square', str(i)) #We will use this variable as a pointer to whatever piece is currently #in this square #The order of pieces on a chessboard from white's perspective. This list #contains the constructor functions for the piece classes defined below pieceOrder = (Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook) for i in range(8, 16): #Load the white pawns self.pieces[i] = Pawn(i, WHITE) for i in range(48, 56): #load the black pawns self.pieces[i] = Pawn(i, PIECEBLACK) for i in range(8): #Load the special pieces for the front row and color them white self.pieces[i] = pieceOrder[i](i, WHITE) #Load the special pieces for the back row and color them black self.pieces[i + 56] = pieceOrder[i](i + 56, PIECEBLACK) #This will represent the index of the currently highlited square self.hiSq = False #This wil represent the index of the square where currently dragged piece #was grabbed from self.dragging = False #Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') self.accept("mouse1", self.grabPiece) #left-click grabs a piece self.accept("mouse1-up", self.releasePiece) #releasing places it #This function swaps the positions of two pieces def swapPieces(self, fr, to): temp = self.pieces[fr] self.pieces[fr] = self.pieces[to] self.pieces[to] = temp if self.pieces[fr]: self.pieces[fr].square = fr self.pieces[fr].obj.setPos(SquarePos(fr)) if self.pieces[to]: self.pieces[to].square = to self.pieces[to].obj.setPos(SquarePos(to)) def mouseTask(self, task): #This task deals with the highlighting and dragging based on the mouse #First, clear the current highlight if self.hiSq is not False: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = False #Check to see if we can access the mouse. We need it to do anything else 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()) #If we are dragging something, set the position of the object #to be at the appropriate point over the plane of the board if self.dragging is not False: #Gets the point described by pickerRay.getOrigin(), which is relative to #camera, relative instead to render nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin()) #Same thing with the direction of the ray nearVec = render.getRelativeVector( camera, self.pickerRay.getDirection()) self.pieces[self.dragging].obj.setPos( PointAtZ(.5, nearPoint, nearVec)) #Do the actual collision pass (Do it only on the squares for #efficiency purposes) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: #if we have hit something, sort the hits so that the closest #is first, and highlight that node self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) #Set the highlight on the picked square self.squares[i].setColor(HIGHLIGHT) self.hiSq = i return Task.cont def grabPiece(self): #If a square is highlighted and it has a piece, set it to dragging mode if (self.hiSq is not False and self.pieces[self.hiSq]): self.dragging = self.hiSq self.hiSq = False def releasePiece(self): #Letting go of a piece. If we are not on a square, return it to its original #position. Otherwise, swap it with the piece in the new square if self.dragging is not False: #Make sure we really are dragging something #We have let go of the piece, but we are not on a square if self.hiSq is False: self.pieces[self.dragging].obj.setPos(SquarePos(self.dragging)) else: #Otherwise, swap the pieces self.swapPieces(self.dragging, self.hiSq) #We are no longer dragging anything self.dragging = False def setupLights(self): #This function sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.8, .8, .8, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(0, 45, -45)) directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight))
class World(ShowBase): def __init__(self): ShowBase.__init__(self) #PStatClient.connect() #self.lookPoint = NodePath(PandaNode("floater")) self.lookPoint = self.loader.loadModel("models/cone") self.lookPoint.reparentTo(render) self.menu = StartMenu(self) #self.bar = Bar() #self.messenger.toggleVerbose() #sys.exit() #pdb.set_trace() # Window change event handler #self.windowEventSetup() def setup(self): print("Init Levels...") self.initLevels() print("Init World...") self.initWorld("yard") print("Init Items...") self.initItems() print("Init Actors...") self.initActors() print("Init GUI ...") self.initGui() print("Init Lights...") self.initLights() print("Init Collisions...") self.initCollision() print("Init Tasks...") self.initTasks() print("Launching World") # Accept the control keys #self.accept("h", self.crono.start) def initItems(self): with open('items/items.json') as items_file: self.items = json.load(items_file) def initActors(self): self.player = Player(self, 20, 10, 10, 10, 10, 10) #app, hp, mana, strength, dexterity, vigor, magic): self.enemies = [] self.npcs = [] #Creating AI World self.AIworld = AIWorld(render) """self.foe1 = Enemy(self, 100, 50, 5, 2, "bug") #(self, app, hp, mana, speed, attackSpeed, name): self.nasgul = Enemy(self, 100, 50, 5, 2, "nasgul") self.npc1 = Npc(self, 100, 50, 5, 2, "guy2") self.npc2 = Npc(self, 100, 50, 5, 2, "ralph") self.enemies.append(self.foe1) self.enemies.append(self.nasgul) self.npcs.append(self.npc1) self.npcs.append(self.npc2)""" def initGui(self): # Load the models. self.inventory = Inventory(self) self.status = Status(self) self.skills = Skills(self) #self.statusBar = self.loader.loadModel("models/statusbar") ##self.statusBar.setDepthTest(True) #self.statusBar.setDepthWrite(True) # Reparent the model to render2d. #self.statusBar.reparentTo(self.render2d) #self.statusBar.setScale(0.15, 0.15, 0.15) #self.statusBar.setPos(-0.95, 0, 0.65) #self.crono = Crono(self) ##self.cursorpos = CursorPos(self) #self.playerpos = PlayerPos(self) #self.crono.draw(0.7, -0.85) #self.cursorpos.draw(0.0, -0.85) #self.playerpos.draw(-0.7, -0.85) self.accept("i", self.inventory.toggle) self.accept("c", self.status.toggle) self.accept("k", self.skills.toggle) def initTasks(self): #self.taskMgr.add(self.crono.task, "cronoTask") #self.taskMgr.add(self.cursorpos.task, "cursorposTask") ###self.taskMgr.add(self.playerpos.task, "playerposTask") self.taskMgr.add(self.checkCollision, "collisionTask") #self.taskMgr.add(self.player.update, "updateTask") self.taskMgr.add(self.player.move, "moveTask") self.taskMgr.add(self.player.updateCamera, "playerCameraTask",priority=1) """ #self.taskMgr.add(self.foe1.update, "bugTask",priority=1) #self.taskMgr.add(self.nasgul.update, "nasgulTask",priority=1) #self.taskMgr.add(self.npc1.update, "npc1Task",priority=1) #self.taskMgr.add(self.npc2.update, "npc2Task",priority=1) """ self.taskMgr.add(self.update, 'update') def initLights(self): # Create some lighting #self.environ.ls() #print(self.environ.findAllMatches("**/Spot")) ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(0.8, 0.8, 0.8, 0.65)) """ directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(-10, -10, 5)) directionalLight.showFrustum() directionalLight.setColor(Vec4(1, 1, 1, 1)) directionalLight.setSpecularColor(Vec4(1, 1, 1, 1)) dirnp = render.attachNewNode(directionalLight) dirnp.setPos(10, 0, 6) """ plight1 = PointLight('plight1') plight1.setColor(VBase4(1, 1, 1, 1)) plight1.showFrustum() #plight1.setShadowCaster(True) plnp1 = render.attachNewNode(plight1) plnp1.setPos(26.71, -33.2, 26) plight2 = PointLight('plight2') plight2.setColor(VBase4(1, 1, 1, 1)) plight2.showFrustum() plnp2 = render.attachNewNode(plight2) plnp2.setPos(-25, 25, 25) slight = Spotlight('slight') slight.setColor(VBase4(1, 1, 1, 1)) lens = PerspectiveLens() lens.setFilmSize(1, 1) # Or whatever is appropriate for your scene slight.setLens(lens) slight.setShadowCaster(True, 512, 512) slight.showFrustum() slnp = render.attachNewNode(slight) slnp.setPos(0, 0, 100) slnp.lookAt(Vec3(0,0,0)) render.setLight(slnp) render.setLight(plnp1) render.setLight(plnp2) #render.setLight(render.attachNewNode(ambientLight)) #render.setLight(dirnp) render.setShaderAuto() #render.setLight(render.attachNewNode(directionalLight)) """ self.light = render.attachNewNode(Spotlight("Spot")) self.light.node().setScene(render) self.light.node().setShadowCaster(True) self.light.node().showFrustum() self.light.node().getLens().setFov(40) self.light.node().getLens().setNearFar(10,100) render.setLight(self.light) """ def initLevels(self): with open('levels/levels.json') as levels_file: self.levels = json.load(levels_file) def initWorld(self, level): self.environ = self.loader.loadModel(self.levels["levels"][level]["model"]) #self.environ.setScale(20, 20, 20) #self.environ.setHpr(0, 0, 0) self.environ.setPos(0, 0, 0) self.playerStartPos = self.environ.find("**/startPos").getPos() # Reparent the model to render self.environ.reparentTo(render) #self.environ.ls() self.accept("q", self.changeMap) def destroyWorld(self): self.environ.detachNode() self.environ.removeNode() def changeMap(self):#, levelName): self.destroyWorld() self.initWorld("yard") def update(self, task): dt = globalClock.getDt() self.AIworld.update() return task.cont def setKey(self, key, value): self.keyMap[key] = value def windowEventSetup( self ): # accept the window event's self.accept( 'window-event', self.windowEventHandler) # create a window event yourself #messenger.send( 'window-event', [self.win] ) def windowEventHandler( self, window=None ): wp = window.getProperties() print("Window changed") print("X = %s" % wp.getXSize()) print("Y = %s" % wp.getYSize()) self.setResolution( wp.getXSize(), wp.getYSize() ) def setResolution( self, w, h ): wp = WindowProperties() wp.setSize( w, h ) if os.name == 'posix': self.openMainWindow() self.graphicsEngine.openWindows() self.win.requestProperties( wp ) # Define a procedure to move the camera. def spinCameraTask(self, task): angleDegrees = task.time * 6.0 angleRadians = angleDegrees * (pi / 180.0) self.camera.setPos(40 * sin(angleRadians), -10.0 * cos(angleRadians), 3) self.camera.setHpr(angleDegrees, 0, 0) return Task.cont def initCollision(self): self.enemyGroundRay = [] self.enemyGroundCol = [] self.enemyGroundColNp = [] self.enemyGroundHandler = [] self.npcGroundRay = [] self.npcGroundCol = [] self.npcGroundColNp = [] self.npcGroundHandler = [] self.cTrav = CollisionTraverser() self.playerGroundRay = CollisionRay() self.playerGroundRay.setOrigin(0, 0, 9) self.playerGroundRay.setDirection(0, 0, -1) self.playerGroundCol = CollisionNode('playerRay') self.playerGroundCol.addSolid(self.playerGroundRay) self.playerGroundCol.setFromCollideMask(CollideMask.bit(0)) self.playerGroundCol.setIntoCollideMask(CollideMask.allOff()) self.playerGroundColNp = self.player.moveFloater.attachNewNode(self.playerGroundCol) self.playerGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler) self.mouseGroundRay = CollisionRay() self.mouseGroundRay.setOrigin(0, 0, 9) self.mouseGroundRay.setDirection(0, 0, -1) self.mouseGroundCol = CollisionNode('mouseRay') self.mouseGroundCol.addSolid(self.mouseGroundRay) self.mouseGroundCol.setFromCollideMask(CollideMask.bit(0)) self.mouseGroundCol.setIntoCollideMask(CollideMask.allOff()) self.mouseGroundColNp = self.camera.attachNewNode(self.mouseGroundCol) self.mouseGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.mouseGroundColNp, self.mouseGroundHandler) # Uncomment this line to see the collision rays #self.playerGroundColNp.show() #self.mouseGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring #self.cTrav.showCollisions(render) i = 0 for enemy in self.enemies: self.enemyGroundRay.append(CollisionRay()) self.enemyGroundRay[i].setOrigin(0, 0, 9) self.enemyGroundRay[i].setDirection(0, 0, -1) self.enemyGroundCol.append(CollisionNode('%sRay' % enemy.name)) self.enemyGroundCol[i].addSolid(self.enemyGroundRay[i]) self.enemyGroundCol[i].setFromCollideMask(CollideMask.bit(0)) self.enemyGroundCol[i].setIntoCollideMask(CollideMask.allOff()) self.enemyGroundColNp.append(enemy.enemyActor.attachNewNode(self.enemyGroundCol[i])) self.enemyGroundHandler.append(CollisionHandlerQueue()) self.cTrav.addCollider(self.enemyGroundColNp[i], self.enemyGroundHandler[i]) #self.enemyGroundColNp.show() i += 1 i = 0 for npc in self.npcs: self.npcGroundRay.append(CollisionRay()) self.npcGroundRay[i].setOrigin(0, 0, 9) self.npcGroundRay[i].setDirection(0, 0, -1) self.npcGroundCol.append(CollisionNode('%sRay' % npc.name)) self.npcGroundCol[i].addSolid(self.npcGroundRay[i]) self.npcGroundCol[i].setFromCollideMask(CollideMask.bit(0)) self.npcGroundCol[i].setIntoCollideMask(CollideMask.allOff()) self.npcGroundColNp.append(npc.npcActor.attachNewNode(self.npcGroundCol[i])) self.npcGroundHandler.append(CollisionHandlerQueue()) self.cTrav.addCollider(self.npcGroundColNp[i], self.npcGroundHandler[i]) #self.npcGroundColNp.show() i += 1 def checkCollision(self, task): startpos = self.player.moveFloater.getPos() entries = list(self.playerGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) for entry in entries: if entry > 0 and entries[0].getIntoNode().getName() == "Ground": self.player.moveFloater.setZ(entry.getSurfacePoint(render).getZ()) else: self.player.moveFloater.setPos(startpos) if self.mouseWatcherNode.hasMouse(): mpos = self.mouseWatcherNode.getMouse() self.mouseGroundRay.setFromLens(self.camNode, mpos.getX(), mpos.getY()) nearPoint = render.getRelativePoint(self.camera, self.mouseGroundRay.getOrigin()) nearVec = render.getRelativeVector(self.camera, self.mouseGroundRay.getDirection()) try: self.lookPoint.setPos(PointAtZ(self.player.moveFloater.getZ(), nearPoint, nearVec)) except: pass i = 0 for enemy in self.enemies: startpos = enemy.enemyActor.getPos() entries = list(self.enemyGroundHandler[i].getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) for entry in entries: if entry > 0: # and entries[0].getIntoNode().getName() == "Ground": enemy.enemyActor.setZ(entry.getSurfacePoint(render).getZ()) else: enemy.enemyActor.setPos(startpos) i += 1 i = 0 for npc in self.npcs: startpos = npc.npcActor.getPos() entries = list(self.npcGroundHandler[i].getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) for entry in entries: if entry > 0: # and entries[0].getIntoNode().getName() == "Ground": npc.npcActor.setZ(entry.getSurfacePoint(render).getZ()) else: npc.npcActor.setPos(startpos) i += 1 return task.cont
class World(DirectObject): mySound = base.loader.loadSfx("trial.mp3") #Used for adding a virus at a randomly generated position def random_vgen(self): print 'I am in random' for i in range(0, 5): self.a[random.randint(0, 7)][random.randint(0, 7)] = 1 def initializer(self, level): self.turns = 0 ## Level Definition def levelone(): self.a[4][4] = 1 self.a[4][5] = 1 self.a[4][6] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[4][6] = 1 self.a[5][5] = 1 def leveltwo(): self.a[4][3] = 1 self.a[4][5] = 1 self.a[4][7] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[2][2] = 1 self.a[5][3] = 1 self.a[1][2] = 1 def levelthree(): self.a[4][4] = 1 self.a[4][5] = 1 self.a[4][6] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[4][6] = 1 self.a[5][5] = 1 self.a[4][3] = 1 self.a[4][5] = 1 self.a[4][7] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[2][2] = 1 self.a[5][3] = 1 options = {1: levelone, 2: leveltwo, 3: levelthree} options[level]() print self.a temp = [] count = 0 for element in reversed(self.a): for ele in element: #print 'cheking element is 1 : ' + str(ele) if ele == 1: temp.append(count) self.pieces[count] = Monster(count, WHITE) #self.squares[count].setColor(HIGHLIGHT) count = count + 1 self.list = temp def showscore(self): try: self.score.destroy() except: pass self.score = OnscreenText(text='Number of Turns : %s' % (self.turns), pos=(0.5, 0.95), scale=0.07, mayChange=True) def menuscreen(self): # Callback function to set text def setText(): b.destroy() helptext.destroy() # Add button b = DirectButton(text=("START", "START", "START", "disabled"), scale=0.15, command=setText, pos=(0, 0, 0.85)) helptext = OnscreenText(text=''' STORY: Hello Mad Scientist! You are so close to finding the cure to aids! You understood the behaviour and can finally manipulate the virus to kill itself! But time is running out! You have a red and white blood cell sample infected with AIDS Virus. INSTRUCTIONS: The AIDS Virus obeys the Conway's Game of Life. Who would have guessed? 1. If virus is surrounded by more than 3 viruses, it dies of suffocation 2. If virus is surrounded by less than 2 viruses, it dies of underpopulation 3. If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned due to breeding. AIM: To kill all the viruses, by moving one of them every turn. ''', pos=(-0.90, 0.72), frame=(123, 123, 123, 1), wordwrap=25, align=TextNode.ALeft, bg=(0.23, 0.243, 0.13, 0.9)) def endscreen(self): def restart(): taskMgr.remove(self.mouseTask) for i in range(64): self.squares[i].setColor(SquareColor(i)) scorecard.destroy() restartb.destroy() end.destroy() nextlevelb.destroy() self.reference.destroy() self.mySound.stop() try: self.score.destroy() except: pass print 'restarting' print self.a print self.list World() def quitgame(): sys.exit() def nextLevel(): self.currlevel = self.currlevel + 1 nextlevelb.destroy() scorecard.destroy() restartb.destroy() end.destroy() self.score.destroy() self.initializer(self.currlevel) # Add button scorecard = OnscreenText(text='You finished it in %s turns! ' % (self.turns), frame=(123, 123, 123, 0), wordwrap=25, bg=(0.2, 0, 0.8, 1)) nextlevelb = DirectButton(text=("NEXT LEVEL", "NEXT LEVEL", "NEXT LEVEL", "disabled"), scale=0.15, command=nextLevel, pos=(0, 0, -0.15)) restartb = DirectButton(text=("RESTART", "RESTART", "RESTART", "disabled"), scale=0.15, command=restart, pos=(0, 0, -0.35)) end = DirectButton(text=("QUIT", "QUIT", "QUIT", "disabled"), scale=0.15, command=quitgame, pos=(0, 0, -0.55)) if self.currlevel == self.maxlevel: nextlevelb.destroy() def __init__(self): #music self.mySound.play() print 'I am being initialized' self.menuscreen() self.list = [] self.turns = 0 self.maxlevel = 3 self.currlevel = 1 self.a = [[0 for x in range(8)] for y in range(8)] #This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Game of Life : Help in ending AIDS!", style=1, fg=(1, 1, 1, 1), pos=(0, -0.95), scale=.07) self.escapeEvent = OnscreenText(text="ESC: Quit", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.95), align=TextNode.ALeft, scale=.05) ## self.mouse1Event = OnscreenText( ## text="Left-click and drag: Pick up virus and drag it to a new bloodcell", ## style=1, fg=(1,1,1,1), pos=(-1.3, 0.90), ## align=TextNode.ALeft, scale = .05) ## self.accept('escape', sys.exit) #Escape quits base.disableMouse() #Disble mouse camera control camera.setPosHpr(0, -13.75, 6, 0, -25, 0) #Set the camera self.setupLights() #Setup default lighting #Since we are using collision detection to do picking, we set it up like #any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() #Make a traverser self.pq = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') #Attach that node to the camera since the ray will need to be positioned #relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() #Make our ray self.pickerNode.addSolid(self.pickerRay) #Add it to the collision node #Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) #self.picker.showCollisions(render) #We will attach all of the squares to their own root. This way we can do the #collision pass just on the sqaures and save the time of checking the rest #of the scene self.squareRoot = render.attachNewNode("squareRoot") #For each square self.squares = [None for i in range(64)] self.pieces = [None for i in range(64)] for i in range(64): #Load, parent, color, and position the model (a single square polygon) self.squares[i] = loader.loadModel("models/square") self.squares[i].reparentTo(self.squareRoot) self.squares[i].setPos(SquarePos1(i)) self.squares[i].setColor(SquareColor(i)) #Set the model itself to be collideable with the ray. If this model was #any more complex than a single polygon, you should set up a collision #sphere around it instead. But for single polygons this works fine. self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) #Set a tag on the square's node so we can look up what square this is #later during the collision pass self.squares[i].find("**/polygon").node().setTag('square', str(i)) #We will use this variable as a pointer to whatever piece is currently #in this square self.initializer(self.currlevel) #This will represent the index of the currently highlited square self.hiSq = False #This wil represent the index of the square where currently dragged piece #was grabbed from self.dragging = False #Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') #self.trial = taskMgr.add(self.trial,'trial') self.accept("mouse1", self.grabPiece) #left-click grabs a piece self.accept("mouse1-up", self.releasePiece) #releasing places it #This function swaps the positions of two pieces def swapPieces(self, fr, to): temp = self.pieces[fr] self.pieces[fr] = self.pieces[to] self.pieces[to] = temp if self.pieces[fr]: print 'imma swapping' self.pieces[fr].square = fr print fr print SquarePos(fr) try: self.pieces[fr].obj.setPos(SquarePos(fr)) except: pass print 'done' if self.pieces[to]: self.pieces[to].square = to try: self.pieces[to].obj.setPos(SquarePos(to)) except: pass def trial(self): self.turns = self.turns + 1 try: self.reference.destroy() except: pass self.reference = OnscreenText(text=''' Reference: virus is surrounded by more than 3 viruses, it dies virus is surrounded by less than 2 viruses, it dies If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned. ''', style=1, fg=(1, 1, 1, 1), pos=(-1, 0.95), align=TextNode.ALeft, scale=.05) self.showscore() a = self.a while True: for i in self.list: #insert deletion code print 'imma deleting the sq : ' + str(i) self.pieces[i].obj.delete() self.squares[i].setColor(SquareColor(i)) count = 0 a = [[([[ sum(b[y1][x1] for b in [[[( (-1 < x2 + dx < len(a[0])) and (-1 < y2 + dy < len(a))) and a[y2 + dy][x2 + dx] or 0 for x2 in range(len(a[0]))] for y2 in range(len(a))] for (dx, dy) in [(dx, dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1] if (dy != 0 or dx != 0)]]) for x1 in range(len(a[0])) ] for y1 in range(len(a))][y][x] == 3 or ([[ sum(c[y3][x3] for c in [[[( (-1 < x4 + dx < len(a[0])) and (-1 < y4 + dy < len(a))) and a[y4 + dy][x4 + dx] or 0 for x4 in range(len(a[0]))] for y4 in range(len(a))] for (dx, dy) in [(dx, dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1] if (dy != 0 or dx != 0)]]) for x3 in range(len(a[0])) ] for y3 in range(len(a))][y][x] == 2 and a[y][x] == 1)) and 1 or 0 for x in range(len(a[0]))] for y in range(len(a))] lis = [] #insert a random virus at a probability of 1/5 diceroll = random.randint(0, 5) if diceroll == 2: self.random_vgen() for element in reversed(a): for ele in element: #print 'cheking element is 1 : ' + str(ele) if ele == 1: lis.append(count) count = count + 1 print lis self.list = lis self.a = a print self.list for i in self.list: self.pieces[i] = Monster(i, WHITE) #self.squares[i].setColor(HIGHLIGHT) print 'leaving trial' if len(self.list) == 0: self.endscreen() break return def mouseTask(self, task): #This task deals with the highlighting and dragging based on the mouse #First, clear the current highlight if self.hiSq is not False: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = False #Check to see if we can access the mouse. We need it to do anything else 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()) #If we are dragging something, set the position of the object #to be at the appropriate point over the plane of the board if self.dragging is not False: #Gets the point described by pickerRay.getOrigin(), which is relative to #camera, relative instead to render nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin()) #Same thing with the direction of the ray nearVec = render.getRelativeVector( camera, self.pickerRay.getDirection()) try: self.pieces[self.dragging].obj.setPos( PointAtZ(.5, nearPoint, nearVec)) except: pass #Do the actual collision pass (Do it only on the squares for #efficiency purposes) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: #if we have hit something, sort the hits so that the closest #is first, and highlight that node self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) #Set the highlight on the picked square self.squares[i].setColor(HIGHLIGHT) self.hiSq = i #print 'selected is ' + str(i) return Task.cont def grabPiece(self): #If a square is highlighted and it has a piece, set it to dragging mode if (self.hiSq is not False and self.pieces[self.hiSq]): self.dragging = self.hiSq self.hiSq = False def releasePiece(self): #Letting go of a piece. If we are not on a square, return it to its original #position. Otherwise, swap it with the piece in the new square if self.dragging is not False: #Make sure we really are dragging something #We have let go of the piece, but we are not on a square if self.hiSq is False: try: self.pieces[self.dragging].obj.setPos( SquarePos(self.dragging)) except: pass else: #Otherwise, swap the pieces self.swapPieces(self.dragging, self.hiSq) #self.draggin is the from print self.list print 'you picked this, so Imma deleting this ' + str( self.dragging) #deletion of i after picking it up. try: self.list.remove(self.dragging) except: pass temp2 = [] temp2 = SquarePosTuple(self.dragging) self.a[temp2[0]][temp2[1]] = 0 i = self.hiSq print self.list print 'highlighted sq is ' + str(i) templis = [] templis = SquarePosTuple(i) print templis self.list.append(i) print self.list print templis self.a[templis[0]][templis[1]] = 1 for line in self.a: print line self.trial() #We are no longer dragging anything self.dragging = False def setupLights(self): #This function sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.8, .8, .8, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(0, 45, -45)) directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight))
class LocationSeeker: def __init__(self, avatar, minDistance, maxDistance, shadowScale = 1): self.dropShadowPath = 'phase_3/models/props/square_drop_shadow.bam' self.rejectSoundPath = 'phase_4/audio/sfx/ring_miss.mp3' self.moveShadowTaskName = 'Move Shadow' self.locationSelectedName = 'Location Selected' self.dropShadow = None self.shadowScale = shadowScale self.rejectSfx = loader.loadSfx(self.rejectSoundPath) self.avatar = avatar self.cameraNode = None self.cameraRay = None self.cameraNP = None self.shadowNP = None self.shadowRay = None self.minDistance = minDistance self.maxDistance = maxDistance self.legacyMode = False self.collHdlFl = CollisionHandlerQueue() return def startSeeking(self): if not self.avatar: return self.cleanupShadow() self.buildShadow() scale = self.dropShadow.getScale() if scale < 1.0: self.maxDistance += 40 x, y, z = self.avatar.getPos(render) self.dropShadow.reparentTo(render) self.dropShadow.setPos(x, y + 5, z + 2) self.cameraNode = CollisionNode('coll_camera') self.cameraNode.setFromCollideMask(CIGlobals.WallBitmask) self.cameraRay = CollisionRay() self.cameraNode.addSolid(self.cameraRay) self.cameraNP = camera.attachNewNode(self.cameraNode) base.cTrav.addCollider(self.cameraNP, CollisionHandlerQueue()) if not self.legacyMode: shadowNode = CollisionNode('coll_shadow') self.shadowRay = CollisionRay(0, 0, 6, 0, 0, -1) shadowNode.addSolid(self.shadowRay) shadowNode.setFromCollideMask(CIGlobals.FloorBitmask) self.shadowNP = self.dropShadow.attachNewNode(shadowNode) base.cTrav.addCollider(self.shadowNP, self.collHdlFl) base.taskMgr.add(self.__moveShadow, self.moveShadowTaskName) self.avatar.acceptOnce('mouse1', self.locationChosen) def stopSeeking(self): base.taskMgr.remove(self.moveShadowTaskName) def __moveShadow(self, task): if base.mouseWatcherNode.hasMouse(): def PointAtZ(z, point, vec): if vec.getZ() != 0: return point + vec * ((z - point.getZ()) / vec.getZ()) else: return self.getLocation() mouse = base.mouseWatcherNode.getMouse() self.cameraRay.setFromLens(base.camNode, mouse.getX(), mouse.getY()) nearPoint = render.getRelativePoint(camera, self.cameraRay.getOrigin()) nearVec = render.getRelativeVector(camera, self.cameraRay.getDirection()) self.dropShadow.setPos(PointAtZ(0.5, nearPoint, nearVec)) if self.legacyMode: self.dropShadow.setZ(base.localAvatar.getZ(render) + 0.5) elif self.collHdlFl.getNumEntries() > 0: self.dropShadow.setZ(self.collHdlFl.getEntry(0).getSurfacePoint(render).getZ() + 0.5) return Task.cont def locationChosen(self): base.taskMgr.remove(self.moveShadowTaskName) distance = self.avatar.getDistance(self.dropShadow) x, y, z = self.getLocation() if distance >= self.minDistance and distance <= self.maxDistance: gag = self.avatar.getBackpack().getActiveGag() self.avatar.sendUpdate('setDropLoc', [gag.getID(), x, y, z]) messenger.send(self.locationSelectedName) else: self.rejectSfx.play() self.avatar.acceptOnce('mouse1', self.locationChosen) base.taskMgr.add(self.__moveShadow, self.moveShadowTaskName) def buildShadow(self): self.cleanupShadow() if not self.dropShadowPath or not self.avatar: return self.dropShadow = loader.loadModel(self.dropShadowPath) self.dropShadow.setScale(self.shadowScale) def setShadowType(self, isCircle = False, scale = 1): if not isCircle: self.dropShadowPath = 'phase_3/models/props/square_drop_shadow.bam' else: self.dropShadowPath = 'phase_3/models/props/drop_shadow.bam' self.shadowScale = scale def getLocation(self): if self.dropShadow: return self.dropShadow.getPos(render) return self.avatar.getPos(render) def getLocationSelectedName(self): return self.locationSelectedName def cleanupShadow(self): if self.dropShadow: self.dropShadow.removeNode() self.dropShadow = None if self.cameraNode: self.cameraNP.removeNode() self.cameraNP = None self.cameraNode = None self.cameraRay = None self.shadowNP.removeNode() self.shadowRay = None self.shadowNP = None self.shadowSphNP = None return def cleanup(self): if self.avatar: base.taskMgr.remove(self.moveShadowTaskName) self.avatar.ignore('mouse1') self.cleanupShadow() self.rejectSfx.stop() self.rejectSfx = None self.avatar = None self.dropShadowPath = None self.rejectSoundPath = None self.locationSelectedName = None self.moveShadowTaskName = None del self.shadowScale return