def leftClick(self): self.mouse1Down = True #Collision traversal pickerNode = CollisionNode('mouseRay') pickerNP = base.camera.attachNewNode(pickerNode) pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) pickerRay = CollisionRay() pickerNode.addSolid(pickerRay) myTraverser = CollisionTraverser() myHandler = CollisionHandlerQueue() myTraverser.addCollider(pickerNP, myHandler) if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) myTraverser.traverse(render) # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue. if myHandler.getNumEntries() > 0: # This is so we get the closest object myHandler.sortEntries() pickedObj = myHandler.getEntry(0).getIntoNodePath() objTag = pickedObj.findNetTag('mouseCollisionTag').getTag('mouseCollisionTag') if objTag and len(objTag)>0: messenger.send('object_click',[objTag]) pickerNP.remove()
def leftClick(self): self.mouse1Down = True #Collision traversal pickerNode = CollisionNode('mouseRay') pickerNP = base.camera.attachNewNode(pickerNode) pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) pickerRay = CollisionRay() pickerNode.addSolid(pickerRay) myTraverser = CollisionTraverser() myHandler = CollisionHandlerQueue() myTraverser.addCollider(pickerNP, myHandler) if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) myTraverser.traverse(render) # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue. if myHandler.getNumEntries() > 0: # This is so we get the closest object myHandler.sortEntries() pickedObj = myHandler.getEntry(0).getIntoNodePath() objTag = pickedObj.findNetTag('mouseCollisionTag').getTag( 'mouseCollisionTag') if objTag and len(objTag) > 0: messenger.send('object_click', [objTag]) pickerNP.remove()
class ControleMouse(): def __init__(self, render, camera): #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) self.pst = CollisionTraverser() #Make a traverser self.hqp = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pstNode = CollisionNode('mouseRaytoObj') #Attach that node to the camera since the ray will need to be positioned relative to it self.pstNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.pstNode2 = camera.attachNewNode(self.pstNode) self.pickerRayObj = CollisionRay() #Everything to be picked will use bit 1. This way if we were doing other collision we could seperate it #self.pstNode.setFromCollideMask(BitMask32.bit(1)) self.pstNode.addSolid(self.pickerRayObj) #Add it to the collision node #Register the ray as something that can cause collisions self.pst.addCollider(self.pstNode2, self.hqp) #self.pst.showCollisions(render)
class Agent: def __init__(self, model, run, walk, startPos, scale, select,ralph,saysome): self.actor = Actor(model, {"run":run, "walk":walk}) self.actor.reparentTo(render) self.actor.setScale(scale) self.actor.setPos(startPos) self.actor.setHpr(90,0,0) self.playerGUI = saysome self.myralph = ralph self.setAI() self.cTrav = CollisionTraverser() self.groundRay = CollisionRay(0,0,1000,0,0,-1) self.groundCol = CollisionNode('dinoRay') self.groundCol.addSolid(self.groundRay) self.groundCol.setFromCollideMask(BitMask32.bit(1)) self.groundCol.setIntoCollideMask(BitMask32.allOff()) self.groundColNp = self.actor.attachNewNode(self.groundCol) self.groundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.groundColNp, self.groundHandler) self.sphere = CollisionSphere(0,0,5,13) self.spherecol = CollisionNode('dinoSphere') self.spherecol.addSolid(self.sphere) self.spherecol.setCollideMask(BitMask32.bit(1)) self.dinocolhs = self.actor.attachNewNode(self.spherecol) #self.dinocolhs.show() #self.groundColNp.show() #self.cTrav.showCollisions(render) def setAI(self): #Creating AI World self.AIworld = AIWorld(render) self.AIchar = AICharacter("seeker",self.actor, 380, 50, 250) self.AIworld.addAiChar(self.AIchar) self.AIbehaviors = self.AIchar.getAiBehaviors() self.AIbehaviors.pursue(self.myralph) self.actor.loop('run') #AI World update taskMgr.add(self.AIUpdate,"AIUpdate") #to update the AIWorld def AIUpdate(self,task): if self.playerGUI.getpausevalue(): self.AIworld.update() return Task.cont def setControl(self, control, value): self.controlMap[control] = value def getactor(self): return self.actor
class RepairMousePicker: def __init__(self): self.pickerNode = CollisionNode('RepairMousePicker.pickerNode') self.pickerNP = base.cam2d.attachNewNode(self.pickerNode) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.collisionTraverser = CollisionTraverser() self.collisionHandler = CollisionHandlerQueue() self.collisionTraverser.addCollider(self.pickerNP, self.collisionHandler) self.clearCollisionMask() self.orthographic = True def destroy(self): del self.pickerNode self.pickerNP.removeNode() del self.pickerNP del self.pickerRay del self.collisionTraverser del self.collisionHandler def setOrthographic(self, ortho): self.orthographic = ortho def setCollisionMask(self, mask): self.pickerNode.setFromCollideMask(mask) def clearCollisionMask(self): self.pickerNode.setFromCollideMask(BitMask32.allOff()) def getCollisions(self, traverseRoot, useIntoNodePaths = False): if not base.mouseWatcherNode.hasMouse(): return [] mpos = base.mouseWatcherNode.getMouse() if self.orthographic: self.pickerRay.setFromLens(base.cam2d.node(), 0, 0) self.pickerNP.setPos(mpos.getX(), 0.0, mpos.getY()) else: self.pickerRay.setFromLens(base.cam2d.node(), mpos.getX(), mpos.getY()) self.pickerNP.setPos(0.0, 0.0, 0.0) self.collisionTraverser.traverse(traverseRoot) pickedObjects = [] if useIntoNodePaths: for i in range(self.collisionHandler.getNumEntries()): pickedObjects.append(self.collisionHandler.getEntry(i).getIntoNodePath()) else: for i in range(self.collisionHandler.getNumEntries()): pickedObjects.append(self.collisionHandler.getEntry(i)) return pickedObjects
class RepairMousePicker: def __init__(self): self.pickerNode = CollisionNode('RepairMousePicker.pickerNode') self.pickerNP = base.cam2d.attachNewNode(self.pickerNode) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.collisionTraverser = CollisionTraverser() self.collisionHandler = CollisionHandlerQueue() self.collisionTraverser.addCollider(self.pickerNP, self.collisionHandler) self.clearCollisionMask() self.orthographic = True def destroy(self): del self.pickerNode self.pickerNP.removeNode() del self.pickerNP del self.pickerRay del self.collisionTraverser del self.collisionHandler def setOrthographic(self, ortho): self.orthographic = ortho def setCollisionMask(self, mask): self.pickerNode.setFromCollideMask(mask) def clearCollisionMask(self): self.pickerNode.setFromCollideMask(BitMask32.allOff()) def getCollisions(self, traverseRoot, useIntoNodePaths=False): if not base.mouseWatcherNode.hasMouse(): return [] mpos = base.mouseWatcherNode.getMouse() if self.orthographic: self.pickerRay.setFromLens(base.cam2d.node(), 0, 0) self.pickerNP.setPos(mpos.getX(), 0.0, mpos.getY()) else: self.pickerRay.setFromLens(base.cam2d.node(), mpos.getX(), mpos.getY()) self.pickerNP.setPos(0.0, 0.0, 0.0) self.collisionTraverser.traverse(traverseRoot) pickedObjects = [] if useIntoNodePaths: for i in range(self.collisionHandler.getNumEntries()): pickedObjects.append( self.collisionHandler.getEntry(i).getIntoNodePath()) else: for i in range(self.collisionHandler.getNumEntries()): pickedObjects.append(self.collisionHandler.getEntry(i)) return pickedObjects
class Selector(object): '''A Selector listens for mouse clicks and then runs select. Select then broadcasts the selected tag (if there is one)''' def __init__(self): ''' Should the traverser be shared? ''' LOG.debug("[Selector] Initializing") # The collision traverser does the checking of solids for collisions self.cTrav = CollisionTraverser() # The collision handler queue is a simple handler that records all # detected collisions during traversal self.cHandler = CollisionHandlerQueue() self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.cTrav.addCollider(self.pickerNP, self.cHandler) # Start listening to clicks self.resume() def select(self, event): LOG.debug("[Selector] Selecting ") if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.cTrav.traverse(render) # TODO - change this to a lower node if self.cHandler.getNumEntries() > 0: #LOG.debug("[Selector] Entries=%d"%self.cHandler.getNumEntries()) self.cHandler.sortEntries() selectionNP = self.cHandler.getEntry(0).getIntoNodePath() selection = selectionNP.findNetTag('SelectorTag').getTag( 'SelectorTag') if selection is not '': LOG.debug("[Selector] Collision with %s" % selection) Event.Dispatcher().broadcast( Event.Event('E_EntitySelect', src=self, data=selection)) else: LOG.debug("[Selector] No collision") #Event.Dispatcher().broadcast(Event.Event('E_EntityUnSelect', src=self, data=selection)) def pause(self): Event.Dispatcher().unregister(self, 'E_Mouse_1') def resume(self): print("unpausing selector") Event.Dispatcher().register(self, 'E_Mouse_1', self.select)
class Selector(object): '''A Selector listens for mouse clicks and then runs select. Select then broadcasts the selected tag (if there is one)''' def __init__(self): ''' Should the traverser be shared? ''' LOG.debug("[Selector] Initializing") # The collision traverser does the checking of solids for collisions self.cTrav = CollisionTraverser() # The collision handler queue is a simple handler that records all # detected collisions during traversal self.cHandler = CollisionHandlerQueue() self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.cTrav.addCollider(self.pickerNP, self.cHandler) # Start listening to clicks self.resume() def select(self, event): LOG.debug("[Selector] Selecting ") if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.cTrav.traverse(render) # TODO - change this to a lower node if self.cHandler.getNumEntries() > 0: #LOG.debug("[Selector] Entries=%d"%self.cHandler.getNumEntries()) self.cHandler.sortEntries() selectionNP = self.cHandler.getEntry(0).getIntoNodePath() selection = selectionNP.findNetTag('SelectorTag').getTag('SelectorTag') if selection is not '': LOG.debug("[Selector] Collision with %s" % selection) Event.Dispatcher().broadcast(Event.Event('E_EntitySelect', src=self, data=selection)) else: LOG.debug("[Selector] No collision") #Event.Dispatcher().broadcast(Event.Event('E_EntityUnSelect', src=self, data=selection)) def pause(self): Event.Dispatcher().unregister(self, 'E_Mouse_1') def resume(self): print("unpausing selector") Event.Dispatcher().register(self, 'E_Mouse_1', self.select)
class Picker(object): ''' classdocs ''' def __init__(self, camera, mouseWatcherNode, camNode, things): ''' Constructor ''' self.mouseWatcherNode = mouseWatcherNode self.camNode = camNode self.things = things self.pickerRay = CollisionRay() self.pickerNode = CollisionNode('mouseRay') self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerNode.addSolid(self.pickerRay) self.pickerNP = camera.attachNewNode(self.pickerNode) self.pq = CollisionHandlerQueue() self.picker = CollisionTraverser() self.picker.addCollider(self.pickerNP, self.pq) def getMouseOn(self, mouse_x, mouse_y): #Set the position of the ray based on the mouse position self.pickerRay.setFromLens(self.camNode, mouse_x, mouse_y) self.picker.traverse(self.things.node) 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() selectedNode = self.pq.getEntry(0).getIntoNode() selectedNodeId = selectedNode.getTag('nodeId') thingId = selectedNode.getTag('ID') mouseOnInfo = MouseOnInfo(self.things.getById(thingId), thingId, selectedNode, selectedNodeId, mouse_x, mouse_y) return mouseOnInfo
def intersect(lbase, delta, mask=None): t = time.time() root = lbase.rootnode terrain = root.getChildren()[2] terrain.setCollideMask(BitMask32.bit(1)) player = root collTrav = CollisionTraverser() #the collision traverser. we need this to perform collide in the end fromObject = player.attachNewNode(CollisionNode('colNode')) camera_pos = tuple(lbase.cameras.getPos()) lens = lbase.cameras.getChildren()[0].node().getLens() fov = np.radians(lens.getMinFov()) zpos = camera_pos[1] sw = 2. * np.abs(zpos) * np.tan(fov / 2.) rvals = np.arange(-sw/2., sw/2., delta) if mask is None: poses = [(xpos , -1 * zpos, ypos) for xpos in rvals for ypos in rvals] else: assert mask.shape == (len(rvals), len(rvals)) poses = [(xpos , -1 * zpos, ypos) for _i, xpos in enumerate(rvals) for _j, ypos in enumerate(rvals) if mask[_j, _i] < 1] print(len(poses), 'lp', len(rvals)**2) print('1a', time.time() - t) t = time.time() for p in poses: vec = camera_pos + p fromObject.node().addSolid(CollisionRay(*vec)) print('1', time.time() - t) t = time.time() #and now we turn turn of the collision for the playermodel so it wont collide with the ray or anything. player.node().setIntoCollideMask(BitMask32.allOff()) fromObject.node().setFromCollideMask(BitMask32.bit(1)) queue = CollisionHandlerQueue() collTrav.addCollider(fromObject, queue) print('2', time.time() - t) t = time.time() collTrav.traverse(root) print('3', time.time() - t) return queue
class heightChecker(): def __init__(self): self.picker = CollisionTraverser() self.pickerQ = CollisionHandlerQueue() pickerCollN = CollisionNode('heightChecker') self.pickerNode = render.attachNewNode(pickerCollN) pickerCollN.setFromCollideMask(BitMask32.bit(1)) pickerCollN.setIntoCollideMask(BitMask32.allOff()) self.pickerRay = CollisionRay(0,0,300,0,0,-1) pickerCollN.addSolid(self.pickerRay) self.picker.addCollider(self.pickerNode, self.pickerQ) def getHeight(self,obj,pos): res=0 self.pickerNode.setPos(pos) self.picker.traverse(obj) if self.pickerQ.getNumEntries() > 0: self.pickerQ.sortEntries() res=self.pickerQ.getEntry(0).getSurfacePoint(render).getZ() return res
class mouseControl(DirectObject): def __init__(self): self.picker = CollisionTraverser() self.pickerQ = CollisionHandlerQueue() pickerCollN = CollisionNode('mouseRay') pickerCamN = base.camera.attachNewNode(pickerCollN) pickerCollN.setFromCollideMask(BitMask32.bit(1)) pickerCollN.setIntoCollideMask(BitMask32.allOff()) self.pickerRay = CollisionRay() pickerCollN.addSolid(self.pickerRay) self.picker.addCollider(pickerCamN, self.pickerQ) self.accept('mouse1',self.pick) def pick(self): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.picker.traverse(render) for i in xrange(self.pickerQ.getNumEntries()): entry=self.pickerQ.getEntry(i) player.control('replace_wp', ('goto', Vec3(entry.getSurfacePoint(render))))
class Gui3D: def __init__(self, game_data, gfx_manager): self.game_data = game_data self.gui_traverser = CollisionTraverser() self.handler = CollisionHandlerQueue() self.selectable_objects = {} for cid, model in gfx_manager.character_models.items(): new_collision_node = CollisionNode('person_' + str(cid)) new_collision_node.addSolid( CollisionTube(0, 0, 0.5, 0, 0, 1.5, 0.5)) new_collision_nodepath = model.attachNewNode(new_collision_node) new_collision_nodepath.setTag("type", "character") new_collision_nodepath.setTag("id", str(cid)) picker_node = CollisionNode('mouseRay') picker_np = camera.attachNewNode(picker_node) self.picker_ray = CollisionRay() picker_node.addSolid(self.picker_ray) self.gui_traverser.addCollider(picker_np, self.handler) self.floor = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0))) self.floor_np = render.attachNewNode(CollisionNode('floor')) self.floor_np.setTag("type", "ground") self.floor_np.node().addSolid(self.floor) def mouse_click(self): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.picker_ray.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.gui_traverser.traverse(render) num_entries = self.handler.getNumEntries() if num_entries > 0: self.handler.sortEntries() entry = self.handler.getEntry(0) selected = entry.getIntoNodePath() selected_type = selected.getTag("type") if selected_type == "character": self.game_data.select_character(int(selected.getTag("id"))) elif selected_type == "ground": self.game_data.click_point(entry.getSurfacePoint(render))
class Gui3D: def __init__(self, game_data, gfx_manager): self.game_data = game_data self.gui_traverser = CollisionTraverser() self.handler = CollisionHandlerQueue() self.selectable_objects = {} for cid, model in gfx_manager.character_models.items(): new_collision_node = CollisionNode('person_' + str(cid)) new_collision_node.addSolid(CollisionTube(0, 0, 0.5, 0, 0, 1.5, 0.5)) new_collision_nodepath = model.attachNewNode(new_collision_node) new_collision_nodepath.setTag("type","character") new_collision_nodepath.setTag("id",str(cid)) picker_node = CollisionNode('mouseRay') picker_np = camera.attachNewNode(picker_node) self.picker_ray = CollisionRay() picker_node.addSolid(self.picker_ray) self.gui_traverser.addCollider(picker_np, self.handler) self.floor = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0))) self.floor_np = render.attachNewNode(CollisionNode('floor')) self.floor_np.setTag("type", "ground") self.floor_np.node().addSolid(self.floor) def mouse_click(self): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.picker_ray.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.gui_traverser.traverse(render) num_entries = self.handler.getNumEntries() if num_entries > 0: self.handler.sortEntries() entry = self.handler.getEntry(0) selected = entry.getIntoNodePath() selected_type = selected.getTag("type") if selected_type == "character": self.game_data.select_character(int(selected.getTag("id"))) elif selected_type == "ground": self.game_data.click_point(entry.getSurfacePoint(render))
collisionHandler.addOutPattern("ray-out-cards") PICKING_MASK = BitMask32.bit(1) #** Setting the ray collider pickerNode = CollisionNode('mouseraycnode') # another important but obvious difference from step 6 is that this time we parent the ray nodepath in render2d instead render root nodepath, otherwise all the objects we're going to define in 2D won't be seen by the ray. pickerNP = base.render2d.attachNewNode(pickerNode) pickerNP.show() # note that this time we set the ray dimension along the Y axis 2 point long to pierce everything is on the Y=0 position (2D objects are usually placed there) pickerRay = CollisionRay(0, -1, 0, 0, 1, 0) pickerNode.addSolid(pickerRay) pickerNode.setFromCollideMask(PICKING_MASK) pickerNode.setIntoCollideMask(BitMask32.allOff()) #** put the ray into the traverse cycle customCtrav.addCollider(pickerNP, collisionHandler) #** We create here 3 cards (indeed are) each of them tagged to bring with the id numnber we'll use to load the proper card texture later and its status which, in the beginning, is hidden (the back card facing up). cm = CardMaker('cm') left, right, bottom, top = 0, 1.4, 0, -2 cm.setFrame(left, right, top, bottom) # Note we parent the card in aspect2d instead render2d because it will keep the right proportions even with different screen ratios cardrootNP = aspect2d.attachNewNode('cardroot') tex = loader.loadTexture('textures/cards/back.png') for x in range(3): card = cardrootNP.attachNewNode(cm.generate()) card.setPos(x * 2, 0, -1) card.setTag('id', str(x + 1)) card.setTag('status', 'hidden') card.setTexture(tex) card.setCollideMask(PICKING_MASK)
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.cTrav = CollisionTraverser() self.cHandler = CollisionHandlerEvent() self.gameMode = "Exploring" self.countNpc = 0 self.npcName = [] self.npcX = [] self.npcY = [] self.talkies = False self.txtConvo = OnscreenText("", style=1, align=TextNode.ALeft, fg=(1, 1, 1, 1), pos=(-1.1, -0.6, 0), scale=0.1) self.txtConvoOp1 = OnscreenText("", style=1, align=TextNode.ALeft, fg=(1, 1, 1, 1), pos=(-1.1, -0.65, 0), scale=0.1) self.txtConvoOp2 = OnscreenText("", style=1, align=TextNode.ALeft, fg=(1, 1, 1, 1), pos=(-1.1, -0.7, 0), scale=0.1) self.txtConvoOp3 = OnscreenText("", style=1, align=TextNode.ALeft, fg=(1, 1, 1, 1), pos=(-1.1, -0.75, 0), scale=0.1) self.convoLineSelected = 0 self.keyboardSetup() self.cameraDistance = -50 self.camHeight = 25 self.camXAngle = 180 self.camYAngle = -15 self.camZAngle = 0 self.corrAngle = math.pi / 2 self.createPlayer() self.terrainSize = 20 self.drawTerrain() self.placeModels() self.collides() #cTrav.showCollisions(render) self.taskMgr.add(self.spinCameraTask, "SpinCameraTask") self.taskMgr.add(self.step, "GameStep") self.drawUI() def createPlayer(self): self.player = self.loader.loadModel( "models/man.x") #,{"walk": "models/panda-walk4"} self.playerNode = render.attachNewNode("PlayerNode") self.playerNode.setScale(1, 1, 1) self.playerCollider = self.playerNode.attachNewNode( CollisionNode("playerCollider")) self.playerCollider.node().addSolid(CollisionSphere(0, 0, 0, 5)) self.player.reparentTo(self.playerNode) self.cTrav.addCollider(self.playerCollider, self.cHandler) #self.playerCollider.show() self.playerY = 50 self.playerX = 50 self.playerZ = 0 self.playerDir = 0.0 self.playerMove = 0.0 self.playerTurn = 0.0 self.playerJumpHeight = 2 self.playerJumpDist = 0 self.playerJumpGrav = 0.2 self.playerJump = 0 self.playerSpeed = 6 self.playerTurnSpeed = 1 self.playerNode.setH(self.playerDir) def step(self, task): if self.gameMode == "Exploring": if (self.playerMove != 0): self.movePlayer(task) if (self.playerTurn != 0): self.turnPlayer(task) if (self.playerJumpDist > 0): self.playerJumpDist += self.playerJump self.playerJump -= self.playerJumpGrav if (self.playerJumpDist <= 1): self.playerJumpDist = 0 self.drawPlayer() task.delayTime = 0.01 return Task.again def spinCameraTask(self, task): if (self.playerMove == 0 and self.gameMode == "Exploring"): self.updateCamera() if (self.gameMode == "Conversation"): self.playerAngle = self.playerNode.getH() * math.pi / 180 self.camX = self.playerX + self.cameraDistance * math.cos( self.corrAngle - self.playerAngle) self.camY = self.playerY + self.cameraDistance * -math.sin( self.corrAngle - self.playerAngle) self.camZ = self.getObjectZ(self.playerX, self.playerY) + self.camHeight self.camera.setPos(self.playerX, self.playerY, self.playerZ + 10) self.camera.lookAt(self.talkiesNpc.getX(), self.talkiesNpc.getY(), self.talkiesNpc.getZ() + 10) return Task.cont def updateCamera(self): self.playerAngle = self.playerNode.getH() * math.pi / 180 self.camX = self.playerX + self.cameraDistance * math.cos( self.corrAngle - self.playerAngle) self.camY = self.playerY + self.cameraDistance * -math.sin( self.corrAngle - self.playerAngle) self.camZ = self.getObjectZ(self.playerX, self.playerY) + self.camHeight self.camera.setPos(self.camX, self.camY, self.camZ) self.camera.setHpr(self.playerDir + self.camXAngle, self.camYAngle, self.camZAngle) def drawUI(self): self.imgInv = dict() for box in range(0, 5): self.imgInv[box] = OnscreenImage(image="textures/inventoryBox.png", pos=((box * 0.22) - 1, 0, -0.9), scale=(0.1, 0.1, 0.1)) self.imgInv[box].setTransparency(TransparencyAttrib.MAlpha) def getObjectZ(self, x, y): if ((x > 0) and (x < 257) and (y > 0) and (y < 257)): return (self.terrain.getElevation(x, y) * self.terrainSize) else: return 0 def placeModels(self): cubeCount = 12 cubeXInc = 24 cubeGen = 0 cubeGenX = 0 cubeGenY = -50 cubeGenScale = 10 cubeGenRot = 90 while (cubeGen < cubeCount): cube = self.loader.loadModel("models/house2.x") cube.reparentTo(self.render) cube.setScale(cubeGenScale, cubeGenScale * 2, cubeGenScale) cube.setPos(0 + cubeXInc * cubeGen, cubeGenY, 0) cubeGen += 1 cubeGen = 0 while (cubeGen < cubeCount): cubeGen += 1 self.placeNPC("Sally Susan", -50, -50) self.placeNPC("Gerald Fanturbett", -80, -40) self.placeNPC("Pillynostrum MacSternum", -20, -100) def placeNPC(self, name, x, y): npcScale = 1 npcTexture = loader.loadTexture("textures/texRock2.png") self.npc = self.loader.loadModel("models/man.x") self.npcNode = render.attachNewNode("NpcNode") self.npc.reparentTo(self.npcNode) self.npcName += [name] self.npc.setName(name) self.npc.setScale(1, 1, 1) self.npc.setPos(x, y, 0) self.npcX += [x] self.npcY += [y] self.npc.setTexture(npcTexture) self.npcCollider = self.npc.attachNewNode(CollisionNode("npcCollider")) self.npcCollider.node().addSolid(CollisionSphere(0, 0, 0, 5)) self.countNpc += 1 #self.npcCollider.show() def conversationWithNPC(self): if self.talkies == True and self.gameMode != "Conversation": self.txtConvo.setText("HEY! LETS TALK!") self.txtConvoOp1.setText("") self.txtConvoOp2.setText("") self.txtConvoOp3.setText("") self.gameMode = "Conversation" elif self.gameMode == "Conversation": self.gameMode = "Exploring" def drawTerrain(self): self.terrain = GeoMipTerrain("terrain") self.terrain.setHeightfield(Filename("textures/heights.png")) self.terrain.setColorMap("textures/heightColour.png") self.terrain.setBlockSize(64) self.terrain.setFactor(0) self.terrain.setNear(40) self.terrain.setFar(120) self.terrain.setMinLevel(1) self.terrain.setBruteforce(True) self.terrain.generate() self.terrain.setAutoFlatten(self.terrain.AFMLight) self.terrain.setFocalPoint( Point3(self.playerX, self.playerY, self.playerZ)) self.root = self.terrain.getRoot() self.root.reparentTo(render) self.root.setSz(self.terrainSize) def jumpPlayer(self): if (self.playerJumpDist == 0): self.playerJump = self.playerJumpHeight self.playerJumpDist += self.playerJump def movePlayer(self, task): self.dx = self.playerMove * math.cos(self.corrAngle - self.playerAngle) self.dy = self.playerMove * -math.sin(self.corrAngle - self.playerAngle) move = True for i in range(self.countNpc): xi = self.playerX + self.dx / 10 xii = self.npcX[i] yi = self.playerY + self.dy / 10 yii = self.npcY[i] sq1 = (xi - xii) * (xi - xii) sq2 = (yi - yii) * (yi - yii) distance = math.sqrt(sq1 + sq2) if distance < 5: move = False if move == True: self.playerX += self.dx / 10 self.playerY += self.dy / 10 self.playerZ = self.getObjectZ(self.playerX, self.playerY) self.playerNode.setPos(self.playerX, self.playerY, self.playerZ + self.playerJumpDist) self.updateCamera() self.terrain.setFocalPoint( Point3(self.playerX, self.playerY, self.playerZ)) self.terrain.update() def drawPlayer(self): self.playerNode.setPos(self.playerX, self.playerY, self.playerZ + self.playerJumpDist) def turnPlayer(self, task): self.playerDir += self.playerTurn self.playerNode.setH(self.playerDir) def keyboardSetup(self): self.accept("w", self.keyW) self.accept("w-up", self.resetMove) self.accept("s", self.keyS) self.accept("s-up", self.resetMove) self.accept("a", self.keyA) self.accept("enter", self.conversationWithNPC) self.accept("a-up", self.resetDir) self.accept("d", self.keyD) self.accept("d-up", self.resetDir) self.accept("space", self.jumpPlayer) def collideEventIn(self, entry): np_into = entry.getIntoNodePath() self.txtConvo.setText("<Press Enter to talk to %s>" % np_into.getParent().getName()) np_into.getParent().setHpr(self.playerDir - 180, 0, 0) self.talkies = True self.talkiesNpc = np_into.getParent() def collideEventOut(self, entry): self.txtConvo.setText("") self.talkies = False self.gameMode = "Exploring" def collides(self): self.cHandler.addInPattern('%fn-into-%in') self.cHandler.addOutPattern('%fn-out-%in') DO = DirectObject() DO.accept("playerCollider-into-npcCollider", self.collideEventIn) DO.accept("playerCollider-out-npcCollider", self.collideEventOut) def keyW(self): self.playerMove = self.playerSpeed def resetMove(self): self.playerMove = 0 def resetDir(self): self.playerTurn = 0 def keyS(self): self.playerMove = -self.playerSpeed def keyA(self): self.playerTurn = self.playerTurnSpeed def keyD(self): self.playerTurn = -self.playerTurnSpeed
class thirdPerson(DirectObject): def __init__(self, parserClass, mainClass, mapLoaderClass, modelLoaderClass): self.switchState = False # self.t = Timer() self.keyMap = {"left": 0, "right": 0, "forward": 0, "backward": 0} self.ralph = Actor( "data/models/units/ralph/ralph", {"run": "data/models/units/ralph/ralph-run", "walk": "data/models/units/ralph/ralph-walk"}, ) self.ralph.reparentTo(render) # self.ralph.setPos(42, 30, 0) self.ralph.setPos(6, 10, 0) self.ralph.setScale(0.1) self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_up", self.setKey, ["forward", 1]) self.accept("arrow_up-up", self.setKey, ["forward", 0]) self.accept("arrow_down", self.setKey, ["backward", 1]) self.accept("arrow_down-up", self.setKey, ["backward", 0]) self.isMoving = False self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 1000) self.ralphGroundRay.setDirection(0, 0, -1) self.ralphGroundCol = CollisionNode("ralphRay") self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) # self.ralphGroundCol.show() base.cam.reparentTo(self.ralph) base.cam.setPos(0, 9, 7) self.floater2 = NodePath(PandaNode("floater2")) self.floater2.reparentTo(self.ralph) self.floater2.setZ(self.floater2.getZ() + 6) base.cam.lookAt(self.floater2) # Uncomment this line to see the collision rays # self.ralphGroundColNp.show() # self.camGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring # self.cTrav.showCollisions(render) self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) taskMgr.add(self.move, "movingTask", extraArgs=[mainClass, parserClass, mapLoaderClass, modelLoaderClass]) # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value def move(self, mainClass, parserClass, mapLoaderClass, modelLoaderClass): # Get the time elapsed since last frame. We need this # for framerate-independent movement. elapsed = globalClock.getDt() # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if self.keyMap["left"] != 0: self.ralph.setH(self.ralph.getH() + elapsed * 300) if self.keyMap["right"] != 0: self.ralph.setH(self.ralph.getH() - elapsed * 300) if self.keyMap["forward"] != 0: self.ralph.setY(self.ralph, -(elapsed * 50)) # 25)) if self.keyMap["backward"] != 0: self.ralph.setY(self.ralph, +(elapsed * 20)) if (self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0) or (self.keyMap["right"] != 0): if self.isMoving is False: self.ralph.loop("run") self.isMoving = True elif self.keyMap["backward"] != 0: if self.isMoving is False: self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False # Now check for collisions. self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries) > 0) and (entries[0].getIntoNode().getName()[0:4] == "tile"): self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) elif (len(entries) > 0) and (entries[0].getIntoNode().getName()[0:5] == "solid"): self.ralph.setPos(startpos) x = int( entries[0] .getIntoNode() .getName()[len(entries[0].getIntoNode().getName()) - 6 : len(entries[0].getIntoNode().getName()) - 4] ) y = int(entries[0].getIntoNode().getName()[len(entries[0].getIntoNode().getName()) - 2 :]) if mapLoaderClass.tileArray[y][x].drillTime != None: mainClass.changeTile(mapLoaderClass.tileArray[y][x], 0, parserClass, modelLoaderClass, mapLoaderClass) else: self.ralph.setPos(startpos) self.ralph.setP(0) return Task.cont
class World(DirectObject): #class World, extends DirectObject, builds the world to play the game ###################### INITIALIZATIONS ######################################### def __init__(self): mySplashScreen = SplashScreen() mySplashScreen.loading() mySplashScreen.introduction() self.promptMode() self.turnWallNotification() ##### Creating Scene ##### self.createBackground() self.loadWallModel() self.loadBallModel() self.setCamera() self.createLighting() ##### Create Controls ##### self.createKeyControls() self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "drop":0} ##### Task Manager ##### timer = 0.2 taskMgr.doMethodLater(timer, self.traverseTask, "tsk_traverse") #scans for collisions every 0.2 seconds taskMgr.add(self.move,"moveTask") #constant smooth movement ##### Collisions ##### self.createBallColliderModel() self.disableForwardMovement = False self.disableBackwardMovement = False self.disableLeftMovement = False self.disableRightMovement = False ##### Game state variables ##### self.isMoving = False self.isDropping = False self.camAngle = math.pi/2 self.direction = "W" #constant; does not change with relativity self.drop = False self.levelHeight = 2.1 self.level = 0 self.maxLevel = 6 self.currentHeight = 13.302 self.cameraHeight = 0.2 self.mode = None self.timer = "" ##### Views ##### self.xray_mode = False self.collision_mode = False self.wireframe = False ##### On-Screen Text ##### self.title = addTitle("aMAZEing") self.instructions = OnscreenText(text="[ i ]: Toggle Instructions", style=1, fg=(0, 0, 0, 1), pos=(1.3, 0.95), align=TextNode.ARight, scale=0.05) self.instr = [] self.messages = [] self.levelText = OnscreenText(text= "Level = " + str(self.level), style=1, fg=(0, 0, 0, 1), pos=(-1.3, -0.95), align=TextNode.ALeft, scale=0.07) self.directionText = OnscreenText(text="Direction = " + self.direction, style=1, fg=(0, 0, 0, 1), pos=(-1.3, -0.85), align=TextNode.ALeft, scale=0.07) self.timerText = OnscreenText(text= self.timer, style=1, fg=(1, 1, 1, 1), pos=(1.3, 0.85), align=TextNode.ARight, scale=0.07) def setKey(self, key, value): #records the state of the arrow keys self.keyMap[key] = value ###################### Onscreen Text ####################################### def postInstructions(self): #posts the instructions onto the screen inst1 = addInstructions(0.95, "[ESC]: Quit") self.instr.append(inst1) inst2 = addInstructions(0.90, "[Left Arrow]: Turn Left") self.instr.append(inst2) inst3 = addInstructions(0.85, "[Right Arrow]: Turn Right") self.instr.append(inst3) inst4 = addInstructions(0.80, "[Up Arrow]: Move Ball Forward") self.instr.append(inst4) inst5 = addInstructions(0.75, "[Down Arrow]: Move Ball Backwards") self.instr.append(inst5) inst6 = addInstructions(0.70, "[Space]: Drop Levels (if level drop is availale)") self.instr.append(inst6) inst7 = addInstructions(0.60, "[x]: Toggle XRay Mode") self.instr.append(inst7) inst8 = addInstructions(0.55, "[c]: Toggle Collision Mode") self.instr.append(inst8) inst9 = addInstructions(0.50, "[z]: Toggle Wireframe") self.instr.append(inst9) inst10 = OnscreenText(text='''Hello! Welcome to aMAZEing! You are this sphere, and your goal is to find the exit of the maze! Each level of the maze has a hole you can drop through, to move on to the next level. This maze has six levels and each maze is a 12x12. If you chose timer mode, you have 5 minutes to finish the maze, or else you lose. Good luck! You're aMAZEing :)''', style = 1, fg=(0, 0, 0, 1), pos=(0, -.1), align=TextNode.ACenter, scale=0.07) self.instr.append(inst10) def deleteInstructions(self): #deletes onscreen instructions for instr in self.instr: instr.destroy() def addNotification(self, txt): #adds a notification to the screen y = 0.9 tex = OnscreenText(text=txt, style=1, fg= (0, 0, 0, 1), pos=(0, y)) self.messages.append(tex) def deleteNotifications(self): #deletes all on-screen notifications for msg in self.messages: msg.destroy() def updateLevelText(self): #updates the level text self.levelText.destroy() levelTextPos = (-1.3, -0.95) levelScale = 0.07 self.levelText = OnscreenText(text= "Level = " + str(self.level), style=1, fg=(0, 0, 0, 1), pos=levelTextPos, align=TextNode.ALeft, scale=levelScale) def updateDirectionText(self): #updates the direction text on the screen self.directionText.destroy() directionTextPos = (-1.3, -0.85) directionScale = 0.07 self.directionText = OnscreenText(text="Direction = " + self.direction, style=1, fg=(0, 0, 0, 1), pos=directionTextPos, align=TextNode.ALeft, scale=directionScale) def updateTimerText(self): #updates timer on screen self.timerText.destroy() timerTextPos = (1.3, 0.85) timerScale = 0.07 if self.mode == "timer": self.timerText = OnscreenText(text= self.timer, style=1, fg=(1, 1, 1, 1), pos=timerTextPos, align=TextNode.ARight, scale=timerScale) def turnWallNotification(self): #give a notification sequence at the beginning notificationSeq = Sequence() notificationSeq.append(Func(addNotification,""" If you just see a blank color, it means you are facing a wall :)""")) notificationSeq.append(Wait(8)) notificationSeq.append(Func(deleteNotifications)) notificationSeq.start() def promptMode(self): #prompts for the mode modeScreen = SplashScreen() modeScreen.mode() def setMode(self, mode): #sets the mode of the game self.mode = mode if self.mode == "timer": self.setTimer() ###################### Initialization Helper Functions ##################### def createBackground(self): #black feautureless space base.win.setClearColor(Vec4(0,0,0,1)) def loadWallModel(self): #loads the wall model (the maze) wallScale = 0.3 wallModelName = self.randomWallModel() #randomly select a maze self.wallModel = loader.loadModel(wallModelName) self.wallModel.setScale(wallScale) self.wallModel.setPos(0, 0, 0) self.wallModel.setCollideMask(BitMask32.allOff()) self.wallModel.reparentTo(render) ### Setting Texture ### texScale = 0.08 self.wallModel.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldNormal) self.wallModel.setTexProjector(TextureStage.getDefault(), render, self.wallModel) self.wallModel.setTexScale(TextureStage.getDefault(), texScale) tex = loader.load3DTexture('/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/wallTex/wallTex_#.png') self.wallModel.setTexture(tex) #creating visual geometry collision self.wallModel.setCollideMask(BitMask32.bit(0)) def randomWallModel(self): #generates a random wall in the library of mazes that were #randomly generated by the Blender script "mazeGenerator" #and exported to this computer numMazes = 10 name = str(random.randint(0, numMazes)) #randomly selects a number saved in the computer path = "/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/mazeModels/maze" path += name return path def loadBallModel(self): #loads the character, a ball model #ballModelStartPos = (-8, -8, 0.701) #THIS IS THE END ballModelStartPos = (8, 8, 13.301) #level 0 ballScale = 0.01 self.ballModel = loader.loadModel("/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/ball") self.ballModel.reparentTo(render) self.ballModel.setScale(ballScale) self.ballModel.setPos(ballModelStartPos) ### Setting ball texture ### texScale = 0.08 self.ballModel.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldPosition) self.ballModel.setTexProjector(TextureStage.getDefault(), render, self.ballModel) self.ballModel.setTexScale(TextureStage.getDefault(), texScale) tex = loader.load3DTexture('/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/ballTex/ballTex_#.png') self.ballModel.setTexture(tex) def setCamera(self): #sets up the initial camera location #camera will follow the sphere followLength = 2 camHeight = 0.2 base.disableMouse() base.camera.setPos(self.ballModel.getX(), self.ballModel.getY() - followLength, self.ballModel.getZ() + camHeight) base.camLens.setNear(0.4) #creates a floater object - will look at the floater object #above the sphere, so you can get a better view self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) def createKeyControls(self): #creates the controllers for the keys #event handler #describes what each key does when pressed and unpressed self.accept("escape", sys.exit) self.accept("arrow_left", self.turnLeft) self.accept("arrow_right", self.turnRight) self.accept("arrow_up", self.setKey, ["forward",1]) self.accept("arrow_down", self.setKey, ["backward",1]) self.accept("space", self.nowDropping) #unpressed event handlers self.accept("arrow_left-up", self.setKey, ["left",0]) self.accept("arrow_right-up", self.setKey, ["right",0]) self.accept("arrow_up-up", self.setKey, ["forward",0]) self.accept("arrow_down-up", self.setKey, ["backward",0]) self.accept("space_up", self.setKey, ["drop", 0]) #views self.accept('x', self.toggle_xray_mode) self.accept('c', self.toggle_collision_mode) self.accept('z', self.toggle_wireframe) #information self.accept('i', self.postInstructions) self.accept('i-up', self.deleteInstructions) #restart self.accept('r', self.restart) #modes self.accept("t", self.setMode, ["timer"]) self.accept("m", self.setMode, ["marathon"]) def createBallColliderModel(self): #creates the collider sphere around the ball cSphereRad = 9.9 self.cTrav = CollisionTraverser() #moves over all possible collisions self.ballModelSphere = CollisionSphere(0, 0, 0, cSphereRad) #collision mesh around ball is a simple sphere self.ballModelCol = CollisionNode('ballModelSphere') self.ballModelCol.addSolid(self.ballModelSphere) self.ballModelCol.setFromCollideMask(BitMask32.bit(0)) self.ballModelCol.setIntoCollideMask(BitMask32.allOff()) self.ballModelColNp = self.ballModel.attachNewNode(self.ballModelCol) self.ballModelGroundHandler = CollisionHandlerQueue() #collision handler queue stores all collision points self.cTrav.addCollider(self.ballModelColNp, self.ballModelGroundHandler) def createLighting(self): #creates lighting for the scene aLightVal = 0.3 dLightVal1 = -5 dLightVal2 = 5 #set up the ambient light ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(aLightVal, aLightVal, aLightVal, 1)) ambientLight1 = AmbientLight("ambientLight1") ambientLight1.setColor(Vec4(aLightVal, aLightVal, aLightVal, 1)) ambientLight2 = AmbientLight("ambientLight2") ambientLight2.setColor(Vec4(aLightVal, aLightVal, aLightVal, 1)) #sets a directional light directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(dLightVal1, dLightVal1, dLightVal1)) directionalLight.setColor(Vec4(1, 1, 1, 1)) directionalLight.setSpecularColor(Vec4(0, 0, 0, 1)) #sets a directional light directionalLight1 = DirectionalLight("directionalLight2") directionalLight1.setDirection(Vec3(dLightVal2, dLightVal1, dLightVal1)) directionalLight1.setColor(Vec4(1, 1, 1, 1)) directionalLight1.setSpecularColor(Vec4(1, 1, 1, 1)) #attaches lights to scene render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(ambientLight1)) render.setLight(render.attachNewNode(ambientLight1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(directionalLight1)) ###################### COLLISION DETECTION ##################################### def traverseTask(self, task=None): # handles collisions with collision handers and a # collision queue # essentially checks region of potential collision for collisions # and stops the ball if a collision is triggered # called by task manager self.ballModelGroundHandler.sortEntries() for i in range(self.ballModelGroundHandler.getNumEntries()): entry = self.ballModelGroundHandler.getEntry(i) if self.drop == True: #we cant drop in this situation self.ballModel.setZ(self.currentHeight) dropFailWait = 4 dropFailSeq = Sequence() dropFailSeq.append(Func(addNotification,"Whoops! You can't drop here!")) dropFailSeq.append(Wait(dropFailWait)) dropFailSeq.append(Func(deleteNotifications)) dropFailSeq.start() self.drop = False elif self.direction == "N": self.northDisableMovements() elif self.direction == "S": self.southDisableMovements() elif self.direction == "E": self.eastDisableMovements() elif self.direction == "W": self.westDisableMovements() if task: return task.cont #exit task # If there are no collisions if task: return task.cont def northDisableMovements(self): #disables movements when direction is north if self.keyMap["forward"] != 0: #if the ball was moving foward self.disableForwardMovement = True #disable forward movement if self.keyMap["backward"] != 0: self.disableBackwardMovement = True def southDisableMovements(self): #disables movements when direction is south if self.keyMap["forward"] != 0: self.disableBackwardMovement = True if self.keyMap["backward"] != 0: self.disableForwardMovement = True def eastDisableMovements(self): #disables movements when direction is east if self.keyMap["forward"] != 0: self.disableRightMovement = True if self.keyMap["backward"] != 0: self.disableLeftMovement = True def westDisableMovements(self): #disables movements when direction is west if self.keyMap["forward"] != 0: self.disableLeftMovement = True if self.keyMap["backward"] != 0: self.disableRightMovement = True def checkCollisions(self): #checks for collisions self.cTrav.traverse(render) def enableAllWalls(self): #enables all walls by disabling all the disable wall functions self.disableLeftMovement = False self.disableRightMovement = False self.disableForwardMovement = False self.disableBackwardMovement = False def inCollision(self): #return true if we are in a collision right now, false otherwise if (self.disableForwardMovement == True or self.disableBackwardMovement == True or self.disableRightMovement == True or self.disableLeftMovement): return True return False def checkForWin(self): #checks for a win, toggles win splash sceen if we win yLoc = self.ballModel.getY() exitBound = -9.1 if yLoc < exitBound: winScreen = SplashScreen() winScreen.win() if self.mode == "timer": self.checkForTimerLoss() def checkForTimerLoss(self): #checks to see the time, will lose if past 5 minutes if self.timer == "0:05:00": loseScreen = SplashScreen() loseScreen.lose() ###################### MOVEMENTS ############################################### def move(self, task): # Accepts arrow keys to move the player front and back # Also deals with grid checking and collision detection step = 0.03 #movement animation self.movementAnimation(step) #rotation animation self.rotationAnimation() base.camera.setX(self.ballModel.getX() + math.sin(self.camAngle)) base.camera.setY(self.ballModel.getY() + math.cos(self.camAngle)) self.resetCamDist() self.checkCollisions() self.lookAtFloater() self.checkForWin() return task.cont def resetCamDist(self): #resets the camera distance to a specific distance #keeps distance relatively constant camFarDist = 0.75 camCloseDist = 0.7 camvec = self.ballModel.getPos() - base.camera.getPos() #vector between ball and camera camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > camFarDist): base.camera.setPos(base.camera.getPos() + camvec*(camdist-camFarDist)) camdist = camFarDist if (camdist < camCloseDist): base.camera.setPos(base.camera.getPos() - camvec*(camCloseDist-camdist)) camdist = camCloseDist base.camera.lookAt(self.ballModel) def lookAtFloater(self): #looks at the floater above the sphere floaterHeight = 0.23 self.floater.setPos(self.ballModel.getPos()) self.floater.setZ(self.ballModel.getZ() + floaterHeight) base.camera.lookAt(self.floater) ####################### Movement Animation ################################# def ballIsMoving(self): #notes if the ball is moving or not with self.isMoving variable if (self.keyMap["forward"]!=0) or (self.keyMap["backward"]!=0): if self.isMoving == False: self.isMoving = True elif self.keyMap["forward"] == 0 and self.keyMap["backward"] == 0: self.isMoving = False def movementAnimation(self, step): #describes the movement animation if self.drop == True: self.dropMovementAnimation(step) elif self.direction == "N": self.northMovementAnimation(step) elif self.direction == "S": self.southMovementAnimation(step) elif self.direction == "E": self.eastMovementAnimation(step) elif self.direction == "W": self.westMovementAnimation(step) def northMovementAnimation(self, step): #describes animation when direction is north if (self.keyMap["forward"]!=0): #if you are pressing forward if self.disableForwardMovement == False: #if you are just moving through space... self.ballModel.setY(self.ballModel.getY() + step) if self.disableBackwardMovement == True: #if you had moved backwards into a wall #and you want to move forward again self.ballModel.setY(self.ballModel.getY() + step) self.disableBackwardMovement = False if (self.keyMap["backward"]!=0): #if you are pressing backwards if self.disableBackwardMovement == False: #if you are just moving backwards through space... self.ballModel.setY(self.ballModel.getY() - step) if self.disableForwardMovement == True: #if you had moved forward into a wall #and want to back away from the wall self.ballModel.setY(self.ballModel.getY() - step) self.disableForwardMovement = False def southMovementAnimation(self, step): #describes animation when direction is north #same relative set of animations to northMovementAnimation #but opposite if (self.keyMap["forward"]!=0): if self.disableBackwardMovement == False: self.ballModel.setY(self.ballModel.getY() - step) if self.disableForwardMovement == True: self.ballModel.setY(self.ballModel.getY() - step) self.disableForwardMovement = False if (self.keyMap["backward"]!=0): if self.disableForwardMovement == False: self.ballModel.setY(self.ballModel.getY() + step) if self.disableBackwardMovement == True: self.ballModel.setY(self.ballModel.getY() + step) self.disableBackwardMovement = False def eastMovementAnimation(self, step): #describes animation when direction is east #same relative as north and south movement animations #but relative to the x axis #and disabling/enabling right and left movement at collisions if (self.keyMap["forward"]!=0): if self.disableRightMovement == False: self.ballModel.setX(self.ballModel.getX() + step) if self.disableLeftMovement == True: self.ballModel.setX(self.ballModel.getX() + step) self.disableLeftMovement = False if (self.keyMap["backward"]!=0): if self.disableLeftMovement == False: self.ballModel.setX(self.ballModel.getX() - step) if self.disableRightMovement == True: self.ballModel.setX(self.ballModel.getX() - step) self.disableRightMovement = False def westMovementAnimation(self, step): #describes animation when direction is west #relatively same animations as the east movement animations #exact opposite if (self.keyMap["forward"]!=0): if self.disableLeftMovement == False: self.ballModel.setX(self.ballModel.getX() - step) if self.disableRightMovement == True: self.ballModel.setX(self.ballModel.getX() - step) self.disableRightMovement = False if (self.keyMap["backward"]!=0): if self.disableRightMovement == False: self.ballModel.setX(self.ballModel.getX() + step) if self.disableLeftMovement == True: self.ballModel.setX(self.ballModel.getX() + step) self.disableLeftMovement = False def turnRight(self): #turns right in the animation #uses an interval to slowly rotate camera around initial = self.camAngle final = self.camAngle + math.pi/2 #turn animation turnTime = 0.2 turnRightSeq = Sequence() turnRightSeq.append(LerpFunc(self.changeCamAngle, turnTime, initial, final, 'easeInOut')) turnRightSeq.start() self.setKey("right", 1) #notes that the right key is pressed #changes the direction right, based on current direction if self.direction == "N": self.direction = "E" elif self.direction == "E": self.direction = "S" elif self.direction == "S": self.direction = "W" else: self.direction = "N" #when you turn, all the collision disablements should be True #just checking #self.enableAllWalls() #update the label self.updateDirectionText() def turnLeft(self): #turns left initial = self.camAngle final = self.camAngle - math.pi/2 #turn animation turnTime = 0.2 turnRightSeq = Sequence() turnRightSeq.append(LerpFunc(self.changeCamAngle, turnTime, initial, final, 'easeInOut')) turnRightSeq.start() self.setKey("left", 1) #notes that left key is pressed #changes the direction left, based on current direction if self.direction == "N": self.direction = "W" elif self.direction == "W": self.direction = "S" elif self.direction == "S": self.direction = "E" else: self.direction = "N" #when you turn, all the collision disablements should be True #just checking #self.enableAllWalls() #update the label self.updateDirectionText() def changeCamAngle(self, angle): #changes the camAngle to angle self.camAngle = angle def dropMovementAnimation(self, step): #describes movement when drop is hit a = 0.1 if self.keyMap["drop"] != 0: if self.ballModel.getZ() > self.currentHeight - self.levelHeight+ a: self.ballModel.setZ(self.ballModel.getZ() - step) else: self.currentHeight -= self.levelHeight self.level += 1 self.updateLevelText() self.drop = False base.camera.setZ(self.ballModel.getZ() + self.cameraHeight) def nowDropping(self): #toggles isDropping boolean self.drop = True self.setKey("drop", 1) ################## Ball Rotation Animation ################################# def rotationAnimation(self): #describes the rotation movement of sphere self.ballIsMoving() speed=300 inCollision = self.inCollision() if self.isMoving and not inCollision: if self.direction == "N": self.northRotationAnimation(speed) if self.direction == "S": self.southRotationAnimation(speed) if self.direction == "E": self.eastRotationAnimation(speed) if self.direction == "W": self.westRotationAnimation(speed) def northRotationAnimation(self, speed): #describes the rotation animation if direction is north if self.keyMap["forward"] != 0: self.ballModel.setP(self.ballModel.getP()-speed*globalClock.getDt()) elif self.keyMap["backward"] != 0: self.ballModel.setP(self.ballModel.getP()+speed*globalClock.getDt()) def southRotationAnimation(self, speed): #describes the rotaiton animation if the direction is south if self.keyMap["backward"] != 0: self.ballModel.setP(self.ballModel.getP()-speed*globalClock.getDt()) elif self.keyMap["forward"] != 0: self.ballModel.setP(self.ballModel.getP()+speed*globalClock.getDt()) def eastRotationAnimation(self, speed): #describes the rotation animation if the direction is east if self.keyMap["backward"] != 0: self.ballModel.setR(self.ballModel.getR()-speed*globalClock.getDt()) elif self.keyMap["forward"] != 0: self.ballModel.setR(self.ballModel.getR()+speed*globalClock.getDt()) def westRotationAnimation(self, speed): #describes the rotation animation if the direction is west if self.keyMap["forward"] != 0: self.ballModel.setR(self.ballModel.getR()-speed*globalClock.getDt()) elif self.keyMap["backward"] != 0: self.ballModel.setR(self.ballModel.getR()+speed*globalClock.getDt()) ###################### VIEWS ################################################### def toggle_xray_mode(self): #Toggle X-ray mode on and off. #Note: slows down program considerably xRayA = 0.5 self.xray_mode = not self.xray_mode if self.xray_mode: self.wallModel.setColorScale((1, 1, 1, xRayA)) self.wallModel.setTransparency(TransparencyAttrib.MDual) else: self.wallModel.setColorScaleOff() self.wallModel.setTransparency(TransparencyAttrib.MNone) def toggle_collision_mode(self): #Toggle collision mode on and off #Shows visual representation of the collisions occuring self.collision_mode = not self.collision_mode if self.collision_mode == True: # Note: Slows the program down considerably self.cTrav.showCollisions(render) else: self.cTrav.hideCollisions() def toggle_wireframe(self): #toggles wireframe view self.wireframe = not self.wireframe if self.wireframe: self.wallModel.setRenderModeWireframe() else: self.wallModel.setRenderModeFilled() ##################### RESTART ################################################## def restart(self): #restarts the game loading = SplashScreen() loading.loading() self.reset() def reset(self): #resets the maze, resets the location of the character #removes all notes self.wallModel.removeNode() self.ballModel.removeNode() #resets notes self.loadWallModel() self.loadBallModel() self.createBallColliderModel() self.resetCamDist() #resets timers taskMgr.remove("timerTask") self.timer = "" self.timerText.destroy() self.promptMode() #################### TIMER ##################################################### def setTimer(self): #code from panda.egg user on Panda3D, #"How to use Timer, a small example maybe?" forum #creates a timer self.timer = DirectLabel(pos=Vec3(1, 0.85),scale=0.08) taskMgr.add(self.timerTask, "timerTask") def dCharstr(self, theString): #code from panda.egg user on Panda3D, #"How to use Timer, a small example maybe?" forum #turns time string into a readable clock string if len(theString) != 2: theString = '0' + theString return theString def timerTask(self, task): #code from panda.egg user on Panda3D, #"How to use Timer, a small example maybe?" forum #task for resetting timer in timer mode secondsTime = int(task.time) minutesTime = int(secondsTime/60) hoursTime = int(minutesTime/60) self.timer = (str(hoursTime) + ':' + self.dCharstr(str(minutesTime%60)) + ':' + self.dCharstr(str(secondsTime%60))) self.updateTimerText() return Task.cont
class Mouse(DirectObject): def __init__(self, app): # local variables for mouse class self.app = app self.init_collide() self.has_mouse = None self.prev_pos = None self.pos = None self.drag_start = None self.hovered_object = None self.button2 = False self.mouseTask = taskMgr.add(self.mouse_task, 'mouseTask') self.task = None # set up event and response to this event self.accept('mouse1', self.mouse1) self.accept('mouse1-up', self.mouse1_up) # change the mouse to accept 'right-click' to rotate camera self.accept('mouse3', self.rotateCamera) self.accept('mouse3-up', self.stopCamera) self.accept('wheel_up', self.zoomIn) self.accept('wheel_down', self.zoomOut) # set up the collision for object def init_collide(self): # why the heck he import within method from pandac.PandaModules import CollisionTraverser, CollisionNode from pandac.PandaModules import CollisionHandlerQueue, CollisionRay # init and import collision for object self.cTrav = CollisionTraverser('MousePointer') self.cQueue = CollisionHandlerQueue() self.cNode = CollisionNode('MousePointer') self.cNodePath = base.camera.attachNewNode(self.cNode) self.cNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.cRay = CollisionRay() self.cNode.addSolid(self.cRay) self.cTrav.addCollider(self.cNodePath, self.cQueue) # by the collision methods mouse is able to find out which tile mouse is at def find_object(self): if self.app.world.nodePath: self.cRay.setFromLens(base.camNode, self.pos.getX(), self.pos.getY()) self.cTrav.traverse(self.app.world.terrain.nodePath) if self.cQueue.getNumEntries() > 0: self.cQueue.sortEntries() return self.cQueue.getEntry(0).getIntoNodePath() return None # setting task for mouse def mouse_task(self, task): action = task.cont # if the current tile has a mouse point to this self.has_mouse = base.mouseWatcherNode.hasMouse() if self.has_mouse: self.pos = base.mouseWatcherNode.getMouse() if self.prev_pos: self.delta = self.pos - self.prev_pos else: self.delta = None if self.task: action = self.task(task) else: self.pos = None if self.pos: self.prev_pos = Point2(self.pos.getX(), self.pos.getY()) return action # when mouse hover over this hexagon def hover(self, task): if self.hovered_object: self.hovered_object.unhover() self.hovered_object = None if self.button2: self.camera_drag() hovered_nodePath = self.find_object() if hovered_nodePath: tile = hovered_nodePath.findNetTag('tile') if not tile.isEmpty(): tag = tile.getTag('tile') coords = tag.split(',') (x, y) = [int(n) for n in coords] # set the hovered target to be the corresponding hexagon on terrain self.hovered_object = self.app.world.terrain.rows[x][y] self.hovered_object.hover() character = hovered_nodePath.findNetTag('char') if not character.isEmpty(): tag = character.getTag('char') (team_index, char_id) = [int(n) for n in tag.split(',')] self.hovered_object = self.app.world.teams[ team_index].characters_dict[char_id] self.hovered_object.hover() ghost = hovered_nodePath.findNetTag('ghost') if not ghost.isEmpty(): tag = ghost.getTag('ghost') (team_index, char_id) = [int(n) for n in tag.split(',')] for ghostInstance in self.app.ghosts: if (ghostInstance.team.index == team_index) and (ghostInstance.id == char_id): self.hovered_object = ghostInstance self.hovered_object.hover() return task.cont def mouse1(self): self.app.state.request('mouse1') def mouse1_up(self): self.app.state.request('mouse1-up') def camera_drag(self): if self.delta: old_heading = base.camera.getH() new_heading = old_heading - self.delta.getX() * 180 base.camera.setH(new_heading % 360) old_pitch = base.camera.getP() new_pitch = old_pitch + self.delta.getY() * 90 new_pitch = max(-90, min(-10, new_pitch)) base.camera.setP(new_pitch) def rotateCamera(self): self.button2 = True def stopCamera(self): self.button2 = False def zoomIn(self): lens = base.cam.node().getLens() size = lens.getFilmSize() if size.length() >= 75: lens.setFilmSize(size / 1.2) def zoomOut(self): lens = base.cam.node().getLens() size = lens.getFilmSize() if size.length() <= 250: lens.setFilmSize(size * 1.2)
class MyApp(ShowBase): def addTitle(self,text): return OnscreenText(text=text, style=1, fg=(1,1,1,1), pos=(0,-0.95), align=TextNode.ACenter, scale = .07) def makeStatusLabel(self, i): return OnscreenText(style=1, fg=(1,1,0,1), pos=(-1.3 + (i*0.8), -0.95 ), align=TextNode.ALeft, scale = .05, mayChange = 1) def __init__(self): #base = ShowBase() ShowBase.__init__(self) self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0} base.win.setClearColor(Vec4(0,0,0,1)) self.texto1 = OnscreenText(text="Collect 8 balls and meet Sonic behind the building", style=1, fg=(1,1,1,1), pos=(0,-0.1), align=TextNode.ACenter, scale = .07) self.texto2 = OnscreenText(text="Eat bananas for energy and avoid green stones", style=1, fg=(1,1,1,1), pos=(0,-0.2), align=TextNode.ACenter, scale = .07) self.texto3 = OnscreenText(text="Arrow keys move the player", style=1, fg=(1,1,1,1), pos=(0,-0.3), align=TextNode.ACenter, scale = .07) self.texto4 = OnscreenText(text="a and s help you view the scene", style=1, fg=(1,1,1,1), pos=(0,-0.4), align=TextNode.ACenter, scale = .07) mySound = base.loader.loadSfx("models/Theme_song.ogg") mySound.setLoop(True) mySound.play() #mySound.setLoop(true) self.noOfbanana = self.makeStatusLabel(0) self.noOfBalls = self.makeStatusLabel(1) self.points = self.makeStatusLabel(2) self.environ = self.loader.loadModel("models/moonsurface.egg") self.environ.reparentTo(self.render) self.environ.setScale(0.25, 0.25, 0.25) self.environ.setPos(-8, 42, -3) self.environ1 = self.loader.loadModel("models/env") self.environ1.reparentTo(self.render) self.environ1.setScale(50,50,30) self.environ1.setPos(0, -170, -3) #self.environ1.setHpr(90,0,0) self.chair1=self.loader.loadModel("models/BeachChair") #self.chair1=self.reaparentTo(self.render) #self.setScale(1000) #self.setPos(25,-160,-3) #self.chair1.setHpr(90,0,0) self.house1 = self.loader.loadModel("models/houses/church") self.house1.reparentTo(self.render) self.house1.setScale(0.30) self.house1.setPos(25, -150, -3) self.house1.setHpr(90,0,0) self.house2 = self.loader.loadModel("models/houses/building") self.house2.reparentTo(self.render) self.house2.setScale(0.30) self.house2.setPos(18, -200, -3) self.house2.setHpr(180,0,0) self.house3 = self.loader.loadModel("models/houses/farmhouse") self.house3.reparentTo(self.render) self.house3.setScale(0.30) self.house3.setPos(20, -130, -3) self.house3.setHpr(90,0,0) self.house4 = self.loader.loadModel("models/houses/dojo") self.house4.reparentTo(self.render) self.house4.setScale(0.05) self.house4.setPos(5, -220, -3) self.house5 = self.loader.loadModel("models/houses/beachhouse2") self.house5.reparentTo(self.render) self.house5.setScale(0.30) self.house5.setPos(-10, -180, -3) self.house5.setHpr(-90,0,0) self.house6 = self.loader.loadModel("models/houses/gazebo") self.house6.reparentTo(self.render) self.house6.setScale(0.50) self.house6.setPos(-10, -200, -3) self.house7 = self.loader.loadModel("models/houses/building") self.house7.reparentTo(self.render) self.house7.setScale(0.30) self.house7.setPos(-10, -120, -3) ''' for x in range(0,8): self.load4 = loader.loadModel("models/fence") self.load4.reparentTo(render) self.load4.setScale(.5, .5, 1.3) self.load4.setPos(28-x*7,0,1.8) cp = self.load4.attachNewNode(CollisionNode('box')) cp.node().addSolid(CollisionPolygon( Point3(-10.0,0.0,4),Point3(10,0,4), Point3(10,-1,-2),Point3(-10,-1,-2))) ''' self.tunnel = [None for i in range(10)] for x in range(10): #Load a copy of the tunnel self.tunnel[x] = loader.loadModel('models/tunnel') self.tunnel[x].setHpr(0,90,0) self.tunnel[x].setScale(0.5) self.tunnel[x].setPos(0,177.5 + 25*x, 0) self.tunnel[x].reparentTo(self.render) ## ###World specific-code ## ## #Create an instance of fog called 'distanceFog'. ## #'distanceFog' is just a name for our fog, not a specific type of fog. ## self.fog = Fog('distanceFog') ## #Set the initial color of our fog to black. ## self.fog.setColor(0, 0, 0) ## #Set the density/falloff of the fog. The range is 0-1. ## #The higher the numer, the "bigger" the fog effect. ## self.fog.setExpDensity(.08) ## #We will set fog on render which means that everything in our scene will ## #be affected by fog. Alternatively, you could only set fog on a specific ## #object/node and only it and the nodes below it would be affected by ## #the fog. ## render.setFog(self.fog) self.banana = [None for i in range(20)] self.flag = [0 for i in range(20)] self.fla = [0 for i in range(5)] self.fl = [0 for i in range(8)] for x in range(10): #Load a copy of the tunnel self.banana[x] = loader.loadModel('models/banana/banana') #self.banana[x].setHpr(0,90,0) self.banana[x].setScale(0.7) if(x%2==0): self.banana[x].setPos(-1,180 + 25*x, -2) else: self.banana[x].setPos(1,177.5 + 25*x, -2) self.banana[x].reparentTo(self.render) self.banana[11] = self.loader.loadModel("models/banana/banana") self.banana[11].reparentTo(self.render) self.banana[11].setPos(12, 8, -2) self.banana[12] = self.loader.loadModel("models/banana/banana") self.banana[12].reparentTo(self.render) self.banana[12].setPos(0, 120, -2) self.banana[13] = self.loader.loadModel("models/banana/banana") self.banana[13].reparentTo(self.render) self.banana[13].setPos(12, 100, -2) self.banana[14] = self.loader.loadModel("models/banana/banana") self.banana[14].reparentTo(self.render) self.banana[14].setPos(22, 80, -2) self.banana[15] = self.loader.loadModel("models/banana/banana") self.banana[15].reparentTo(self.render) self.banana[15].setPos(12, 50, -2) self.banana[16] = self.loader.loadModel("models/banana/banana") self.banana[16].reparentTo(self.render) self.banana[16].setPos(15, 30, -2) self.banana[17] = self.loader.loadModel("models/banana/banana") self.banana[17].reparentTo(self.render) self.banana[17].setPos(-10, 8, -2) self.banana[18] = self.loader.loadModel("models/banana/banana") self.banana[18].reparentTo(self.render) self.banana[18].setPos(-20, -30, -2) self.banana[19] = self.loader.loadModel("models/banana/banana") self.banana[19].reparentTo(self.render) self.banana[19].setPos(-50, -50, -2) self.candy = self.loader.loadModel("models/candy/candycane2") self.candy.reparentTo(self.render) self.candy.setScale(0.001) self.candy.setPos(-6, 10, -2) self.fire = self.loader.loadModel("models/candy/candycane2") self.fire.reparentTo(self.render) self.fire.setScale(0.001) self.fire.setPos(0, 2, -2) self.ball = [None for i in range(8)] self.ball[0] = self.loader.loadModel("models/ball/soccerball") self.ball[0].reparentTo(self.render) self.ball[0].setPos(-6, 6, -2) self.ball[0].setScale(0.7) self.ball[1] = self.loader.loadModel("models/ball/soccerball") self.ball[1].reparentTo(self.render) self.ball[1].setPos(-6, -6, -2) self.ball[1].setScale(0.7) self.ball[2] = self.loader.loadModel("models/ball/soccerball") self.ball[2].reparentTo(self.render) self.ball[2].setPos(-15, 10, -2) self.ball[2].setScale(0.7) self.ball[3] = self.loader.loadModel("models/ball/soccerball") self.ball[3].reparentTo(self.render) self.ball[3].setPos(-19, 0, -2) self.ball[3].setScale(0.7) self.ball[4] = self.loader.loadModel("models/ball/soccerball") self.ball[4].reparentTo(self.render) self.ball[4].setPos(-6, -20, -2) self.ball[4].setScale(0.7) self.ball[5] = self.loader.loadModel("models/ball/soccerball") self.ball[5].reparentTo(self.render) self.ball[5].setPos(6, 6, -2) self.ball[5].setScale(0.7) self.ball[6] = self.loader.loadModel("models/ball/soccerball") self.ball[6].reparentTo(self.render) self.ball[6].setPos(19, 10, -2) self.ball[6].setScale(0.7) self.ball[7] = self.loader.loadModel("models/ball/soccerball") self.ball[7].reparentTo(self.render) self.ball[7].setPos(-15, 12, -2) self.ball[7].setScale(0.7) self.rock = [None for i in range(8)] self.rock[0] = self.loader.loadModel("models/greencrystal") self.rock[0].reparentTo(self.render) self.rock[0].setPos(0,306, -4) self.rock[0].setScale(0.007) self.rock[0].setHpr(90,0,0) self.rock[1] = self.loader.loadModel("models/greencrystal") self.rock[1].reparentTo(self.render) self.rock[1].setPos(-2, 150, -3) self.rock[1].setScale(0.007) self.rock[1].setHpr(90,0,0) self.rock[2] = self.loader.loadModel("models/greencrystal") self.rock[2].reparentTo(self.render) self.rock[2].setPos(-10, 10, -3) self.rock[2].setScale(0.007) self.rock[2].setHpr(90,0,0) self.rock[3] = self.loader.loadModel("models/greencrystal") self.rock[3].reparentTo(self.render) self.rock[3].setPos(5, 0, -3) self.rock[3].setScale(0.007) self.rock[3].setHpr(90,0,0) self.rock[4] = self.loader.loadModel("models/greencrystal") self.rock[4].reparentTo(self.render) self.rock[4].setPos(-2, -120, -3) self.rock[4].setScale(0.007) self.rock[4].setHpr(90,0,0) self.tire = self.loader.loadModel("models/tire/tire") self.tire.reparentTo(self.render) self.tire.setScale(0.25, 0.25, 0.25) self.tire.setPos(-20, 3, -2) self.bunny1 = self.loader.loadModel("models/bunny") self.bunny1.reparentTo(self.render) self.bunny1.setScale(0.2) self.bunny1.setPos(15, -160, -3) self.bunny1.setHpr(-60,0,0) self.bunny2 = self.loader.loadModel("models/bunny") self.bunny2.reparentTo(self.render) self.bunny2.setScale(0.2) self.bunny2.setPos(15, -161, -3) self.bunny2.setHpr(-145,0,0) # Add the spinCameraTask procedure to the task manager. #self.taskMgr.add(self.spinCameraTask, "SpinCameraTask") # Load and transform the panda actor. self.pandaActor = Actor("models/panda-model", {"walk": "models/panda-walk4"}) self.pandaActor.setScale(0.005, 0.005, 0.005) #self.pandaActor.setPos(0,100,-3) self.pandaActor.reparentTo(self.render) # Loop its animation. self.pandaActor.loop("walk") # Create the four lerp intervals needed for the panda to # walk back and forth. pandaPosInterval1 = self.pandaActor.posInterval(20, Point3(0, -110, -3), startPos=Point3(0, -90, -3)) pandaPosInterval2 = self.pandaActor.posInterval(20, Point3(0, -90, -3), startPos=Point3(0, -110, -3)) pandaHprInterval1 = self.pandaActor.hprInterval(3, Point3(180, 0, 0), startHpr=Point3(0, 0, 0)) pandaHprInterval2 = self.pandaActor.hprInterval(3, Point3(0, 0, 0), startHpr=Point3(180, 0, 0)) # Create and play the sequence that coordinates the intervals. self.pandaPace = Sequence(pandaPosInterval1, pandaHprInterval1, pandaPosInterval2, pandaHprInterval2, name="pandaPace") self.pandaPace.loop() self.eve = Actor("models/eve", {"walk": "models/eve-walk"}) self.eve.setScale(0.5, 0.5, 0.5) self.eve.setPos(-1,-140,-3) self.eve.reparentTo(self.render) # Loop its animation. self.eve.loop("walk") # Create the four lerp intervals needed for the panda to # walk back and forth. evePosInterval1 = self.eve.posInterval(20, Point3(-1, -160, -3), startPos=Point3(-1, -140, -3)) evePosInterval2 = self.eve.posInterval(20, Point3(-1, -140, -3), startPos=Point3(-1, -160, -3)) eveHprInterval1 = self.eve.hprInterval(3, Point3(180, 0, 0), startHpr=Point3(0, 0, 0)) eveHprInterval2 = self.eve.hprInterval(3, Point3(0, 0, 0), startHpr=Point3(180, 0, 0)) # Create and play the sequence that coordinates the intervals. self.evePace = Sequence(evePosInterval1,eveHprInterval1,evePosInterval2,eveHprInterval2,name="evePace") self.evePace.loop() self.ralph = Actor("models/r/ralph", {"run":"models/ralph-run", "walk": "models/ralph-walk"}) self.ralph.setScale(0.5, 0.5, 0.5) self.ralph.setPos(0, 420, -3) self.ralph.reparentTo(self.render) self.boy = Actor("models/soni/sonic", {"anim":"models/soni/sonic-win"}) self.boy.setScale(0.05, 0.05, 0.05) self.boy.setPos(33, -203, -2) self.boy.setHpr(-90,0,0) self.boy.reparentTo(self.render) self.boy.loop("anim") self.boy1 = Actor("models/boy/boymodel", {"anim":"models/boy/boyanimation"}) self.boy1.setScale(0.007) self.boy1.setPos(-5, -200, -2) self.boy1.setHpr(180,0,0) self.boy1.reparentTo(self.render) self.boy1.loop("anim") self.character=Actor() self.character.loadModel('models/dancer') self.character.setPos(3,150,-3) self.character.reparentTo(render) self.character.setHpr(180,0,0) self.character.setScale(0.6) self.character.loadAnims({'win':'models/dancer'}) self.character.loop('win') self.character1=Actor() self.character1.loadModel('models/gorillawalking') self.character1.setPos(2,-13,-3) self.character1.setScale(0.6) self.character1.reparentTo(render) self.character1.setHpr(180,0,0) self.character1.loadAnims({'win':'models/gorillawalking'}) self.character1.loop('win') self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left",1]) self.accept("arrow_right", self.setKey, ["right",1]) self.accept("arrow_up", self.setKey, ["forward",1]) self.accept("a", self.setKey, ["cam-left",1]) self.accept("s", self.setKey, ["cam-right",1]) self.accept("arrow_left-up", self.setKey, ["left",0]) self.accept("arrow_right-up", self.setKey, ["right",0]) self.accept("arrow_up-up", self.setKey, ["forward",0]) self.accept("a-up", self.setKey, ["cam-left",0]) self.accept("s-up", self.setKey, ["cam-right",0]) taskMgr.add(self.move,"moveTask") taskMgr.add(self.find,"fisdTask") taskMgr.add(self.potask,"potaskTask") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,-1) #print self.ralph.getX(), self.ralph.getY() ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(-5, -5, -5)) directionalLight.setColor(Vec4(1, 1, 1, 1)) directionalLight.setSpecularColor(Vec4(1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) self.updateStatusLabel() self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0,0,1000) self.ralphGroundRay.setDirection(0,0,-1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,1000) self.camGroundRay.setDirection(0,0,-1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) def potask(self,task): global points if(self.ralph.getY()<410): self.texto1.destroy() self.texto2.destroy() self.texto3.destroy() self.texto4.destroy() if(points<0): OnscreenText(text="Game Over", style=1, fg=(1,1,1,1), pos=(0,0), align=TextNode.ACenter, scale = 0.4) OnscreenText(text="You are out of energy", style=1, fg=(1,1,1,1), pos=(0,-0.20), align=TextNode.ACenter, scale = 0.05) return Task.cont def find(self,task): global nob, points, noba #print self.ralph.getX(),self.ralph.getY() if ((self.ralph.getX()>=-3 and self.ralph.getX()<=-1) and (self.ralph.getY()>=145 and self.ralph.getY()<=165) and self.fla[1] == 0): self.rock[1].removeNode() points= points - 20 self.fla[1]=1 elif((self.ralph.getX()>=-11 and self.ralph.getX()<=-9) and (self.ralph.getY()>=9 and self.ralph.getY()<=11) and self.fla[2] == 0): self.rock[2].removeNode() points= points - 20 self.fla[2]=1 elif((self.ralph.getX()>=4 and self.ralph.getX()<=6) and (self.ralph.getY()>=-1 and self.ralph.getY()<=1) and self.fla[3] == 0): self.rock[3].removeNode() points= points - 20 self.fla[3]=1 elif((self.ralph.getX()>=-1 and self.ralph.getX()<=1) and (self.ralph.getY()>=305 and self.ralph.getY()<=307) and self.fla[0] == 0): self.rock[0].removeNode() points= points - 20 self.fla[0]=1 elif((self.ralph.getX()>=-3 and self.ralph.getX()<=-1) and (self.ralph.getY()>=-121 and self.ralph.getY()<=-119) and self.fla[4] == 0): self.rock[4].removeNode() points= points - 20 self.fla[4]=1 if ((self.ralph.getX()>=-7.5 and self.ralph.getX()<=-6.5) and (self.ralph.getY()>=-7.5 and self.ralph.getY()<=-6.5) and self.fl[1] == 0): self.ball[1].removeNode() noba= noba + 1 self.fl[1]=1 elif((self.ralph.getX()>=-15.5 and self.ralph.getX()<=-14.5) and (self.ralph.getY()>=9.5 and self.ralph.getY()<=10.5) and self.fl[2] == 0): self.ball[2].removeNode() noba= noba + 1 self.fl[2]=1 elif((self.ralph.getX()>=-19.5 and self.ralph.getX()<=-18.5) and (self.ralph.getY()>=-0.5 and self.ralph.getY()<=0.5) and self.fl[3] == 0): self.ball[3].removeNode() noba= noba + 1 self.fl[3]=1 elif((self.ralph.getX()>=-6.5 and self.ralph.getX()<=-5.5) and (self.ralph.getY()>=5.5 and self.ralph.getY()<=6.5) and self.fl[0] == 0): self.ball[0].removeNode() noba= noba + 1 self.fl[0]=1 elif((self.ralph.getX()>=-6.5 and self.ralph.getX()<=-5.5) and (self.ralph.getY()>=-20.5 and self.ralph.getY()<=-19.5) and self.fl[4] == 0): self.ball[4].removeNode() noba= noba + 1 self.fl[4]=1 elif((self.ralph.getX()>=5.5 and self.ralph.getX()<=6.5) and (self.ralph.getY()>=5.5 and self.ralph.getY()<=6.5) and self.fl[5] == 0): self.ball[5].removeNode() noba= noba + 1 self.fl[5]=1 elif((self.ralph.getX()>=18.5 and self.ralph.getX()<=19.5) and (self.ralph.getY()>=9.5 and self.ralph.getY()<=10.5) and self.fl[6] == 0): self.ball[6].removeNode() noba= noba + 1 self.fl[6]=1 elif((self.ralph.getX()>=-15.5 and self.ralph.getX()<=-14.5) and (self.ralph.getY()>=11.5 and self.ralph.getY()<=12.5) and self.fl[7] == 0): self.ball[7].removeNode() noba= noba + 1 self.fl[7]=1 if ((self.ralph.getX()>=11.5 and self.ralph.getX()<=12.5) and (self.ralph.getY()>=7.5 and self.ralph.getY()<=8.5) and self.flag[11]==0): self.banana[11].removeNode() nob= nob + 1 points= points + 10 self.flag[11]=1 elif ((self.ralph.getX()>=0.5 and self.ralph.getX()<=1.5) and (self.ralph.getY()>=404.5 and self.ralph.getY()<=405.5) and self.flag[9]==0): self.banana[9].removeNode() nob= nob + 1 points= points + 10 self.flag[9]=1 elif ((self.ralph.getX()>=0.5 and self.ralph.getX()<=1.5) and (self.ralph.getY()>=354.5 and self.ralph.getY()<=355.5) and self.flag[7]==0): self.banana[7].removeNode() nob= nob + 1 points= points + 10 self.flag[7]=1 elif ((self.ralph.getX()>=0.5 and self.ralph.getX()<=1.5) and (self.ralph.getY()>=304.5 and self.ralph.getY()<=305.5) and self.flag[5]==0): self.banana[5].removeNode() nob= nob + 1 points= points + 10 self.flag[5]=1 elif ((self.ralph.getX()>=0.5 and self.ralph.getX()<=1.5) and (self.ralph.getY()>=254.5 and self.ralph.getY()<=255.5) and self.flag[3]==0): self.banana[3].removeNode() nob= nob + 1 points= points + 10 self.flag[3]=1 elif ((self.ralph.getX()>=0.5 and self.ralph.getX()<=1.5) and (self.ralph.getY()>=204.5 and self.ralph.getY()<=205.5) and self.flag[1]==0): self.banana[1].removeNode() nob= nob + 1 points= points + 10 self.flag[1]=1 elif ((self.ralph.getX()>=-1.5 and self.ralph.getX()<=-0.5) and (self.ralph.getY()>=379.5 and self.ralph.getY()<=380.5) and self.flag[8]==0): self.banana[8].removeNode() #print 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' nob= nob + 1 points= points + 10 self.flag[8]=1 elif ((self.ralph.getX()>=-1.5 and self.ralph.getX()<=-0.5) and (self.ralph.getY()>=329.5 and self.ralph.getY()<=330.5) and self.flag[6]==0): self.banana[6].removeNode() nob= nob + 1 points= points + 10 self.flag[6]=1 elif ((self.ralph.getX()>=-1.5 and self.ralph.getX()<=-0.5) and (self.ralph.getY()>=279.5 and self.ralph.getY()<=280.5) and self.flag[4]==0): self.banana[4].removeNode() nob= nob + 1 points= points + 10 self.flag[4]=1 elif ((self.ralph.getX()>=-1.5 and self.ralph.getX()<=-0.5) and (self.ralph.getY()>=229.5 and self.ralph.getY()<=230.5) and self.flag[2]==0): self.banana[2].removeNode() nob= nob + 1 points= points + 10 self.flag[2]=1 elif ((self.ralph.getX()>=-1.5 and self.ralph.getX()<=-0.5) and (self.ralph.getY()>=179.5 and self.ralph.getY()<=180.5) and self.flag[0]==0): self.banana[0].removeNode() nob= nob + 1 points= points + 10 self.flag[0]=1 elif ((self.ralph.getX()>=-0.5 and self.ralph.getX()<=0.5) and (self.ralph.getY()>=119.5 and self.ralph.getY()<=120.5) and self.flag[12]==0): self.banana[12].removeNode() nob= nob + 1 points= points + 10 self.flag[12]=1 elif ((self.ralph.getX()>=11.5 and self.ralph.getX()<=12.5) and (self.ralph.getY()>=99.5 and self.ralph.getY()<=100.5) and self.flag[13]==0): self.banana[13].removeNode() nob= nob + 1 points= points + 10 self.flag[13]=1 elif ((self.ralph.getX()>=21.5 and self.ralph.getX()<=22.5) and (self.ralph.getY()>=79.5 and self.ralph.getY()<=80.5) and self.flag[14]==0): self.banana[14].removeNode() nob= nob + 1 points= points + 10 self.flag[14]=1 elif ((self.ralph.getX()>=11.5 and self.ralph.getX()<=12.5) and (self.ralph.getY()>=49.5 and self.ralph.getY()<=50.5) and self.flag[15]==0): self.banana[15].removeNode() nob= nob + 1 points= points + 10 self.flag[15]=1 elif ((self.ralph.getX()>=14.5 and self.ralph.getX()<=15.5) and (self.ralph.getY()>=29.5 and self.ralph.getY()<=30.5) and self.flag[16]==0): self.banana[16].removeNode() nob= nob + 1 points= points + 10 self.flag[16]=1 elif ((self.ralph.getX()>=-10.5 and self.ralph.getX()<=-9.5) and (self.ralph.getY()>=7.5 and self.ralph.getY()<=8.5) and self.flag[17]==0): self.banana[17].removeNode() nob= nob + 1 points= points + 10 self.flag[17]=1 elif ((self.ralph.getX()>=-20.5 and self.ralph.getX()<=-19.5) and (self.ralph.getY()>=-30.5 and self.ralph.getY()<=-29.5) and self.flag[18]==0): self.banana[18].removeNode() nob= nob + 1 points= points + 10 self.flag[18]=1 elif ((self.ralph.getX()>=-50.5 and self.ralph.getX()<=-49.5) and (self.ralph.getY()>=-50.5 and self.ralph.getY()<=-49.5) and self.flag[19]==0): self.banana[19].removeNode() nob= nob + 1 points= points + 10 self.flag[19]=1 if(self.ralph.getX()>30 and self.ralph.getY()<-200 and noba <8): self.boy.loop("anim") #self.ralph.removeNode() OnscreenText(text="Game Over (n)-Sad!", style=1, fg=(1,1,1,1), pos=(0,0), align=TextNode.ACenter, scale = 0.4) OnscreenText(text="You've Failed this City! \nTask not Completed", style=1, fg=(1,1,1,1), pos=(0,-0.20), align=TextNode.ACenter, scale = 0.05) OnscreenText(text="This is a Akshay Arun Shubham Production!", style=1, fg=(1,1,1,1), pos=(0,-0.40), align=TextNode.ACenter, scale = 0.05) elif(self.ralph.getX()>30 and self.ralph.getY()<-200 and noba ==8): #self.ralph.removeNode() OnscreenText(text="Game Over", style=1, fg=(1,1,1,1), pos=(0,0), align=TextNode.ACenter, scale = 0.4) OnscreenText(text="Congratulations, Task Completed", style=1, fg=(1,1,1,1), pos=(0,-0.20), align=TextNode.ACenter, scale = 0.05) OnscreenText(text="This is a Akshay Arun Shubham Production!", style=1, fg=(1,1,1,1), pos=(0,-0.40), align=TextNode.ACenter, scale = 0.05) self.updateStatusLabel() return Task.cont #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): if(self.ralph.getY()<160): # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. base.camera.lookAt(self.ralph) if (self.keyMap["cam-left"]!=0): base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["cam-right"]!=0): base.camera.setX(base.camera, +20 * globalClock.getDt()) # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if (self.keyMap["left"]!=0): self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.ralph.setY(self.ralph, -25 * globalClock.getDt()) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0): if self.isMoving is False: self.ralph.loop("run") self.isMoving = True else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk",5) self.isMoving = False else: # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. base.camera.lookAt(self.ralph) startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if ((self.keyMap["left"]!=0) and self.ralph.getX()<2.5): self.ralph.setH(self.ralph.getH() + 200 * globalClock.getDt()) if ((self.keyMap["right"]!=0) and self.ralph.getX()>-2.5): self.ralph.setH(self.ralph.getH() - 200 * globalClock.getDt()) if ((self.keyMap["forward"]!=0) and self.ralph.getX()>-3 and self.ralph.getX()<3): self.ralph.setY(self.ralph, -25 * globalClock.getDt()) elif (self.ralph.getX()<-3): self.ralph.setX(-2.9) elif (self.ralph.getX()>3): self.ralph.setX(2.9) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0): if self.isMoving is False: self.ralph.loop("run") self.isMoving = True else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk",5) self.isMoving = False camvec = self.ralph.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 10.0): base.camera.setPos(base.camera.getPos() + camvec*(camdist-10)) camdist = 10.0 if (camdist < 5.0): base.camera.setPos(base.camera.getPos() - camvec*(5-camdist)) camdist = 5.0 return task.cont def updateStatusLabel( self ): global nob, points self.noOfbanana.setText("Bananas Taken: " + str(nob)) self.points.setText("Energy Meter: " + str(points)) self.noOfBalls.setText("Balls found: " + str(noba))
class Mode(object): """This is the base Mode class""" def __init__(self, game): self.name = "MODE" self.guiMediaPath = '../Packages/anw/gui/media/' self.alive = 1 self.enableMouseCamControl = 1 self.enableScrollWheelZoom = 1 self.canSelectFlags = {} self.messagePositions = [] self.selectTypes = [] self.gui = [] self.sims = [] self.game = game self.depth = 20.0 self.zoomCameraDepth = 10.0 self.zoomCameraOutDepth = -10.0 self.zoomSpeed = 5 self.panSpeed = 1.0 self.runningTasks = [] if globals.serverMode == 0: self.setMyBackground() camera.setHpr(0,0,0) self.mainmenu = None self.scrollSpeed = 0.1 if globals.serverMode == 0: self.setMousePicker() self.setCameraPosition() self.selector = None self.selector2 = None self.log = logging.getLogger('mode') self.entryFocusList = ('anw.gui.mainmenubuttons','anw.gui.industryvalue', 'anw.gui.cityindustry','anw.gui.weapondirection', 'anw.gui.scrollvalue','anw.gui.shipdesignvalue', 'anw.gui.systemmenu','anw.gui.tradevalue', 'anw.gui.designmenu','anw.gui.shipyardmenu', 'anw.gui.mimenu', 'anw.gui.textentry', 'anw.gui.marketsystemsellvalue', 'anw.gui.sendcreditsvalue') def __getstate__(self): odict = self.__dict__.copy() # copy the dict since we change it del odict['log'] # remove stuff not to be pickled return odict def __setstate__(self,dict): log=logging.getLogger('mode') self.__dict__.update(dict) self.log=log def setMousePicker(self): self.picker = CollisionTraverser() self.pq = CollisionHandlerQueue() self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.picker.addCollider(self.pickerNP, self.pq) self.selectable = render.attachNewNode("selectable") def setCameraPosition(self): self.cameraPos = (camera.getX(), camera.getY(), camera.getZ()) self.cameraMoving = 0 def setCanSelectFlag(self, key): """Set the Flag""" self.clearAllCanSelectFlags() self.canSelectFlags[key] = 1 def clearAllCanSelectFlags(self): """Clear any selection flags""" for key in self.canSelectFlags.keys(): self.canSelectFlags[key] = 0 def isAnyFlagSelected(self): """Return 1 if any flags are selected""" for key in self.canSelectFlags.keys(): if self.canSelectFlags[key] == 1: return 1 return 0 def validateSelection(self): """Can something be selected right now""" if self.cameraMoving == 0: return 1 else: return 0 def removeMyGui(self, myGuiName): """Remove gui""" myGui = getattr(self, myGuiName) if myGui in self.gui: self.gui.remove(myGui) if myGui != None: myGui.destroy() setattr(self, myGuiName, None) def createMainMenu(self, key): self.mainmenu = mainmenubuttons.MainMenuButtons(self.guiMediaPath) self.mainmenu.setMyGame(self.game) self.mainmenu.setMyMode(self) self.mainmenu.enableLastButton(key) self.mainmenu.checkDisableButton(key) self.mainmenu.writeGameInfo() self.mainmenu.acceptSpaceBarKey() self.gui.append(self.mainmenu) def removeMainMenu(self): if self.mainmenu != None: self.mainmenu.destroyMe() self.mainmenu = None def centerCameraOnSim(self, sim): """Center the camera on the sim position""" self.game.app.disableMouseCamControl() camera.setPos(sim.getX(), camera.getY(), sim.getZ()) camera.setHpr(0,0,0) if self.enableMouseCamControl == 1: self.game.app.enableMouseCamControl() def drawBox(self, x, y, width, height, color='guiblue1', lineWidth=0.15, glow=1): """Draw a box""" #LEFT myLine = line.Line(self.guiMediaPath,(x,y),(x,y+height), 'square_grey', lineWidth, glow) myLine.sim.setColor(globals.colors[color]) self.gui.append(myLine) #TOP myLine = line.Line(self.guiMediaPath,(x,y+height),(x+width,y+height), 'square_grey', lineWidth, glow) myLine.sim.setColor(globals.colors[color]) self.gui.append(myLine) #RIGHT myLine = line.Line(self.guiMediaPath,(x+width,y+height),(x+width,y), 'square_grey', lineWidth, glow) myLine.sim.setColor(globals.colors[color]) self.gui.append(myLine) #BOTTOM myLine = line.Line(self.guiMediaPath,(x+width,y),(x,y), 'square_grey', lineWidth, glow) myLine.sim.setColor(globals.colors[color]) self.gui.append(myLine) def stopCameraTasks(self): taskMgr.remove('zoomInCameraTask') taskMgr.remove('zoomOutCameraTask') self.cameraMoving = 0 self.game.app.enableMouseCamControl() self.enableMouseCamControl=1 def resetCamera(self): self.game.app.disableMouseCamControl() camera.setPos(self.cameraPos[0], self.zoomCameraOutDepth, self.cameraPos[2]) # I don't really understand why this doesn't reset the view when having a planet selected and hitting spacebar? camera.setHpr(0,0,0) if self.enableMouseCamControl == 1: self.game.app.enableMouseCamControl() def zoomInCamera(self): if camera.getY() <= self.zoomCameraDepth: self.game.app.disableMouseCamControl() taskMgr.add(self.zoomInCameraTask, 'zoomInCameraTask', extraArgs=[self.zoomCameraDepth]) self.runningTasks.append('zoomInCameraTask') def zoomInCameraAmount(self, amount): """Zoom in Camera a certain amount specified""" depth = camera.getY()+amount self.game.app.disableMouseCamControl() taskMgr.add(self.zoomInCameraTask, 'zoomInCameraTask', extraArgs=[depth]) self.runningTasks.append('zoomInCameraTask') def zoomInCameraTask(self, depth): """Zoom in the camera until its at depth""" y = camera.getY() if y + 0.1 >= depth: # or y >= 8.0: # TODO: tacking this on will mess with the design screen but prevents you from zooming in too close everywhere else. self.cameraMoving = 0 if self.enableMouseCamControl == 1: self.game.app.enableMouseCamControl() camera.setY(y) return Task.done else: camera.setY(y+self.getZoomSpeed(y, depth)) self.cameraMoving = 1 return Task.cont def getZoomSpeed(self, y, depth): """Make Camera zoom in faster if camera is further away""" diff = depth-y return diff/5.0 def zoomOutCamera(self): if camera.getY() >= self.zoomCameraOutDepth: self.game.app.disableMouseCamControl() taskMgr.add(self.zoomOutCameraTask, 'zoomOutCameraTask', extraArgs=[self.zoomCameraOutDepth]) self.runningTasks.append('zoomOutCameraTask') def zoomOutCameraAmount(self, amount): """Zoom out Camera a certain amount sepecified""" depth = camera.getY()-amount self.game.app.disableMouseCamControl() taskMgr.add(self.zoomOutCameraTask, 'zoomOutCameraTask', extraArgs=[depth]) self.runningTasks.append('zoomOutCameraTask') def zoomOutCameraTask(self, depth): """Zoom out the camera until its at 0 Depth""" y = camera.getY() if y - 0.1 <= depth: self.cameraMoving = 0 if self.enableMouseCamControl == 1: self.game.app.enableMouseCamControl() camera.setY(y) return Task.done else: camera.setY(y+self.getZoomSpeed(y, depth)) self.cameraMoving = 1 return Task.cont def panCameraLeft(self, amount): """Pan Camera""" pos = camera.getX()-amount self.game.app.disableMouseCamControl() taskMgr.add(self.panCameraLeftTask, 'panCameraLeftTask', extraArgs=[pos]) self.runningTasks.append('panCameraLeftTask') def panCameraLeftTask(self, pos): """pan the camera to new position""" x = camera.getX() if x <= pos: self.cameraMoving = 0 if self.enableMouseCamControl == 1: self.game.app.enableMouseCamControl() return Task.done else: camera.setX(x-self.panSpeed) self.cameraMoving = 1 return Task.cont def panCameraRight(self, amount): """Pan Camera""" pos = camera.getX()+amount self.game.app.disableMouseCamControl() taskMgr.add(self.panCameraRightTask, 'panCameraRightTask', extraArgs=[pos]) self.runningTasks.append('panCameraRightTask') def panCameraRightTask(self, pos): """pan the camera to new position""" x = camera.getX() if x >= pos: self.cameraMoving = 0 if self.enableMouseCamControl == 1: self.game.app.enableMouseCamControl() return Task.done else: camera.setX(x+self.panSpeed) self.cameraMoving = 1 return Task.cont def panCameraUp(self, amount): """Pan Camera""" pos = camera.getZ()+amount self.game.app.disableMouseCamControl() taskMgr.add(self.panCameraUpTask, 'panCameraUpTask', extraArgs=[pos]) self.runningTasks.append('panCameraUpTask') def panCameraUpTask(self, pos): """pan the camera to new position""" z = camera.getZ() if z >= pos: self.cameraMoving = 0 if self.enableMouseCamControl == 1: self.game.app.enableMouseCamControl() return Task.done else: camera.setZ(z+self.panSpeed) self.cameraMoving = 1 return Task.cont def panCameraDown(self, amount): """Pan Camera""" pos = camera.getZ()-amount self.game.app.disableMouseCamControl() taskMgr.add(self.panCameraDownTask, 'panCameraDownTask', extraArgs=[pos]) self.runningTasks.append('panCameraDownTask') def panCameraDownTask(self, pos): """pan the camera to new position""" z = camera.getZ() if z <= pos: self.cameraMoving = 0 if self.enableMouseCamControl == 1: self.game.app.enableMouseCamControl() return Task.done else: camera.setZ(z-self.panSpeed) self.cameraMoving = 1 return Task.cont def createSelector(self,type='select',speed=2.0): """Create selector for indication of selected objects""" self.selector = self.loadObject(type, scale=2, parent=render, transparency=True, pos=Point2(0,0), glow=1) self.selector.hide() ival = self.selector.hprInterval((speed), Vec3(0, 0, 360)) ival.loop() def createSelector2(self,type='select',speed=2.0): """Create selector2 for indication of secondary selected objects""" self.selector2 = self.loadObject(type, scale=2, parent=render, transparency=True, pos=Point2(0,0), glow=1) self.selector2.hide() ival = self.selector2.hprInterval((speed), Vec3(0, 0, 360)) ival.loop() def playSound(self, soundName): """Play a Sound based on soundName given, call app""" if globals.serverMode == 0: self.game.app.playSound(soundName) def askForHelp(self): """Ask the Server to analyse Player and provide help""" try: serverResult = self.game.server.askForHelp(self.game.authKey) if type(serverResult) == types.ListType: (message, self.game.myEmpire['help']) = serverResult self.modeMsgBox(message) else: self.modeMsgBox(serverResult) except: self.modeMsgBox('askForHelp->Connection to Server Lost') def assignSelector(self, myObj, scale): """create the Selector and assign to myObj at scale""" if self.selector == None: self.createSelector() self.selector.show() self.selector.setPos(myObj.getX(), myObj.getY(), myObj.getZ()) self.selector.setScale(scale) def assignSelector2(self, myObj, scale): """create the Selector2 and assign to myObj at scale""" if self.selector2 == None: self.createSelector2() self.selector2.show() self.selector2.setPos(myObj.getX(), myObj.getY(), myObj.getZ()) self.selector2.setScale(scale) ##def checkEndTurn(self): ##"""Do a Server Assesment of turn before ending the turn""" ##try: ##if 'EndTurn' in self.game.myEmpire['help']: ### turn not ended yet ##(serverResult, self.game.myEmpire['help']) = self.game.server.askForHelp(self.game.authKey) ##if serverResult == 'Server Assessment: WARNINGS:0, CRITICAL:0 (Check Mail for Assesment)': ### server assessment is good, end the turn without asking ##self.endMyTurn() ##else: ### server assessment has not come back without warnings ask for confirmation ##self.modeYesNoBox('%s - Do you still want to end your turn?' % serverResult, 'endturnYes', 'yesNoBoxNo') ##else: ### turn already ended, unend turn ##self.modeYesNoBox('Do you want to cancel your end turn?' , 'endturnYes', 'yesNoBoxNo') ##except: ##self.modeMsgBox('checkEndTurn->Connection to Server Lost, Login Again') def exitGame(self, doLogout=True): """Exit the game""" self.setEmpireDefaults(self.game.authKey) if doLogout: self.setLogout(self.game.authKey) self.alive = 0 self.game.app.quit() def getCreditInfoFromServer(self): self.getEmpireUpdate(['CR']) def refreshCredit(self): """Ask the Server for an updated Credit Info""" self.mainmenu.updateCR() def getEmpireUpdate(self, listAttr): """Ask the Server for updated Empire info""" try: serverResult = self.game.server.getEmpireUpdate(self.game.authKey, listAttr) if type(serverResult) == types.StringType: self.modeMsgBox(serverResult) else: for key, value in serverResult.iteritems(): self.game.myEmpire[key] = value except: self.modeMsgBox('getEmpireUpdate->Connection to Server Lost') def getMailUpdate(self): """Ask the Server for any updated mail""" try: myMailDict = self.game.myEmpire['mailBox'] serverResult = self.game.server.getMailUpdate(self.game.authKey, myMailDict.keys()) if type(serverResult) == types.StringType: self.modeMsgBox(serverResult) else: for key, value in serverResult.iteritems(): myMailDict[key] = value except: self.modeMsgBox('getMailUpdate->Connection to Server Lost') def getGalaxyUpdate(self, listAttr): """Ask the Server for updated Galaxy info""" try: serverResult = self.game.server.getGalaxyUpdate(listAttr, self.game.authKey) if type(serverResult) == types.StringType: self.modeMsgBox(serverResult) else: for key, value in serverResult.iteritems(): self.game.myGalaxy[key] = value except: self.modeMsgBox('getGalaxyUpdate->Connection to Server Lost') def getSystemUpdate(self, listAttr, systemID): """Ask the Server for updated System info""" try: serverResult = self.game.server.getSystemUpdate(listAttr, systemID, self.game.authKey) if type(serverResult) == types.StringType: self.modeMsgBox(serverResult) else: mySystemDict = self.game.allSystems[systemID] for key, value in serverResult.iteritems(): mySystemDict[key] = value except: self.modeMsgBox('getSystemUpdate->Connection to Server Lost') def enterMode(self): """Enter the mode.""" self.alive = 1 self.setShortcuts() def setShortcuts(self): """Set the default mode shortcuts""" self.game.app.accept('mouse1', self.onMouse1Down) self.game.app.accept('mouse3', self.onMouse2Down) self.game.app.accept('space', self.onSpaceBarClear) if self.enableMouseCamControl == 1: self.game.app.accept('wheel_up', self.onMouseWheelUp) self.game.app.accept('wheel_down', self.onMouseWheelDown) def exitMode(self): """Exit the mode""" self.removeMySims() self.removeAllGui() self.game.app.ignoreAll() self.removeAllTasks() self.alive = 0 def removeAllTasks(self): """Remove and Stop any tasks running""" for taskName in self.runningTasks: taskMgr.remove(taskName) def removeMySims(self): """Remove all sims in mode""" for sim in self.sims: try: sim.destroy() except: sim.removeNode() def removeAllGui(self): """Remove all DirectGUI""" for gui in self.gui: gui.destroy() def setPlanePickable(self, obj, dictName): """Set the plane model itself to be collideable with the mouse ray""" obj.sim.reparentTo(self.selectable) obj.sim.find('**/pPlane1').node().setIntoCollideMask(BitMask32.bit(1)) obj.sim.find('**/pPlane1').node().setTag(dictName, obj.id) def setSpherePickable(self, obj, dictName): """Set the sphere model itself to be collideable with the mouse ray""" obj.sim.reparentTo(self.selectable) obj.sim.find('**/pSphere1').node().setIntoCollideMask(BitMask32.bit(1)) obj.sim.find('**/pSphere1').node().setTag(dictName, obj.id) def setMySelector(self, x, y, z, scale): """Show selector if it is not in current position else return false""" selectorPos = (self.selector.getX(), self.selector.getY(), self.selector.getZ()) if selectorPos != (x,y,z): self.selector.setPos(x,y,z) self.selector.show() self.selector.setScale(scale) return 1 else: self.selector.setPos(-1,-1,-1) return 0 #self.enableScrollWheelZoom = 0 def getListButton(self, id, myScrolledList): """Return Button selected from buttonList gui based on id""" for button in myScrolledList.buttonsList: if button['extraArgs'][1] == id: return button def setMySelector2(self, x, y, z, scale): """Show selector2 if it is not in current position else return false""" selectorPos = (self.selector2.getX(), self.selector2.getY(), self.selector2.getZ()) if selectorPos != (x,y,z): self.selector2.setPos(x,y,z) self.selector2.show() self.selector2.setScale(scale) return 1 else: self.selector2.setPos(-1,-1,-1) return 0 #self.enableScrollWheelZoom = 0 def hideMySelector(self): """Hide the selector, move its position""" self.selector.setPos(-1,-1,-1) self.selector.hide() if self.selector2 != None: self.selector2.hide() def onMouse1Down(self): """Allow dynamic picking of an object within mode""" #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()) #Do the actual collision pass (Do it only on the selectable for #efficiency purposes) self.picker.traverse(self.selectable) 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() for selectable in self.selectTypes: name = self.pq.getEntry(0).getIntoNode().getTag(selectable) if name != '': self.clearAnyGui() mySelectedDict = getattr(self, selectable) mySelected = mySelectedDict[name] myMethod = getattr(self, '%sSelected' % selectable) if self.validateSelection(): myMethod(mySelected) break def onMouseWheelUp(self): """ zoom out """ if self.enableScrollWheelZoom: self.stopCameraTasks() self.zoomInCameraAmount(20.0) def onMouseWheelDown(self): """ zoom in """ if self.enableScrollWheelZoom: self.stopCameraTasks() self.zoomOutCameraAmount(20.0) def onMouse2Down(self): """clear""" self.onSpaceBarClear() def onSpaceBarClear(self): """Space bar should reset the view in the mode""" if self.validateSelection(): self.resetCamera() self.clearMouseSelection() self.zoomOutCamera() self.setShortcuts() self.enableScrollWheelZoom = 1 def clearMouseSelection(self): """Clear mouse selection before selecting something new""" pass def clearAnyGui(self): pass def update(self, interval): """update the mode, return the status, 0 means stop game""" return self.alive def setMyBackground(self): """Set the Background of mode""" base.setBackgroundColor(globals.colors['guiblue3']) def setEmpireDefaults(self, clientKey): """Read the defaults currently set and change them in the database""" try: # setup attributes to send to server defaults = ['viewIndustry', 'viewMilitary', 'viewResources', 'viewTradeRoutes'] d = {} for item in defaults: d[item] = self.game.myEmpire[item] serverResult = self.game.server.setEmpire(clientKey, d) if serverResult == 1: print 'Setup Empire Defaults Success' else: self.modeMsgBox(serverResult) except: self.modeMsgBox('SetEmpireDefaults->Connection to Server Lost, Login Again') def setEmpireValues(self, dValues): """Update Empire with d = key: empire attribute name, value = new value""" try: serverResult = self.game.server.setEmpire(self.game.authKey, dValues) if serverResult == 1: for key, value in dValues.iteritems(): self.game.myEmpire[key] = value print 'Empire Update Success' else: self.modeMsgBox(serverResult) except: self.modeMsgBox('setEmpireValues->Connection to Server Lost, Login Again') def setLogout(self, clientKey): """Send a Logout Request to the Server""" try: serverResult = self.game.server.logout(clientKey) if serverResult == 1: print 'Logout Successful, Exit Program' else: self.modeMsgBox(serverResult) except: self.modeMsgBox('setLogout->Connection to Server Lost, Login Again') def submitDesign(self, name): """Take Ship Design and submit it to Server for verification and storage""" (oldName, hullID, compDict, weaponDict) = self.myShipDesign.getMyDesign() dOrder = {'name':name, 'hullID':hullID, 'compDict':compDict, 'weaponDict':weaponDict} try: serverResult = self.game.server.addShipDesign(self.game.authKey, dOrder) if type(serverResult) == types.StringType: self.modeMsgBox(serverResult) else: # design has been accepted by server, retrieve design ID and add to client (ID,name) = serverResult self.game.shipDesigns[ID] = (name, hullID, compDict, weaponDict) self.getEmpireUpdate(['designsLeft']) except: self.modeMsgBox('submitDesign->Connection to Server Lost, Login Again') def destroyTempFrames(self): """Destroy any Temp Frames""" for frame in self.tempFrames: frame.destroy() self.tempFrames = [] def modeMsgBox(self, messageText): """Create a message for the user""" self.createMessage(messageText) def createMessage(self, text): """Create a new message for user""" myMessage = fadingtext.FadingText(self.guiMediaPath, text, self.messagePositions) self.messagePositions.append(myMessage.getMyPosition()) self.playSound('beep03') def writeToScreen(self, myText, x, z, scale=0.2, color='default', font=3, wordwrap=10): if color == 'default': color = Vec4(.1,.1,.8,.8) text = textonscreen.TextOnScreen(self.guiMediaPath, myText, scale,font=3) text.writeTextToScreen(x, self.depth, z, wordwrap=wordwrap) text.setColor(color) self.gui.append(text) def loadObject(self, tex=None, pos='default', depth=55, scale=1, transparency=True, parent='cam', model='plane', glow=0): if pos == 'default': pos = Point2(0,0) if parent == 'cam': parent = camera scaleX = 187.5 scaleZ = 117.1875 obj = loader.loadModelCopy('%s%s' % (self.guiMediaPath, model)) #default object uses the plane model if parent: obj.reparentTo(parent) #Everything is parented to the camera so #that it faces the screen obj.setPos(Point3(pos.getX(), depth, pos.getY())) #Set initial position obj.setSx(scaleX) obj.setSz(scaleZ) obj.setBin("unsorted", 0) #This tells Panda not to worry about the #order this is drawn in. (it prevents an #effect known as z-fighting) if transparency: obj.setTransparency(1) #All of our objects are trasnparent if tex: tex = loader.loadTexture('%s%s.png' % (self.guiMediaPath, tex)) #Load the texture obj.setTexture(tex, 1) #Set the texture self.sims.append(obj) obj.setShaderInput('glow',Vec4(glow,0,0,0),glow) return obj def onEntryFocus(self): """When a text Entry is in focus disable all shortcut keys""" for gui in self.gui: if gui.__module__ in self.entryFocusList: gui.ignoreShortcuts() def onEntryOutFocus(self): """When an text Entry is out of focus enable all shortcut keys""" for gui in self.gui: if gui.__module__ in self.entryFocusList: gui.setShortcuts()
class World(DirectObject): def __init__(self): self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "shoot":0} base.win.setClearColor(Vec4(0,0,0,1)) # Post the instructions self.inst6 = addInstructions(0.95, "Mad Max's Revenge!") self.inst1 = addInstructions(0.90, "[ESC]: Quit") self.inst2 = addInstructions(0.85, "[a]: Left Turn") self.inst3 = addInstructions(0.80, "[d]: Right Turn") self.inst4 = addInstructions(0.75, "[w]: Drive Forward") self.inst4 = addInstructions(0.70, "[s]: Reverse") self.inst5 = addInstructions(0.65, "[mouse]: Fire Rocket") # Set up the environment # # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("Assets/Models/env") #models/environment self.environ.reparentTo(render) self.environ.setPos(0,0,0) self.sky = loader.loadModel("Assets/Models/sky") #models/environment self.sky.reparentTo(render) self.sky.setPos(0,0,0) # Create the main character, player playerStartPos = Point3(8,14,1) #self.environ.find("**/start_point").getPos() enemyStartPos = Point3(-7,-8,1) #self.environ.find("**/start_point").getPos() #~ print enemyStartPos enemyStartPos.addX(1.0) enemyStartPos.addY(1.0) #~ print enemyStartPos self.player = Actor("Assets/Models/player_model", {"drive":"Assets/Models/player_drive", "fire":"Assets/Models/player_turret", "drivefire":"Assets/Models/player_both"}) self.player.reparentTo(render) self.player.setScale(0.1) self.player.setPos(playerStartPos) #~ self.playerdrive=self.player.actorInterval("drive") #~ self.playerfire=self.player.actoraaaaaaaInterval("fire") #~ self.playerdrivefire=self.player.actorInterval("drivefire") # Create the enemy, Enemy self.enemy = Actor("Assets/Models/enemy_model", {"drive":"Assets/Models/enemy_drive", "fire":"Assets/Models/enemy_turret", "drivefire":"Assets/Models/enemy_both"}) self.enemy.reparentTo(render) self.enemy.setScale(0.1) tex = loader.loadTexture("Assets/Models/cartexture1.png") self.enemy.setTexture(tex, 1) self.enemy.setPos(enemyStartPos) self.enemyrockettiming = globalClock.getFrameTime() #print self.enemy.getCurrentAnim() #print self.enemy.getCurrentAnim() #~ self.enemydrive=self.enemy.actorInterval("drive") #~ self.enemyfire=self.enemy.actorInterval("fire") #~ self.enemydrivefire=self.enemy.actorInterval("drivefire") self.music = loader.loadMusic("Assets/Sound/music.mp3") SoundInterval(self.music).loop() audio3d.attachSoundToObject(EnemyRunning, self.enemy) audio3d.attachSoundToObject(EnemyIdling, self.enemy) backward = self.enemy.getNetTransform().getMat().getRow3(1) backward.setZ(0) backward.normalize() #self.enemy.setPos(self.enemy.getPos() - backward*(50)) #Set up the lighting self.playerleftlight=self.player.attachNewNode(Spotlight("playerheadleft")) self.playerleftlight.node().setColor(Vec4(0.75, 0.75, 0.75, 1)) self.playerleftlight.node().setLens( PerspectiveLens() ) self.playerleftlight.node().getLens().setFov( 50, 50) self.playerleftlight.node().setAttenuation( Vec3( 0.1, 0.005, 0.0 ) ) self.playerleftlight.node().setExponent( 60.0 ) self.playerleftlight.setPos(-1, -0.1, 1.5) self.playerleftlight.setHpr(180, -10, 0) render.setLight(self.playerleftlight) self.playerrightlight=self.player.attachNewNode(Spotlight("playerheadright")) self.playerrightlight.node().setColor(Vec4(0.75, 0.75, 0.75, 1)) self.playerrightlight.node().setLens( PerspectiveLens() ) self.playerrightlight.node().getLens().setFov( 50, 50) self.playerrightlight.node().setAttenuation( Vec3( 0.1, 0.005, 0.0 ) ) self.playerrightlight.node().setExponent( 60.0 ) self.playerrightlight.setPos(1, -0.1, 1.5) self.playerrightlight.setHpr(180, -10, 0) render.setLight(self.playerrightlight) self.playerlightson=1 self.enemyleftlight=self.enemy.attachNewNode(Spotlight("enemyheadleft")) self.enemyleftlight.node().setColor(Vec4(0.75, 0.75, 0.75, 1)) self.enemyleftlight.node().setLens( PerspectiveLens() ) self.enemyleftlight.node().getLens().setFov( 50, 50) self.enemyleftlight.node().setAttenuation( Vec3( 0.1, 0.005, 0.0 ) ) self.enemyleftlight.node().setExponent( 60.0 ) self.enemyleftlight.setPos(-1, -0.1, 1.5) self.enemyleftlight.setHpr(180, -10, 0) render.setLight(self.enemyleftlight) self.enemyrightlight=self.enemy.attachNewNode(Spotlight("enemyheadright")) self.enemyrightlight.node().setColor(Vec4(0.75, 0.75, 0.75, 1)) self.enemyrightlight.node().setLens( PerspectiveLens() ) self.enemyrightlight.node().getLens().setFov( 50, 50) self.enemyrightlight.node().setAttenuation( Vec3( 0.1, 0.005, 0.0 ) ) self.enemyrightlight.node().setExponent( 60.0 ) self.enemyrightlight.setPos(1, -0.1, 1.5) self.enemyrightlight.setHpr(180, -10, 0) render.setLight(self.enemyrightlight) self.enemylightson=1 self.spotlight=camera.attachNewNode(PointLight("spotlight")) #self.spotlight.setPos(0, 3, 0.5) #self.spotlight.setHpr(0, 0, 0) self.spotlight.node().setColor(Vec4(1, 1, 1, 1)) #self.spotlight.node().setLens( PerspectiveLens() ) #self.spotlight.node().getLens().setFov( 180, 120) self.spotlight.node().setAttenuation( Vec3( 1, 0, 0.05 )) #self.spotlight.node().setExponent( 60.0 ) render.setLight(self.spotlight) self.playerlight=self.player.attachNewNode(PointLight("spotlight")) self.playerlight.node().setColor(Vec4(1, 1, 1, 1)) #self.spotlight.node().setLens( PerspectiveLens() ) #self.spotlight.node().getLens().setFov( 180, 120) self.playerlight.node().setAttenuation( Vec3( 1, 0, 0.05 )) #self.spotlight.node().setExponent( 60.0 ) render.setLight(self.playerlight) self.ambientlight=self.sky.attachNewNode(AmbientLight("ambientLight")) self.ambientlight.node().setColor(Vec4(1, 1, 1, 1)) self.sky.setLight(self.ambientlight) # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("a", self.setKey, ["left",1]) self.accept("d", self.setKey, ["right",1]) self.accept("w", self.setKey, ["forward",1]) self.accept("s", self.setKey, ["backward",1]) self.accept("a-up", self.setKey, ["left",0]) self.accept("d-up", self.setKey, ["right",0]) self.accept("w-up", self.setKey, ["forward",0]) self.accept("s-up", self.setKey, ["backward",0]) self.accept("l", self.playerLights,[]) self.accept("mouse1", self.setKey, ["shoot", 1]) self.accept("mouse1-up", self.setKey, ["shoot", 0]) #self.shootRocketshootRocket taskMgr.add(self.playerMove,"moveTask") taskMgr.add(self.enemyMove,"moveTask") taskMgr.add(self.shoot,"shootTask") taskMgr.add(self.rocketCollision,"rocketCollision") # Game state variables self.prevtime = 0 self.isMoving = False self.prevShotTime = 0 self.prevEnemyMoveTime = 0 # Set up the camera base.disableMouse() base.camera.setPos(self.player.getX(),self.player.getY()+10,2) # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above player's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.playerGroundRay = CollisionRay() self.playerGroundRay.setOrigin(0,0,1000) self.playerGroundRay.setDirection(0,0,-1) self.playerGroundCol = CollisionNode('playerRay') self.playerGroundCol.addSolid(self.playerGroundRay) self.playerGroundCol.setFromCollideMask(BitMask32.bit(3)) self.playerGroundCol.setIntoCollideMask(BitMask32.allOff()) self.playerGroundColNp = self.player.attachNewNode(self.playerGroundCol) self.playerGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,1000) self.camGroundRay.setDirection(0,0,-1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(3)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays #self.playerGroundColNp.show() #self.camGroundColNp.show() #Uncomment this line to show a visual representation of the #collisions occuring #self.cTrav.showCollisions(render) #Code for Enemy player self.enemyGroundRay = CollisionRay() self.enemyGroundRay.setOrigin(0,0,1000) self.enemyGroundRay.setDirection(0,0,-1) self.enemyGroundCol = CollisionNode('enemyRay') self.enemyGroundCol.addSolid(self.enemyGroundRay) self.enemyGroundCol.setFromCollideMask(BitMask32.bit(3)) self.enemyGroundCol.setIntoCollideMask(BitMask32.allOff()) self.enemyGroundColNp = self.enemy.attachNewNode(self.enemyGroundCol) self.enemyGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.enemyGroundColNp, self.enemyGroundHandler) self.cRocketHandler = CollisionHandlerQueue() self.worldEdge = CollisionInvSphere(0, 0, 0, 50) cNode = CollisionNode("worldEdge") cNode.addSolid(self.worldEdge) cNode.setFromCollideMask(BitMask32.allOff()) cNode.setIntoCollideMask(BitMask32.allOn()) self.worldEdgeNp=self.environ.attachNewNode(cNode) #self.cTrav.addCollider(self.worldEdgeNp, self.cRocketHandler) #cNP = render.attachNewNode(cNode) cNode2 = CollisionNode("wall") cNode2.addSolid(CollisionPlane(Plane(Vec3(-1,0,0), Point3(22.5,0,0)))) cNode2.addSolid(CollisionPlane(Plane(Vec3(1,0,0), Point3(-22.5,0,0)))) cNode2.addSolid(CollisionPlane(Plane(Vec3(0,-1,0), Point3(0,22.5,0)))) cNode2.addSolid(CollisionPlane(Plane(Vec3(0,1,0), Point3(0,-22.5,0)))) cNode2.setFromCollideMask(BitMask32.allOff()) cNode2.setIntoCollideMask(BitMask32.allOn()) cNP2=self.environ.attachNewNode(cNode2) 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.allOn()) 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.playerrocket = None self.enemyrocket = None self.enemyTurn = 0 self.enemyDestAng = 180 self.enemyHp = 3 self.playerHp = 3 #Collisions self.setupCollisions() self.playermoving = False #setup hud self.drawHud() def drawHud(self): #Player OnscreenText(text="Player Health", style=1, fg=(1,1,1,1), pos=(0.85, 0.9), align=TextNode.ALeft, scale = .08) self.playerHealthImg = OnscreenImage(image = 'Assets/Images/healthFull.png', pos = (1.05, 0, .84), scale = .12) self.playerHealthImg.setTransparency(TransparencyAttrib.MAlpha) #Enemy OnscreenText(text="Enemy Health", style=1, fg=(1,1,1,1), pos=(0.85, 0.7), align=TextNode.ALeft, scale = .08) self.enemyHealthImg = OnscreenImage(image = 'Assets/Images/healthFull.png', pos = (1.05, 0, .64), scale = .12) self.enemyHealthImg.setTransparency(TransparencyAttrib.MAlpha) def updateGui(self): #player bar if self.playerHp == 2: self.playerHealthImg.setImage('Assets/Images/healthMedium.png') self.playerHealthImg.setTransparency(TransparencyAttrib.MAlpha) elif self.playerHp == 1: self.playerHealthImg.setImage('Assets/Images/healthLow.png') self.playerHealthImg.setTransparency(TransparencyAttrib.MAlpha) #enemy bar if self.enemyHp == 2: self.enemyHealthImg.setImage('Assets/Images/healthMedium.png') self.enemyHealthImg.setTransparency(TransparencyAttrib.MAlpha) elif self.enemyHp == 1: self.enemyHealthImg.setImage('Assets/Images/healthLow.png') self.enemyHealthImg.setTransparency(TransparencyAttrib.MAlpha) def setupCollisions(self): #player sphere cPlayerSphere = CollisionSphere(Point3(0, 0, .5), 10) cPlayerNode = CollisionNode("Player") cPlayerNode.addSolid(cPlayerSphere) cPlayerNode.setFromCollideMask(BitMask32.bit(4)) cPlayerNode.setIntoCollideMask(BitMask32(20)) cPlayerNP = self.player.attachNewNode(cPlayerNode) self.cTrav.addCollider(cPlayerNP, self.playerGroundHandler) #self.cTrav.addCollider(cPlayerNP, self.cRocketHandler) #cPlayerNP.show() #enemy sphere cEnemySphere = CollisionSphere(Point3(0, 0, .5), 10) cEnemyNode = CollisionNode("Enemy") cEnemyNode.addSolid(cEnemySphere) cEnemyNode.setFromCollideMask(BitMask32.bit(4)) cEnemyNode.setIntoCollideMask(BitMask32(18)) cEnemyNP = self.enemy.attachNewNode(cEnemyNode) self.cTrav.addCollider(cEnemyNP, self.enemyGroundHandler) #self.cTrav.addCollider(cEnemyNP, self.cRocketHandler) #cEnemyNP.show() def rocketCollision(self, task): """Check for rocket collisions with players and objects""" toRemove = [] for i in range(self.cRocketHandler.getNumEntries()): entry = self.cRocketHandler.getEntry(i) #~ print entry if entry.getFromNode().getName() == "PlayerRocket" and entry.getIntoNode().getName() == "Enemy": self.enemyHp -= 1 self.updateGui() if self.enemyHp == 0: print "Victory!" OnscreenText(text="Victory!", style=2, fg=(0,1,0,1), pos=(-0.6, 0), align=TextNode.ALeft, scale = .5, shadow=(0,0,0,0)) self.playerHp += 5 #LerpFunc(end_game, fromData = 0, toData = 1, duration = 3.0, #blendType = 'noBlend', extraArgs = [], name = None) taskMgr.remove("moveTask") taskMgr.remove("shootTask") #print "GAME OVER, YOU WIN" #sys.exit(0) elif entry.getFromNode().getName() == "EnemyRocket" and entry.getIntoNode().getName() == "Player": self.playerHp -= 1 self.updateGui() if self.playerHp == 0: #~ print "GAME OVER, YOU LOSE" OnscreenText(text="Failure!", style=2, fg=(1,0,0,1), pos=(-0.6, 0), align=TextNode.ALeft, scale = .5, shadow=(0,0,0,0)) self.enemyHp += 5 taskMgr.remove("moveTask") taskMgr.remove("shootTask") #Add to remove list if entry.getFromNodePath() not in toRemove: toRemove.append(entry.getFromNodePath()) #remove for np in toRemove: if np.getNode(0).getName() == "PlayerRocket": if self.playerrocket: self.playerrocket.kill_light() #~ print "BOOM!, PLAYER ROCKET EXPLODED" BoomSound.play() RocketFire.stop() Explosion.Explosion(self.playerrocket.rocket.getPos(), render) self.playerrocket = None np.getParent().remove() else: if self.enemyrocket: self.enemyrocket.kill_light() #~ print "BOOM!, ENEMY ROCKET EXPLODED" BoomSound.play() RocketFire.stop() Explosion.Explosion(self.enemyrocket.rocket.getPos(), render) self.enemyrocket = None np.getParent().remove() self.cRocketHandler.clearEntries() return Task.cont def shootPlayerRocket(self): """Shoot a player rocket""" #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()) #Do the actual collision pass pickerpoint=Point3(0,0,0) self.picker.traverse(render) for i in range(self.pq.getNumEntries()): entry = self.pq.getEntry(i) if entry.getFromNode().getName() == "mouseRay" and entry.getIntoNode().getName()=="terrain": pickerpoint=entry.getSurfacePoint(render) direction=pickerpoint-Point3(self.player.getX(), self.player.getY(), self.player.getZ()+0.5) #~ if self.playerrocket is None: #~ angle = math.radians(self.player.getH()) playerpos=self.player.getPos() self.playerrocket = Rocket.Rocket(Point3(playerpos.getX(), playerpos.getY(), playerpos.getZ()+0.5), direction, "PlayerRocket", render) self.playerrocket.setupCollision(self.cTrav, self.cRocketHandler) RocketFire.play() if self.player.getCurrentAnim()=="drive": self.player.play("drivefire") else: self.player.play("fire") def shootEnemyRocket(self): """Shoot a enemy rocket""" if not (self.enemyrocket) and self.enemyrockettiming <= globalClock.getFrameTime() : #~ angle = math.radians(self.enemy.getH()) #~ self.enemyrocket = Rocket.Rocket(self.enemy.getPos(), angle, "EnemyRocket", render) #~ self.enemyrocket.setupCollision(self.cTrav, self.cRocketHandler) direction = self.player.getPos() - self.enemy.getPos() enemyPos = self.enemy.getPos() self.enemyrocket = Rocket.Rocket(enemyPos + Point3(0,0,.5),direction,"EnemyRocket",render) self.enemyrocket.setupCollision(self.cTrav, self.cRocketHandler) RocketFire.play() self.enemy.play("drivefire") self.enemyrockettiming = globalClock.getFrameTime() + 2.0 #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value def shoot(self, task): elapsed = task.time - self.prevShotTime if(self.keyMap["shoot"]!=0 and elapsed > 1): self.shootPlayerRocket() self.prevShotTime = task.time return Task.cont def playerLights(self): if self.playerlightson: self.playerleftlight.node().setColor(Vec4(0,0,0,1)) self.playerrightlight.node().setColor(Vec4(0,0,0,1)) self.playerlightson=0 else: self.playerleftlight.node().setColor(Vec4(0.75,0.75,0.75,1)) self.playerrightlight.node().setColor(Vec4(0.75,0.75,0.75,1)) self.playerlightson=1 def enemyLights(self): if self.enemylightson: self.enemyleftlight.node().setColor(Vec4(0,0,0,1)) self.enemyrightlight.node().setColor(Vec4(0,0,0,1)) self.enemylightson=0 else: self.enemyleftlight.node().setColor(Vec4(0.75,0.75,0.75,1)) self.enemyrightlight.node().setColor(Vec4(0.75,0.75,0.75,1)) self.enemylightson=1 def enemyMove(self, task): elapsed = task.time - self.prevEnemyMoveTime startpos = self.enemy.getPos() #Calculate distance to the enemy distvec = self.player.getPos() - self.enemy.getPos() distvec.setZ(0) dist = distvec.length() backward = self.enemy.getNetTransform().getMat().getRow3(1) backward.setZ(0) backward.normalize() #Drive! if self.enemy.getCurrentAnim() is None: self.enemy.loop("drive") #Find the vector from the enemy to the player, then find the angle of that vector vec = self.enemy.getPos() - self.player.getPos() angle = math.degrees(math.atan2(vec.getX(), vec.getY())) #Find the angle left to turn according to the enemy's current angle angleToPlayer = (-self.enemy.getH() - angle) % 360 #Fire rocket if within 60 degree arc of player #~ print angleToPlayer if angleToPlayer < 30 or angleToPlayer > 330: self.shootEnemyRocket() #AI control code starts here #enemyTurn is zero for heading straight, -1 to turn full left, +1 to turn full right #Turning rate is currently maxed at 100 degrees per second #drivedir is for forward (1) or backward (-1) #Wall avoidance stuff enemyTurn=0 myh=self.player.getH()%360 print myh if abs(self.enemy.getPos().getX())>19 or abs(self.enemy.getPos().getX())>19: drivedir=-1.0 else: drivedir=1.0 if self.playerrocket: playerpos=self.player.getPos() if playerpos.getX()>12.5 and (myh<90 or myh>270): self.enemyTurn = -(0.5+0.05*(self.enemy.getX()-12.5))*sign(myh-180) print 1 elif playerpos.getX()<12.5 and not (myh<90 or myh>270): self.enemyTurn = -(0.5+0.05*(12.5-self.enemy.getX()))*sign(myh-180) print 2 elif playerpos.getY()>12.5 and myh<180: self.enemyTurn = -(0.5+0.05*(self.enemy.getY()-12.5))*sign(myh-90) print 3 elif playerpos.getY()<12.5 and myh>180: self.enemyTurn = -(0.5+0.05*(12.5-self.enemy.getY()))*sign(myh-270) print 4 elif self.enemy.getPos().getX()>12.5 and (myh<90 or myh>270): self.enemyTurn = -(0.5+0.05*(self.enemy.getX()-12.5))*sign(myh-180) print 5 elif self.enemy.getPos().getX()<-12.5 and not (myh<90 or myh>270): self.enemyTurn = -(0.5+0.05*(12.5-self.enemy.getX()))*sign(myh-180) print 6 elif self.enemy.getPos().getY()>12.5 and myh<180: self.enemyTurn = -(0.5+0.05*(self.enemy.getY()-12.5))*sign(myh-90) print 7 elif self.enemy.getPos().getY()<-12.5 and myh>180: self.enemyTurn = -(0.5+0.05*(12.5-self.enemy.getY()))*sign(myh-270) print 8 elif not(math.fabs(self.enemyDestAng - angleToPlayer) > 3 and math.fabs(self.enemyDestAng - angleToPlayer) < 357): print 9 self.enemyTurn = 0 else: print 10 if dist > 5: self.enemyDestAng = 0 if angleToPlayer > 1 and angleToPlayer <= 180: #Turn left self.enemyTurn = -0.5 elif angleToPlayer > 180 and angleToPlayer < 359: #Turn right self.enemyTurn = 0.5 elif dist < 5: self.enemyDestAng = 180 if angleToPlayer >= 0 and angleToPlayer < 179: #Turn left self.enemyTurn = 0.5 elif angleToPlayer > 181 and angleToPlayer < 360: #Turn right self.enemyTurn = -0.5 #Replace later #drivedir=1.0 #End of AI code #Enemy always tries to move forward, regardless of where the player is self.enemy.setPos(self.enemy.getPos() - backward*(drivedir*elapsed*5)) self.enemy.setH(self.enemy.getH() - elapsed *100.0*self.enemyTurn) EnemyRunning.play() self.cTrav.traverse(render) entries = [] terrain = [] for i in range(self.enemyGroundHandler.getNumEntries()): entry = self.enemyGroundHandler.getEntry(i) if entry.getFromNode().getName() == "enemyRay": terrain.append(entry) elif entry.getFromNode().getName() == "Enemy" and entry.getIntoNode().getName() != "terrain": entries.append(entry) terrain.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0): self.enemy.setPos(startpos) if (len(terrain)>0) and (terrain[0].getIntoNode().getName() == "terrain"): self.enemy.setZ(terrain[0].getSurfacePoint(render).getZ()+.5) else: self.enemy.setPos(startpos) # Store the task time and continue. self.prevEnemyMoveTime = task.time return Task.cont # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def playerMove(self, task): elapsed = task.time - self.prevtime base.camera.lookAt(self.player) camright = base.camera.getNetTransform().getMat().getRow3(0) camright.normalize() # save player's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.player.getPos() # If a move-key is pressed, move player in the specified direction. if ((self.keyMap["left"]!=0) & (self.keyMap["forward"]!=0)): self.player.setH(self.player.getH() + elapsed*50) Idling.stop() Running.play() self.playermoving = True elif((self.keyMap["left"]!=0) & (self.keyMap["backward"]!=0)): self.player.setH(self.player.getH() - elapsed*50) Idling.stop() Running.play() self.playermoving = True if ((self.keyMap["right"]!=0) & (self.keyMap["forward"]!=0)): self.player.setH(self.player.getH() - elapsed*50) Idling.stop() Running.play() self.playermoving = True elif ((self.keyMap["right"]!=0) & (self.keyMap["backward"]!=0)): self.player.setH(self.player.getH() + elapsed*50) Idling.stop() Running.play() self.playermoving = True if (self.keyMap["forward"]!=0): backward = self.player.getNetTransform().getMat().getRow3(1) backward.setZ(0) backward.normalize() self.player.setPos(self.player.getPos() - backward*(elapsed*5)) Running.play() Idling.stop() self.playermoving = True if (self.keyMap["backward"]!=0): backward = self.player.getNetTransform().getMat().getRow3(1) backward.setZ(0) backward.normalize() self.player.setPos(self.player.getPos() + backward*(elapsed*5)) Idling.stop() Running.play() self.playermoving = True if (self.keyMap["backward"]==0 and self.keyMap["forward"]==0 and self.keyMap["left"]==0 and self.keyMap["right"]==0): Running.stop() Idling.play() self.playermoving = False if self.player.getCurrentAnim()=="drive": self.player.stop() #print "STOP MOVING" #DRIVE! if self.player.getCurrentAnim() is None and self.playermoving: self.player.loop("drive") #print "DRIVE ON!" dist = 10.0 angle = math.radians(self.player.getH()) + math.pi dx = dist * math.sin(angle) dy = dist * -math.cos(angle) dest = Point3(self.player.getX() + dx, self.player.getY() + dy, self.player.getZ()+1) base.camera.setPos(dest) # If player is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0): if self.isMoving is False: #self.player.loop("run") self.isMoving = True else: if self.isMoving: #self.player.stop() #self.player.pose("walk",5) self.isMoving = False # If the camera is too far from player, move it closer. # If the camera is too close to player, move it farther. camvec = self.player.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 20.0): base.camera.setPos(base.camera.getPos() + camvec*(camdist-20)) camdist = 20.0 if (camdist < 10.0): base.camera.setPos(base.camera.getPos() - camvec*(10-camdist)) camdist = 10.0 # Now check for collisions. self.cTrav.traverse(render) # Adjust player's Z coordinate. If player's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. terrain = [] entries = [] for i in range(self.playerGroundHandler.getNumEntries()): entry = self.playerGroundHandler.getEntry(i) if entry.getFromNode().getName() == "playerRay": terrain.append(entry) elif entry.getFromNode().getName() == "Player" and entry.getIntoNode().getName() != "terrain": entries.append(entry) terrain.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0): self.player.setPos(startpos) elif (len(terrain)>0) and (terrain[0].getIntoNode().getName() == "terrain"): self.player.setZ(terrain[0].getSurfacePoint(render).getZ()+.5) else: self.player.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above player, whichever is greater. entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+ 1.5) if (base.camera.getZ() < self.player.getZ() + 2.5): base.camera.setZ(self.player.getZ() + 2.5) # The camera should look in player's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above player's head. self.floater.setPos(self.player.getPos()) self.floater.setZ(self.floater.getZ()+1) base.camera.lookAt(self.floater) # Store the task time and continue. self.prevtime = task.time return Task.cont
class cameraCollisionClass: def __init__( self ): self.collisionCheckSetup() def collisionCheckSetup( self ): print "setting up collision check" #No we create a ray to start above the ball and cast down. This is to #Determine the height the ball should be at and the angle the floor is #tilting. We could have used the sphere around the ball itself, but it #would not be as reliable self.cameraGroundRay = CollisionRay() #Create the ray self.cameraGroundRay.setOrigin(0,0,0.0) #Set its origin self.cameraGroundRay.setDirection(0,0,-1.0) #And its direction #Collision solids go in CollisionNode self.cameraGroundCol = CollisionNode('cameraGroundRay') #Create and name the node self.cameraGroundCol.addSolid(self.cameraGroundRay) #Add the ray self.cameraGroundCol.setFromCollideMask(bitMaskOr([GROUND])) #Set its bitmasks self.cameraGroundCol.setIntoCollideMask(bitMaskOr([])) #Attach the node to the ballRoot so that the ray is relative to the ball #(it will always be 10 feet over the ball and point down) # self.cameraGroundColNp = base.camera.attachNewNode(self.cameraGroundCol) ### the ground controller is allways looking down NOT ACTIVE self.horizontalCameraNode = base.camera.attachNewNode('horizontalCameraNode') self.horizontalCameraNode.reparentTo( base.camera ) self.cameraGroundColNp = self.horizontalCameraNode.attachNewNode(self.cameraGroundCol) #Uncomment this line to see the ray #self.cameraGroundColNp.show() ''' # the camera forward rays look in the direction of the camera self.cameraFrontRay = CollisionRay() #Create the ray self.cameraFrontRay.setOrigin (0,-1,0) #Set its origin self.cameraFrontRay.setDirection(0, 5,0) #And its direction self.cameraFrontCol = CollisionNode('cameraFrontRay') #Create and name the node self.cameraFrontCol.addSolid(self.cameraFrontRay) #Add the ray self.cameraFrontCol.setFromCollideMask(bitMaskOr([WALLS])) #Set its bitmasks self.cameraFrontCol.setIntoCollideMask(bitMaskOr([])) self.cameraFrontColNp = base.camera.attachNewNode(self.cameraFrontCol) #self.cameraFrontColNp.show() self.cameraBackRay = CollisionRay() #Create the ray self.cameraBackRay.setOrigin (0, 1,0) #Set its origin self.cameraBackRay.setDirection(0,-5,0) #And its direction self.cameraBackCol = CollisionNode('cameraBackRay') #Create and name the node self.cameraBackCol.addSolid(self.cameraBackRay) #Add the ray self.cameraBackCol.setFromCollideMask(bitMaskOr([WALLS])) #Set its bitmasks self.cameraBackCol.setIntoCollideMask(bitMaskOr([])) self.cameraBackColNp = base.camera.attachNewNode(self.cameraBackCol) #self.cameraBackColNp.show() # the camera left/right rays self.cameraLeftRay = CollisionRay() #Create the ray self.cameraLeftRay.setOrigin (-1,0,0) #Set its origin self.cameraLeftRay.setDirection( 5,0,0) #And its direction self.cameraLeftCol = CollisionNode('cameraLeftRay') #Create and name the node self.cameraLeftCol.addSolid(self.cameraLeftRay) #Add the ray self.cameraLeftCol.setFromCollideMask(bitMaskOr([WALLS])) #Set its bitmasks self.cameraLeftCol.setIntoCollideMask(bitMaskOr([])) self.cameraLeftColNp = base.camera.attachNewNode(self.cameraLeftCol) #self.cameraLeftColNp.show() self.cameraRightRay = CollisionRay() #Create the ray self.cameraRightRay.setOrigin ( 1,0,0) #Set its origin self.cameraRightRay.setDirection(-5,0,0) #And its direction self.cameraRightCol = CollisionNode('cameraRightRay') #Create and name the node self.cameraRightCol.addSolid(self.cameraRightRay) #Add the ray self.cameraRightCol.setFromCollideMask(bitMaskOr([WALLS])) #Set its bitmasks self.cameraRightCol.setIntoCollideMask(bitMaskOr([])) self.cameraRightColNp = base.camera.attachNewNode(self.cameraRightCol) #self.cameraRightColNp.show() ''' #Finally, we create a CollisionTraverser. CollisionTraversers are what #do the job of calculating collisions self.cTrav = CollisionTraverser() #Collision traverservs tell collision handlers about collisions, and then #the handler decides what to do with the information. We are using a #CollisionHandlerQueue, which simply creates a list of all of the #collisions in a given pass. There are more sophisticated handlers like #one that sends events and another that tries to keep collided objects #apart, but the results are often better with a simple queue self.cGroundHandler = CollisionHandlerQueue() self.cWallHandler = CollisionHandlerQueue() #Now we add the collision nodes that can create a collision to the #traverser. The traverser will compare these to all others nodes in the #scene. There is a limit of 32 CollisionNodes per traverser #We add the collider, and the handler to use as a pair #self.cTrav.addCollider(self.cameraBallSphere, self.cHandler) self.cTrav.addCollider(self.cameraGroundColNp, self.cGroundHandler) ''' self.cTrav.addCollider(self.cameraBackColNp, self.cWallHandler) self.cTrav.addCollider(self.cameraFrontColNp, self.cWallHandler) self.cTrav.addCollider(self.cameraLeftColNp, self.cWallHandler) self.cTrav.addCollider(self.cameraRightColNp, self.cWallHandler) ''' # we dont want this to be automatically executed #base.cTrav = self.cTrav #Collision traversers have a built in tool to help visualize collisions. #Uncomment the next line to see it. #self.cTrav.showCollisions(render) #self.cTrav.traverse( render ) # add a task to check for collisions taskMgr.add(self.collisionCheckTask, 'collisionCheckTask') def collisionCheckTask( self, task ): # make the parent of the groundCollideHandler be horizontal relative to render self.horizontalCameraNode.setHpr( render, Vec3(0,0,0)) self.cTrav.traverse( render ) #The collision handler collects the collisions. We dispatch which function #to handle the collision based on the name of what was collided into for i in range(self.cGroundHandler.getNumEntries()): self.cGroundHandler.sortEntries() entry = self.cGroundHandler.getEntry(i) object = entry.getIntoNode() self.groundCollideHandler(entry) # stop after first one break for i in range(self.cWallHandler.getNumEntries()): self.cWallHandler.sortEntries() entry = self.cWallHandler.getEntry(i) object = entry.getIntoNode() self.wallCollideHandler(entry) # stop after first one break return Task.cont def groundCollideHandler( self, colEntry ): # get Z position of collision newZ = colEntry.getSurfacePoint(render).getZ() # set position node of camera above collision point base.camera.setZ(newZ+GROUNDDISTANCE) def wallCollideHandler( self, colEntry ): # get position of collision collisionPos = colEntry.getSurfacePoint(render) # get position of camera cameraPos = base.camera.getPos(render) # distance from collisionpoint to camera distance = collisionPos - cameraPos # length of the distance distanceLength = distance.length() # if distance to collision point smaller then defined if distanceLength < MINDISTANCEWALL: # move camera backwand to be at correct distance base.camera.setPos( base.camera.getPos() - (distance * (MINDISTANCEWALL - distanceLength)))
class World(DirectObject): def __init__(self): base.win.setClearColor(Vec4(0, 0, 0, 1)) # enable physics (and particle) engine self.throwMode = False self.freelook = False self.score = OnscreenText('0', pos=(-1.32, 0.9), fg=(1, 1, 1, 1), bg=(0, 0, 0, 0.5), scale=0.1, align=TextNode.ALeft) # Load the environment in which Eve will walk. Set its parent # to the render variable so that it is a top-lplayerl node. self.env = loader.loadModel('models/world/world.egg.pz') self.env.reparentTo(render) self.env.setPos(0, 0, 0) self.createCollisionHandlers() # Create an Actor instance for Eve. We also specify the animation # models that we want to use as a dictionary, where we can use to # keys to refer to the animations later on. The start point of Eve # is hardcoded in the world model somewhere, so we look that up. self.player = Eve('Eve', self, self.env.find('**/start_point').getPos()) #self.player.nodePath.setZ(self.player.nodePath.getZ() + 10) self.player.nodePath.reparentTo(render) # Create a floater object that always floats 2 units above Eve. # We make sure that it is attached to Eve by reparenting it to # Eve's object instance. self.floater = NodePath(PandaNode('floater')) self.floater.reparentTo(self.player.nodePath) self.floater.setZ(self.floater.getZ() + 2) # load baseball self.baseball = Baseball('baseball', self, self.player.nodePath.getPos()) self.baseball.nodePath.reparentTo(render) self.player.pickUpItem(self.baseball) # Load the panda bear self.panda = Panda('panda', self, self.player.nodePath.getPos()) self.panda.nodePath.reparentTo(render) # Disable controlling the camera using the mouse. Note that this does # not disable the mouse completely, it merely disables the camera # movement by mouse. base.disableMouse() self.hideMouseCursor() # Set the initial position for the camera as X, Y and Z values. base.camera.setPos(self.player.nodePath.getX(), self.player.nodePath.getY() + 10, 2) # Disable modifier button compound events. base.mouseWatcherNode.setModifierButtons(ModifierButtons()) base.buttonThrowers[0].node().setModifierButtons(ModifierButtons()) # Register any control callbacks. self.accept('escape', sys.exit) self.accept('d', self.dropItem) self.accept('f', self.toggleFullscreen) self.accept('space', self.enterThrowMode) self.accept('space-up', self.leaveThrowMode) # Also make sure that we can, at any time, request the state (pressed # or not) for these keys. self.keys = keys.KeyStateManager() self.keys.registerKeys({ 'arrow_left': 'left', 'arrow_right': 'right', 'arrow_up': 'forward', 'arrow_down': 'backward', 'shift': 'shift', 'r': 'reset' }) self.mouse = mouse.MousePointerManager(0) # Schedule the move method to be executed in the game's main loop. taskMgr.add(self.update, 'update') def hideMouseCursor(self): props = WindowProperties() props.setCursorHidden(True) base.win.requestProperties(props) def toggleFullscreen(self): props = WindowProperties() props.setFullscreen(not base.win.getProperties().getFullscreen()) base.win.requestProperties(props) def enableFreelook(self): self.freelook = True # Make sure we reset the MouseMovementManager's last known mouse position, # so we don't get a huge delta on the first attempt. self.mouse.reset() base.camera.setP(0) def disableFreelook(self): self.freelook = False def createCollisionHandlers(self): # Create a new collision traverser instance. We will use this to determine # if any collisions occurred after performing movement. self.cTrav = CollisionTraverser() camGroundRay = CollisionRay() camGroundRay.setOrigin(0, 0, 1000) camGroundRay.setDirection(0, 0, -1) camGroundCol = CollisionNode('camRay') camGroundCol.addSolid(camGroundRay) camGroundCol.setFromCollideMask(BitMask32.bit(0)) camGroundCol.setIntoCollideMask(BitMask32.allOff()) camGroundColNp = base.camera.attachNewNode(camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(camGroundColNp, self.camGroundHandler) # register the collision pusher self.pusher = CollisionHandlerPusher() # register collision event pattern names self.pusher.addInPattern('col-%fn-into') def update(self, task): # get the time passed since the last frame timePassed = globalClock.getDt() # update player self.player.forceMove(timePassed) self.panda.forceMove(timePassed) # Do collision detection. This iterates all the collider nodes self.cTrav.traverse(render) # check if player's move is valid self.player.validateMove() self.panda.validateMove() # Set the initial position for the camera as X, Y and Z values. base.camera.setPos(self.player.nodePath.getPos()) if self.throwMode: # Position the camera a bit above the ground. base.camera.setZ(base.camera, 1.5) if self.freelook: mx, my = self.mouse.getDelta() h = -mx * 0.1 p = -my * 0.1 base.camera.setHpr(base.camera, h, p, 0) self.player.nodePath.setH(self.player.nodePath, h) else: # Set the heading, pitch and roll of the camera. base.camera.setHpr(self.player.nodePath.getHpr()) else: # Set the heading, pitch and roll of the camera. base.camera.setHpr(self.player.nodePath.getHpr()) # Position the camera somewhat behind the player. base.camera.setY(base.camera, 10) # Make sure the camera is above the ground. camGroundEntry = self.getGroundEntry(self.camGroundHandler) if camGroundEntry is not None and camGroundEntry.getIntoNode( ).getName() == 'terrain': base.camera.setZ( camGroundEntry.getSurfacePoint(render).getZ() + 1.5) # Let the camera look at the floater object above Eve. base.camera.lookAt(self.floater) return Task.cont def dropItem(self): self.player.dropItem() def getGroundEntry(self, collisionHandler): # Put all the collision entries into a Python list so we can sort it, # properly. entries = [] for i in range(collisionHandler.getNumEntries()): entries.append(collisionHandler.getEntry(i)) # Sort the list by the collision points' Z values, making sure the # highest value ends up at the front of the list. entries.sort(lambda x, y: cmp( y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if len(entries) > 0: return entries[0] else: return None def enterThrowMode(self): self.throwMode = True self.player.enterStrafeMode() self.enableFreelook() def leaveThrowMode(self): self.throwMode = False self.player.leaveStrafeMode() self.disableFreelook()
from pandac.PandaModules import Point3 from pandac.PandaModules import Vec3 import math from math import sqrt wallRayNP = render.attachNewNode(CollisionNode("wall ray collision node")) wallRayNP.node().addSolid(CollisionRay(0,0,0,0,1,0)) wallRayNP.node().setIntoCollideMask(BitMask32.allOff()) wallRayNP.node().setFromCollideMask(BitMask32.allOn() & ~GeomNode.getDefaultCollideMask()) wallRayNP.node().setFromCollideMask(wallRayNP.node().getFromCollideMask() & ~BitMask32.bit(1)) #wallRayNP.show() collisionHandler = CollisionHandlerQueue() collisionTraverser = CollisionTraverser("pathfinder's collisionTraverser") collisionTraverser.addCollider(wallRayNP, collisionHandler) collisionTraverser.setRespectPrevTransform(True) class PathFinder(): ## def __init__(self, position, ID = -1): ## NodePath.__init__(self, "Waypoint") ## self.position = position ## self.texture = loader.loadTexture("textures/blue.jpg") ## self.costToThisNode = 0 ## self.visited = False ## self.neighbors = [] ## self.ID = ID ## self.previousWaypoint = None @classmethod
collisionHandler.addOutPattern("ray-out-cards") PICKING_MASK = BitMask32.bit(1) # ** Setting the ray collider pickerNode = CollisionNode("mouseraycnode") # another important but obvious difference from step 6 is that this time we parent the ray nodepath in render2d instead render root nodepath, otherwise all the objects we're going to define in 2D won't be seen by the ray. pickerNP = base.render2d.attachNewNode(pickerNode) pickerNP.show() # note that this time we set the ray dimension along the Y axis 2 point long to pierce everything is on the Y=0 position (2D objects are usually placed there) pickerRay = CollisionRay(0, -1, 0, 0, 1, 0) pickerNode.addSolid(pickerRay) pickerNode.setFromCollideMask(PICKING_MASK) pickerNode.setIntoCollideMask(BitMask32.allOff()) # ** put the ray into the traverse cycle customCtrav.addCollider(pickerNP, collisionHandler) # ** We create here 3 cards (indeed are) each of them tagged to bring with the id numnber we'll use to load the proper card texture later and its status which, in the beginning, is hidden (the back card facing up). cm = CardMaker("cm") left, right, bottom, top = 0, 1.4, 0, -2 cm.setFrame(left, right, top, bottom) # Note we parent the card in aspect2d instead render2d because it will keep the right proportions even with different screen ratios cardrootNP = aspect2d.attachNewNode("cardroot") tex = loader.loadTexture("textures/cards/back.png") for x in range(3): card = cardrootNP.attachNewNode(cm.generate()) card.setPos(x * 2, 0, -1) card.setTag("id", str(x + 1)) card.setTag("status", "hidden") card.setTexture(tex) card.setCollideMask(PICKING_MASK)
class Game(DirectObject.DirectObject): def __init__(self, showbase, usersData, gameData): self.showbase = showbase self.usersData = usersData self.gameData = gameData random.seed(self.gameData.randSeed) # Initialize the collision traverser. self.cTrav = CollisionTraverser() # Initialize the handler. self.collHandEvent = CollisionHandlerEvent() self.collHandEvent.addInPattern('into-%in') self.world = World(showbase) for user in self.usersData: user.centipede = Centipede(showbase, len(self.usersData), self.addToCollisions) if user.thisPlayer: self.centipede = user.centipede self.centipede.attachRing(showbase) self.foods = [] for i in range(self.gameData.maxFoods): self.foods.append(Food(self.showbase, i, self.addToCollisions)) self.ticks = 0 def destroy(self): self.world.destroy() for user in self.usersData: user.centipede.destroy() for food in self.foods: food.destroy() def runTick(self, dt): # run each of the centipedes simulations for user in self.usersData: user.centipede.update(dt) if len(user.centipede.body) > 10: return False for food in self.foods: food.update(dt) self.cTrav.traverse(self.showbase.render) self.ticks += 1 # Return true if game is still not over (false to end game) return True def collideInto(self, collEntry): for user in self.usersData: if collEntry.getFromNodePath( ) == user.centipede.head.collisionNode[0]: for food in self.foods: if collEntry.getIntoNodePath( ) == food.model.collisionNode[0]: user.centipede.addLength(self.showbase) food.reset() if len(user.centipede.body) > 2: if collEntry.getIntoNodePath( ) == user.centipede.tail.collisionNode[0]: user.centipede.reset() for i in range(len(user.centipede.body) - 1 - 2): if collEntry.getIntoNodePath() == user.centipede.body[ i + 2].collisionNode[0]: user.centipede.reset() break def addToCollisions(self, item): # Add this object to the traverser. self.cTrav.addCollider(item[0], self.collHandEvent) # Accept the events sent by the collisions. self.accept('into-' + str(item[1]), self.collideInto)
class objectIdPicklingClass: def __init__( self, bit=[PICKABLE] ): global OBJECTIDMAPPING #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 = base.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(bitMaskOr(bit)) 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) def mousePick( self ): #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()) #Do the actual collision pass (Do it only on the squares for #efficiency purposes) self.picker.traverse( render ) 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() pickedObj = self.pq.getEntry(0).getIntoNodePath() #print pickedObj pickedObjObjectId = pickedObj.findNetTag( 'objectId' ) if pickedObj.hasNetTag( 'objectId' ): return pickedObj.getNetTag( 'objectId' ) else: print "pickedObj.hasNetTag( 'objectId' ) failed" return None else: print "self.pq.getNumEntries() = %i" % self.pq.getNumEntries() return None else: print "base.mouseWatcherNode.hasMouse() failed" return None def getPickerRayDirection( self, mousePos=None ): #posX, posY ): ''' return the direction of the ray sent trought the mouse ''' # the pickerRay cannot be changed anyway once it has been set in a frame (BUG?) if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() #mousePos = (mpos.getX(), mpos.getY()) self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) # make a copy of the ray direction = self.pickerRay.getDirection() mouseRayDirection = Point3(direction.getX(), direction.getY(), direction.getZ()) # and normalize it mouseRayDirection.normalize() return mouseRayDirection def getObjectMousePick( self ): objectId = self.mousePick() if OBJECTIDMAPPING.has_key( objectId ): return OBJECTIDMAPPING[objectId] else: return None
class FreeBLiTZ(ShowBase): def __init__(self): from pandac.PandaModules import CollisionHandlerFloor, CollisionHandlerPusher, CollisionHandlerEvent, CollisionTraverser from pandac.PandaModules import DirectionalLight, AmbientLight, VBase4 ShowBase.__init__(self) self.sky = self.loader.loadModel('models/sky-sphere') self.sky.reparentTo(self.render) self.stage = self.loader.loadModel('models/test-collide') self.stage.reparentTo(self.render) self.floor = self.stage.findAllMatches('**/=CollideType=floor') self.floor.setCollideMask(FLOOR_MASK) self.obstacles = self.stage.findAllMatches('**/=CollideType=obstacle') if self.obstacles: self.obstacles.setCollideMask(OBSTACLE_MASK) self.zones = self.stage.findAllMatches('**/=CollideType=zone') if self.zones: self.zones.setCollideMask(ZONE_MASK) self.create_stanchions() # Character rig, which allows camera to follow character self.char_rig = self.stage.attachNewNode('char_rig') self.active_char = Character('mainchar', self.char_rig) self.cam.reparentTo(self.char_rig) self.cam.setPos(0.5, -3, 1.5) self.cam.lookAt(0.5, 0, 1.5) self.light = DirectionalLight('dlight') self.light.setColor(VBase4(0.3, 0.28, 0.26, 1.0)) self.lightNP = self.stage.attachNewNode(self.light) self.lightNP.setHpr(-75, -45, 0) self.stage.setLight(self.lightNP) self.amblight = AmbientLight('amblight') self.amblight.setColor(VBase4(0.7, 0.68, 0.66, 1.0)) self.amblightNP = self.stage.attachNewNode(self.amblight) self.stage.setLight(self.amblightNP) self.accept('w', self.active_char.begin_forward) self.accept('a', self.active_char.begin_left) self.accept('s', self.active_char.begin_backward) self.accept('d', self.active_char.begin_right) self.accept('w-up', self.active_char.end_forward) self.accept('a-up', self.active_char.end_left) self.accept('s-up', self.active_char.end_backward) self.accept('d-up', self.active_char.end_right) self.taskMgr.add(self.active_char.MoveTask, 'MoveTask') self.look = False self.prev_pos = None self.accept('mouse2', self.begin_look) self.accept('mouse2-up', self.end_look) self.accept('mouse3', self.active_char.begin_spin) self.accept('mouse3-up', self.active_char.end_spin) self.taskMgr.add(self.MouseTask, 'MouseTask') self.floor_handler = CollisionHandlerFloor() self.floor_handler.addCollider(self.active_char.actor_from_floor, self.char_rig) self.wall_handler = CollisionHandlerPusher() self.wall_handler.addCollider(self.active_char.actor_from_obstacle, self.char_rig) self.zone_handler = CollisionHandlerEvent() self.zone_handler.addInPattern('%fn-into') self.zone_handler.addOutPattern('%fn-out') def foo(entry): print 'You are in the zone' def bar(entry): print 'You are not in the zone' self.accept('blockchar_zone-into', foo) self.accept('blockchar_zone-out', bar) self.cTrav = CollisionTraverser('main traverser') self.cTrav.setRespectPrevTransform(True) self.cTrav.addCollider(self.active_char.actor_from_floor, self.floor_handler) self.cTrav.addCollider(self.active_char.actor_from_obstacle, self.wall_handler) self.cTrav.addCollider(self.active_char.actor_from_zone, self.zone_handler) #self.cTrav.showCollisions(self.stage) def create_stanchions(self): from pandac.PandaModules import GeomVertexReader, CollisionNode, CollisionTube self.stanchions = self.stage.findAllMatches('**/=Stanchion') for stanchion in self.stanchions: geomnode = stanchion.node() radius = float(stanchion.getTag('Stanchion')) geom = geomnode.getGeom(0) vdata = geom.getVertexData() for gp in range(geom.getNumPrimitives()): vreader = GeomVertexReader(vdata, 'vertex') prim = geom.getPrimitive(gp) prim = prim.decompose() for p in range(prim.getNumPrimitives()): start = prim.getPrimitiveStart(p) end = prim.getPrimitiveEnd(p) vertices = [] for v in range(start, end): vi = prim.getVertex(v) vreader.setRow(vi) vertex = vreader.getData3f() vertices.append(vertex) vertices.append(vertices[0]) for i in range(1, len(vertices)): a, b = vertices[i-1], vertices[i] stanchion_np = stanchion.attachNewNode(CollisionNode('stanchion')) print 'creating cyl with radius %f from %s to %s' % (radius, a, b) stanchion_np.node().addSolid(CollisionTube(a[0], a[1], a[2], b[0], b[1], b[2], radius)) stanchion_np.node().setFromCollideMask(OBSTACLE_MASK) geomnode.removeAllGeoms() def begin_look(self): self.look = True def end_look(self): self.look = False self.prev_pos = None def MouseTask(self, task): if self.mouseWatcherNode.hasMouse(): (x, y) = self.mouseWatcherNode.getMouse() if self.prev_pos: if self.look or self.active_char.spinning: h_diff = (x - self.prev_pos[0]) * 180 p_diff = (y - self.prev_pos[1]) * 90 new_h = clamp_deg_sign(self.char_rig.getH() - h_diff) self.char_rig.setH(new_h) self.cam.setP(self.cam.getP() + p_diff) self.active_char.spin(new_h) self.prev_pos = (x, y) return task.cont
class BallPlateWorld(WorldBase): def __init__(self, controller, log_2_memory, display_categories): WorldBase.__init__(self, controller, log_2_memory, display_categories) self.display_categories = display_categories self.last_time = time.time() self.step = 0 self.__init_kepler_scene() def set_3d_scene(self, x,y,z, alpha, beta, dt): new_position = Point3(x,y,z) self.maze.setP(-self.alpha) self.maze.setR(-self.beta) self.ballRoot.setPos(new_position) #This block of code rotates the ball. It uses a quaternion #to rotate the ball around an arbitrary axis. That axis perpendicular to #the balls rotation, and the amount has to do with the size of the ball #This is multiplied on the previous rotation to incrimentally turn it. prevRot = LRotationf(self.ball.getQuat()) axis = UP.cross(self.ballV) newRot = LRotationf(axis, 45.5 * dt * self.ballV.length()) self.ball.setQuat(prevRot * newRot) def __init_kepler_scene(self): self.hud_count_down = 0 self.alpha = 0. self.beta = 0. self._set_title("Hugomatic 3D sim") self.alpha_rot_speed = 0. self.beta_rot_speed = 0. #This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Kepler simulation tool 1", style=1, fg=(1,1,1,1), pos=(0.7,-0.95), scale = .07, font = font) self.instructions = OnscreenText(text="alpha: 0.000\nbeta: 0.000", pos = (-1.3, .95), fg=(1,1,1,1), font = font, align = TextNode.ALeft, scale = .05) if DISABLE_MOUSE: base.disableMouse() #Disable mouse-based camera control camera.setPosHpr(-10, -10, 25, 0, -90, 0) #Place the camera #Load the maze and place it in the scene self.maze = loader.loadModel("models/maze") process_model(self.maze) self.maze.reparentTo(render) #Most times, you want collisions to be tested against invisible geometry #rather than every polygon. This is because testing against every polygon #in the scene is usually too slow. You can have simplified or approximate #geometry for the solids and still get good results. # #Sometimes you'll want to create and position your own collision solids in #code, but it's often easier to have them built automatically. This can be #done by adding special tags into an egg file. Check maze.egg and ball.egg #and look for lines starting with <Collide>. The part is brackets tells #Panda exactly what to do. Polyset means to use the polygons in that group #as solids, while Sphere tells panda to make a collision sphere around them #Keep means to keep the polygons in the group as visable geometry (good #for the ball, not for the triggers), and descend means to make sure that #the settings are applied to any subgroups. # #Once we have the collision tags in the models, we can get to them using #NodePath's find command #Find the collision node named wall_collide self.walls = self.maze.find("**/wall_collide") #Collision objects are sorted using BitMasks. BitMasks are ordinary numbers #with extra methods for working with them as binary bits. Every collision #solid has both a from mask and an into mask. Before Panda tests two #objects, it checks to make sure that the from and into collision masks #have at least one bit in common. That way things that shouldn't interact #won't. Normal model nodes have collision masks as well. By default they #are set to bit 20. If you want to collide against actual visible polygons, #set a from collide mask to include bit 20 # #For this example, we will make everything we want the ball to collide with #include bit 0 self.walls.node().setIntoCollideMask(BitMask32.bit(0)) #CollisionNodes are usually invisible but can be shown. Uncomment the next #line to see the collision walls if VISIBLE_WALLS: self.walls.show() #Ground_collide is a single polygon on the same plane as the ground in the #maze. We will use a ray to collide with it so that we will know exactly #what height to put the ball at every frame. Since this is not something #that we want the ball itself to collide with, it has a different #bitmask. self.mazeGround = self.maze.find("**/ground_collide") self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1)) #Load the ball and attach it to the scene #It is on a root dummy node so that we can rotate the ball itself without #rotating the ray that will be attached to it self.ballRoot = render.attachNewNode("ballRoot") self.ball = loader.loadModel("models/ball") self.ball.reparentTo(self.ballRoot) #Find the collison sphere for the ball which was created in the egg file #Notice that it has a from collision mask of bit 0, and an into collison #mask of no bits. This means that the ball can only cause collisions, not #be collided into self.ballSphere = self.ball.find("**/ball") self.ballSphere.node().setFromCollideMask(BitMask32.bit(0)) self.ballSphere.node().setIntoCollideMask(BitMask32.allOff()) #No we create a ray to start above the ball and cast down. This is to #Determine the height the ball should be at and the angle the floor is #tilting. We could have used the sphere around the ball itself, but it #would not be as reliable self.ballGroundRay = CollisionRay() #Create the ray self.ballGroundRay.setOrigin(0,0,10) #Set its origin self.ballGroundRay.setDirection(0,0,-1) #And its direction #Collision solids go in CollisionNode self.ballGroundCol = CollisionNode('groundRay') #Create and name the node self.ballGroundCol.addSolid(self.ballGroundRay) #Add the ray self.ballGroundCol.setFromCollideMask(BitMask32.bit(1)) #Set its bitmasks self.ballGroundCol.setIntoCollideMask(BitMask32.allOff()) #Attach the node to the ballRoot so that the ray is relative to the ball #(it will always be 10 feet over the ball and point down) self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol) #Uncomment this line to see the ray self.ballGroundColNp.show() #Finally, we create a CollisionTraverser. CollisionTraversers are what #do the job of calculating collisions self.cTrav = CollisionTraverser() #Collision traverservs tell collision handlers about collisions, and then #the handler decides what to do with the information. We are using a #CollisionHandlerQueue, which simply creates a list of all of the #collisions in a given pass. There are more sophisticated handlers like #one that sends events and another that tries to keep collided objects #apart, but the results are often better with a simple queue self.cHandler = CollisionHandlerQueue() #Now we add the collision nodes that can create a collision to the #traverser. The traverser will compare these to all others nodes in the #scene. There is a limit of 32 CollisionNodes per traverser #We add the collider, and the handler to use as a pair self.cTrav.addCollider(self.ballSphere, self.cHandler) self.cTrav.addCollider(self.ballGroundColNp, self.cHandler) #Collision traversers have a built in tool to help visualize collisions. #Uncomment the next line to see it. if VISIBLE_WALLS: self.cTrav.showCollisions(render) #This section deals with lighting for the ball. Only the ball was lit #because the maze has static lighting pregenerated by the modeler lAttrib = LightAttrib.makeAllOff() ambientLight = AmbientLight( "ambientLight" ) ambientLight.setColor( Vec4(.55, .55, .55, 1) ) lAttrib = lAttrib.addLight( ambientLight ) directionalLight = DirectionalLight( "directionalLight" ) directionalLight.setDirection( Vec3( 0, 0, -1 ) ) directionalLight.setColor( Vec4( 0.375, 0.375, 0.375, 1 ) ) directionalLight.setSpecularColor(Vec4(1,1,1,1)) lAttrib = lAttrib.addLight( directionalLight ) self.ballRoot.node().setAttrib( lAttrib ) #This section deals with adding a specular highlight to the ball to make #it look shiny m = Material() m.setSpecular(Vec4(1,1,1,1)) m.setShininess(96) self.ball.setMaterial(m, 1) #Finally, we call start for more initialization # self.start() #def start(self): #The maze model also has a locator in it for where to start the ball #To access it we use the find command startPos = (0,0,0)#= self.maze.find("**/start").getPos() self.ballRoot.setPos(startPos) #Set the ball in the starting position self.ballV = Vec3(0,0,0) #Initial velocity is 0 self.accelV = Vec3(0,0,0) #Initial acceleration is 0 #For a traverser to actually do collisions, you need to call #traverser.traverse() on a part of the scene. Fortunatly, base has a #task that does this for the entire scene once a frame. This sets up our #traverser as the one to be called automatically base.cTrav = self.cTrav #This function handles the collision between the ray and the ground #Information about the interaction is passed in colEntry def groundCollideHandler(self, colEntry): #Set the ball to the appropriate Z value for it to be exactly on the ground newZ = colEntry.getSurfacePoint(render).getZ() self.ballRoot.setZ(newZ + .4) #Find the acceleration direction. First the surface normal is crossed with #the up vector to get a vector perpendicular to the slope norm = colEntry.getSurfaceNormal(render) accelSide = norm.cross(UP) #Then that vector is crossed with the surface normal to get a vector that #points down the slope. By getting the acceleration in 3D like this rather #than in 2D, we reduce the amount of error per-frame, reducing jitter self.accelV = norm.cross(accelSide) #This function handles the collision between the ball and a wall def wallCollideHandler(self, colEntry): #First we calculate some numbers we need to do a reflection norm = colEntry.getSurfaceNormal(render) * -1 #The normal of the wall curSpeed = self.ballV.length() #The current speed inVec = self.ballV / curSpeed #The direction of travel velAngle = norm.dot(inVec) #Angle of incidance hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos() hitDir.normalize() hitAngle = norm.dot(hitDir) #The angle between the ball and the normal #Ignore the collision if the ball is either moving away from the wall #already (so that we don't accidentally send it back into the wall) #and ignore it if the collision isn't dead-on (to avoid getting caught on #corners) if velAngle > 0 and hitAngle > .995: #Standard reflection equation reflectVec = (norm * norm.dot(inVec * -1) * 2) + inVec #This makes the velocity half of what it was if the hit was dead-on #and nearly exactly what it was if this is a glancing blow self.ballV = reflectVec * (curSpeed * (((1-velAngle)*.5)+.5)) #Since we have a collision, the ball is already a little bit buried in #the wall. This calculates a vector needed to move it so that it is #exactly touching the wall disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) newPos = self.ballRoot.getPos() + disp self.ballRoot.setPos(newPos) def update_hud(self): self.hud_count_down -= 1 if self.hud_count_down <= 0: self.hud_count_down = 5 p1, p2 = self.get_ball_position() text = "\nalpha: %.5f\nbeta: %.5f\npos [%.05f,%.05f]\n" % (self.alpha, self.beta, p1,p2) self.instructions.setText(text) def control_task(self,task): delta_time = task.time - self.last_time self.last_time = task.time self.step += 1 if self.controller: self.controller.loop(self.step, task.time, delta_time) if self.logging: data = self.controller.get_display_data() self.log.snapshot(get_data_logger(), self.step, task.time, data, ('self')) def get_table_inclination(self): angle1 = math.radians(self.alpha) angle2 = math.radians(self.beta) return (angle1, angle2) def set_table_rotation_speed(self, alpha_rot_speed, beta_rot_speed): self.alpha_rot_speed = alpha_rot_speed self.beta_rot_speed = beta_rot_speed def get_ball_position(self): p = self.ballRoot.getPos() p1 = p[0] p2 = p[1] #print "ball position [%s, %s]" % (p1, p2) return (p1, p2)
class FreeBLiTZ(ShowBase): def __init__(self): from pandac.PandaModules import CollisionHandlerFloor, CollisionHandlerPusher, CollisionHandlerEvent, CollisionTraverser from pandac.PandaModules import DirectionalLight, AmbientLight, VBase4 ShowBase.__init__(self) self.sky = self.loader.loadModel('models/sky-sphere') self.sky.reparentTo(self.render) self.stage = self.loader.loadModel('models/test-collide') self.stage.reparentTo(self.render) self.floor = self.stage.findAllMatches('**/=CollideType=floor') self.floor.setCollideMask(FLOOR_MASK) self.obstacles = self.stage.findAllMatches('**/=CollideType=obstacle') if self.obstacles: self.obstacles.setCollideMask(OBSTACLE_MASK) self.zones = self.stage.findAllMatches('**/=CollideType=zone') if self.zones: self.zones.setCollideMask(ZONE_MASK) self.create_stanchions() # Character rig, which allows camera to follow character self.char_rig = self.stage.attachNewNode('char_rig') self.active_char = Character('mainchar', self.char_rig) self.cam.reparentTo(self.char_rig) self.cam.setPos(0.5, -3, 1.5) self.cam.lookAt(0.5, 0, 1.5) self.light = DirectionalLight('dlight') self.light.setColor(VBase4(0.3, 0.28, 0.26, 1.0)) self.lightNP = self.stage.attachNewNode(self.light) self.lightNP.setHpr(-75, -45, 0) self.stage.setLight(self.lightNP) self.amblight = AmbientLight('amblight') self.amblight.setColor(VBase4(0.7, 0.68, 0.66, 1.0)) self.amblightNP = self.stage.attachNewNode(self.amblight) self.stage.setLight(self.amblightNP) self.accept('w', self.active_char.begin_forward) self.accept('a', self.active_char.begin_left) self.accept('s', self.active_char.begin_backward) self.accept('d', self.active_char.begin_right) self.accept('w-up', self.active_char.end_forward) self.accept('a-up', self.active_char.end_left) self.accept('s-up', self.active_char.end_backward) self.accept('d-up', self.active_char.end_right) self.taskMgr.add(self.active_char.MoveTask, 'MoveTask') self.look = False self.prev_pos = None self.accept('mouse2', self.begin_look) self.accept('mouse2-up', self.end_look) self.accept('mouse3', self.active_char.begin_spin) self.accept('mouse3-up', self.active_char.end_spin) self.taskMgr.add(self.MouseTask, 'MouseTask') self.floor_handler = CollisionHandlerFloor() self.floor_handler.addCollider(self.active_char.actor_from_floor, self.char_rig) self.wall_handler = CollisionHandlerPusher() self.wall_handler.addCollider(self.active_char.actor_from_obstacle, self.char_rig) self.zone_handler = CollisionHandlerEvent() self.zone_handler.addInPattern('%fn-into') self.zone_handler.addOutPattern('%fn-out') def foo(entry): print 'You are in the zone' def bar(entry): print 'You are not in the zone' self.accept('blockchar_zone-into', foo) self.accept('blockchar_zone-out', bar) self.cTrav = CollisionTraverser('main traverser') self.cTrav.setRespectPrevTransform(True) self.cTrav.addCollider(self.active_char.actor_from_floor, self.floor_handler) self.cTrav.addCollider(self.active_char.actor_from_obstacle, self.wall_handler) self.cTrav.addCollider(self.active_char.actor_from_zone, self.zone_handler) #self.cTrav.showCollisions(self.stage) def create_stanchions(self): from pandac.PandaModules import GeomVertexReader, CollisionNode, CollisionTube self.stanchions = self.stage.findAllMatches('**/=Stanchion') for stanchion in self.stanchions: geomnode = stanchion.node() radius = float(stanchion.getTag('Stanchion')) geom = geomnode.getGeom(0) vdata = geom.getVertexData() for gp in range(geom.getNumPrimitives()): vreader = GeomVertexReader(vdata, 'vertex') prim = geom.getPrimitive(gp) prim = prim.decompose() for p in range(prim.getNumPrimitives()): start = prim.getPrimitiveStart(p) end = prim.getPrimitiveEnd(p) vertices = [] for v in range(start, end): vi = prim.getVertex(v) vreader.setRow(vi) vertex = vreader.getData3f() vertices.append(vertex) vertices.append(vertices[0]) for i in range(1, len(vertices)): a, b = vertices[i - 1], vertices[i] stanchion_np = stanchion.attachNewNode( CollisionNode('stanchion')) print 'creating cyl with radius %f from %s to %s' % ( radius, a, b) stanchion_np.node().addSolid( CollisionTube(a[0], a[1], a[2], b[0], b[1], b[2], radius)) stanchion_np.node().setFromCollideMask(OBSTACLE_MASK) geomnode.removeAllGeoms() def begin_look(self): self.look = True def end_look(self): self.look = False self.prev_pos = None def MouseTask(self, task): if self.mouseWatcherNode.hasMouse(): (x, y) = self.mouseWatcherNode.getMouse() if self.prev_pos: if self.look or self.active_char.spinning: h_diff = (x - self.prev_pos[0]) * 180 p_diff = (y - self.prev_pos[1]) * 90 new_h = clamp_deg_sign(self.char_rig.getH() - h_diff) self.char_rig.setH(new_h) self.cam.setP(self.cam.getP() + p_diff) self.active_char.spin(new_h) self.prev_pos = (x, y) return task.cont
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.debug = True self.statusLabel = self.makeStatusLabel(0) self.collisionLabel = self.makeStatusLabel(1) self.world = self.loader.loadModel("world.bam") self.world.reparentTo(self.render) self.maxspeed = 100.0 # Avion à la pointe des chateaux, direction Ouest ! self.startPos = Vec3(1200, 320, 85) #print (self.startPos) self.startHpr = Vec3(0, 0, 0) #self.player.setPos(1200,320,85) #self.player.setH(0) self.player = self.loader.loadModel("alliedflanker.egg") #self.player.setPos(640,640,85) self.player.setScale(0.2, 0.2, 0.2) self.player.reparentTo(self.render) self.resetPlayer() # load the explosion ring self.explosionModel = loader.loadModel('explosion') self.explosionModel.reparentTo(self.render) self.explosionModel.setScale(0.0) self.explosionModel.setLightOff() # only one explosion at a time: self.exploding = False # performance (to be masked later by fog) and view: self.maxdistance = 1200 self.camLens.setFar(self.maxdistance) self.camLens.setFov(60) self.taskMgr.add(self.updateTask, "update") self.keyboardSetup() # relevant for world boundaries self.worldsize = 1024 self.createEnvironment() self.setupCollisions() self.textCounter = 0 def resetPlayer(self): self.player.show() #self.player.setPos(self.world,self.startPos) #self.player.setHpr(self.world,self.startHpr) self.player.setPos(self.startPos) self.player.setHpr(self.startHpr) self.speed = 10.0 #self.speed = self.maxspeed/2 #print (self.player.getPos()) def makeStatusLabel(self, i): return OnscreenText(style=2, fg=(.5,1,.5,1), pos=(-1.3,0.92-(.08 * i)), \ align=TextNode.ALeft, scale = .08, mayChange = 1) def updateTask(self, task): self.updatePlayer() self.updateCamera() self.collTrav.traverse(self.render) for i in range(self.playerGroundHandler.getNumEntries()): entry = self.playerGroundHandler.getEntry(i) if (self.debug == True): self.collisionLabel.setText("DEAD:" + str(globalClock.getFrameTime())) if (self.exploding == False): self.player.setZ( entry.getSurfacePoint(self.render).getZ() + 10) self.explosionSequence() # we will later deal with 'what to do' when the player dies return task.cont def keyboardSetup(self): self.keyMap = {"left":0, "right":0, "climb":0, "fall":0, \ "accelerate":0, "decelerate":0, "fire":0} self.accept("escape", sys.exit) ## Gestion Vitesse self.accept("a", self.setKey, ["accelerate", 1]) self.accept("a-up", self.setKey, ["accelerate", 0]) self.accept("q", self.setKey, ["decelerate", 1]) self.accept("q-up", self.setKey, ["decelerate", 0]) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_down", self.setKey, ["climb", 1]) self.accept("arrow_down-up", self.setKey, ["climb", 0]) self.accept("arrow_up", self.setKey, ["fall", 1]) self.accept("arrow_up-up", self.setKey, ["fall", 0]) # self.accept(“space”, self.setKey, [“fire”,1]) # self.accept(“space-up”, self.setKey, [“fire”,0]) base.disableMouse() # or updateCamera will fail! def setKey(self, key, value): self.keyMap[key] = value def updateCamera(self): # see issue content for how we calculated these: self.camera.setPos(self.player, 25.6225, 3.8807, 10.2779) #self.camera.setPos(0, 0, 90) self.camera.setHpr(self.player, 94.8996, -16.6549, 1.55508) def updatePlayer(self): # Global Clock # by default, panda runs as fast as it can frame to frame scalefactor = (globalClock.getDt() * self.speed) #climbfactor = scalefactor * 0.5 #bankfactor = scalefactor #speedfactor = scalefactor * 2.9 climbfactor = scalefactor * 0.5 * 2 bankfactor = scalefactor * 2.0 speedfactor = scalefactor * 2.9 # throttle control if (self.keyMap["accelerate"] != 0): self.speed += 1 if (self.speed > self.maxspeed): self.speed = self.maxspeed elif (self.keyMap["decelerate"] != 0): self.speed -= 1 if (self.speed < 0.0): self.speed = 0.0 # Left and Right if (self.keyMap["left"] != 0 and self.speed > 0.0): self.player.setH(self.player.getH() + bankfactor) self.player.setP(self.player.getP() + bankfactor) if (self.player.getP() >= 180): self.player.setP(-180) elif (self.keyMap["right"] != 0 and self.speed > 0.0): self.player.setH(self.player.getH() - bankfactor) self.player.setP(self.player.getP() - bankfactor) if (self.player.getP() <= -180): self.player.setP(180) elif (self.player.getP() > 0): # autoreturn from right self.player.setP(self.player.getP() - (bankfactor + 0.1)) if (self.player.getP() < 0): self.player.setP(0) elif (self.player.getP() < 0): # autoreturn from left self.player.setP(self.player.getP() + (bankfactor + 0.1)) if (self.player.getP() > 0): self.player.setP(0) # Climb and Fall if (self.keyMap["climb"] != 0 and self.speed > 0.00): # faster you go, quicker you climb self.player.setZ(self.player.getZ() + climbfactor) self.player.setR(self.player.getR() + climbfactor) if (self.player.getR() >= 180): self.player.setR(-180) elif (self.keyMap["fall"] != 0 and self.speed > 0.00): self.player.setZ(self.player.getZ() - climbfactor) self.player.setR(self.player.getR() - climbfactor) if (self.player.getR() <= -180): self.player.setR(180) elif (self.player.getR() > 0): # autoreturn from up self.player.setR(self.player.getR() - (climbfactor + 0.1)) if (self.player.getR() < 0): self.player.setR(0) # avoid jitter elif (self.player.getR() < 0): # autoreturn from down self.player.setR(self.player.getR() + (climbfactor + 0.1)) if (self.player.getR() > 0): self.player.setR(0) # move forwards - our X/Y is inverted, see the issue if self.exploding == False: self.player.setX(self.player, -speedfactor) self.applyBoundaries() def createEnvironment(self): # Fog to hide a performance tweak: colour = (0.0, 0.0, 0.0) expfog = Fog("scene-wide-fog") expfog.setColor(*colour) expfog.setExpDensity(0.001) # original : 0.004 render.setFog(expfog) base.setBackgroundColor(*colour) # Our sky skydome = loader.loadModel('sky.egg') skydome.setEffect(CompassEffect.make(self.render)) skydome.setScale(self.maxdistance / 2) # bit less than "far" skydome.setZ(-65) # sink it # NOT render - you'll fly through the sky!: skydome.reparentTo(self.camera) # Our lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.6, .6, .6, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(0, -10, -10)) directionalLight.setColor(Vec4(1, 1, 1, 1)) directionalLight.setSpecularColor(Vec4(1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) def setupCollisions(self): self.collTrav = CollisionTraverser() self.playerGroundSphere = CollisionSphere(0, 1.5, -1.5, 1.5) self.playerGroundCol = CollisionNode('playerSphere') self.playerGroundCol.addSolid(self.playerGroundSphere) # bitmasks self.playerGroundCol.setFromCollideMask(BitMask32.bit(0)) self.playerGroundCol.setIntoCollideMask(BitMask32.allOff()) self.world.setCollideMask(BitMask32.bit(0)) # and done self.playerGroundColNp = self.player.attachNewNode( self.playerGroundCol) self.playerGroundHandler = CollisionHandlerQueue() self.collTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler) # DEBUG if (self.debug == True): self.playerGroundColNp.show() self.collTrav.showCollisions(self.render) def applyBoundaries(self): if (self.player.getZ() > self.maxdistance): self.player.setZ(self.maxdistance) # should never happen once we add collision, but in case: elif (self.player.getZ() < 0): self.player.setZ(0) # and now the X/Y world boundaries: boundary = False if (self.player.getX() < 0): self.player.setX(0) boundary = True elif (self.player.getX() > self.worldsize): self.player.setX(self.worldsize) boundary = True if (self.player.getY() < 0): self.player.setY(0) boundary = True elif (self.player.getY() > self.worldsize): self.player.setY(self.worldsize) boundary = True # lets not be doing this every frame... if boundary == True and self.textCounter > 30: self.statusLabel.setText("STATUS: MAP END; TURN AROUND") elif self.textCounter > 30: self.statusLabel.setText("STATUS: OK") if self.textCounter > 30: self.textCounter = 0 else: self.textCounter = self.textCounter + 1 def explosionSequence(self): self.exploding = True self.explosionModel.setPosHpr( Vec3(self.player.getX(),self.player.getY(), \ self.player.getZ()), Vec3( self.player.getH(),0,0)) self.player.hide() taskMgr.add(self.expandExplosion, 'expandExplosion') def expandExplosion(self, Task): # expand the explosion rign each frame until a certain size if self.explosionModel.getScale() < VBase3(60.0, 60.0, 60.0): factor = globalClock.getDt() scale = self.explosionModel.getScale() scale = scale + VBase3(factor * 40, factor * 40, factor * 40) self.explosionModel.setScale(scale) return Task.cont else: self.explosionModel.setScale(0) self.exploding = False self.resetPlayer()
class CogdoFlyingCameraManager: def __init__(self, cam, parent, player, level): self._toon = player.toon self._camera = cam self._parent = parent self._player = player self._level = level self._enabled = False def enable(self): if self._enabled: return self._toon.detachCamera() self._prevToonY = 0.0 levelBounds = self._level.getBounds() l = Globals.Camera.LevelBoundsFactor self._bounds = ( (levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]), (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]), (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2]), ) self._lookAtZ = self._toon.getHeight() + Globals.Camera.LookAtToonHeightOffset self._camParent = NodePath("CamParent") self._camParent.reparentTo(self._parent) self._camParent.setPos(self._toon, 0, 0, 0) self._camParent.setHpr(180, Globals.Camera.Angle, 0) self._camera.reparentTo(self._camParent) self._camera.setPos(0, Globals.Camera.Distance, 0) self._camera.lookAt(self._toon, 0, 0, self._lookAtZ) self._cameraLookAtNP = NodePath("CameraLookAt") self._cameraLookAtNP.reparentTo(self._camera.getParent()) self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr()) self._levelBounds = self._level.getBounds() self._enabled = True self._frozen = False self._initCollisions() def _initCollisions(self): self._camCollRay = CollisionRay() camCollNode = CollisionNode("CameraToonRay") camCollNode.addSolid(self._camCollRay) camCollNode.setFromCollideMask( OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask ) camCollNode.setIntoCollideMask(0) self._camCollNP = self._camera.attachNewNode(camCollNode) self._camCollNP.show() self._collOffset = Vec3(0, 0, 0.5) self._collHandler = CollisionHandlerQueue() self._collTrav = CollisionTraverser() self._collTrav.addCollider(self._camCollNP, self._collHandler) self._betweenCamAndToon = {} self._transNP = NodePath("trans") self._transNP.reparentTo(render) self._transNP.setTransparency(True) self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon) self._transNP.setBin("fixed", 10000) def _destroyCollisions(self): self._collTrav.removeCollider(self._camCollNP) self._camCollNP.removeNode() del self._camCollNP del self._camCollRay del self._collHandler del self._collOffset del self._betweenCamAndToon self._transNP.removeNode() del self._transNP def freeze(self): self._frozen = True def unfreeze(self): self._frozen = False def disable(self): if not self._enabled: return self._destroyCollisions() self._camera.wrtReparentTo(render) self._cameraLookAtNP.removeNode() del self._cameraLookAtNP self._camParent.removeNode() del self._camParent del self._prevToonY del self._lookAtZ del self._bounds del self._frozen self._enabled = False def update(self, dt=0.0): self._updateCam(dt) self._updateCollisions() def _updateCam(self, dt): toonPos = self._toon.getPos() camPos = self._camParent.getPos() x = camPos[0] z = camPos[2] toonWorldX = self._toon.getX(render) maxX = Globals.Camera.MaxSpinX toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX) spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (maxX * maxX) newH = 180.0 + spinAngle self._camParent.setH(newH) spinAngle = spinAngle * (pi / 180.0) distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle) distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle) d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0]) if abs(d) > Globals.Camera.LeewayX: if d > Globals.Camera.LeewayX: x = toonPos[0] + Globals.Camera.LeewayX else: x = toonPos[0] - Globals.Camera.LeewayX x = self._toon.getX(render) + distToRightOfToon boundToonZ = min(toonPos[2], self._bounds[2][1]) d = z - boundToonZ if d > Globals.Camera.MinLeewayZ: if self._player.velocity[2] >= 0 and toonPos[1] != self._prevToonY or self._player.velocity[2] > 0: z = boundToonZ + d * INVERSE_E ** (dt * Globals.Camera.CatchUpRateZ) elif d > Globals.Camera.MaxLeewayZ: z = boundToonZ + Globals.Camera.MaxLeewayZ elif d < -Globals.Camera.MinLeewayZ: z = boundToonZ - Globals.Camera.MinLeewayZ if self._frozen: y = camPos[1] else: y = self._toon.getY(render) - distBehindToon self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z)) if toonPos[2] < self._bounds[2][1]: h = self._cameraLookAtNP.getH() if d >= Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ) elif d <= -Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ) self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0) self._camera.setHpr(smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr())) self._prevToonY = toonPos[1] def _updateCollisions(self): pos = self._toon.getPos(self._camera) + self._collOffset self._camCollRay.setOrigin(pos) direction = -Vec3(pos) direction.normalize() self._camCollRay.setDirection(direction) self._collTrav.traverse(render) nodesInBetween = {} if self._collHandler.getNumEntries() > 0: self._collHandler.sortEntries() for entry in self._collHandler.getEntries(): name = entry.getIntoNode().getName() if name.find("col_") >= 0: np = entry.getIntoNodePath().getParent() if not nodesInBetween.has_key(np): nodesInBetween[np] = np.getParent() for np in nodesInBetween.keys(): if self._betweenCamAndToon.has_key(np): del self._betweenCamAndToon[np] else: np.setTransparency(True) np.wrtReparentTo(self._transNP) if np.getName().find("lightFixture") >= 0: if not np.find("**/*floor_mesh").isEmpty(): np.find("**/*floor_mesh").hide() elif np.getName().find("platform") >= 0: if not np.find("**/*Floor").isEmpty(): np.find("**/*Floor").hide() for np, parent in self._betweenCamAndToon.items(): np.wrtReparentTo(parent) np.setTransparency(False) if np.getName().find("lightFixture") >= 0: if not np.find("**/*floor_mesh").isEmpty(): np.find("**/*floor_mesh").show() elif np.getName().find("platform") >= 0: if not np.find("**/*Floor").isEmpty(): np.find("**/*Floor").show() self._betweenCamAndToon = nodesInBetween
class World(ShowBase): def __init__(self): ShowBase.__init__(self) self.debug = False self.statusLabel = self.makeStatusLabel(0) self.collisionLabel = self.makeStatusLabel(1) if os.path.isfile("assets/1stmap.bam"): self.world = self.loader.loadModel("assets/1stmap.bam") self.world.reparentTo(self.render) else: print "generating terrain and saving bam for future use" terrain = GeoMipTerrain("worldTerrain") terrain.setHeightfield("./assets/1stmap_HF.png") terrain.setColorMap("./assets/1stmap_TM.png") terrain.setBruteforce(True) root = terrain.getRoot() root.reparentTo(self.render) root.setSz(60) terrain.generate() root.writeBamFile("./assets/1stmap.bam") self.worldsize = 1024 # Player self.maxspeed = 100.0 self.startPos = Vec3(200, 200, 35) self.startHpr = Vec3(225, 0, 0) self.player = self.loader.loadModel("assets/alliedflanker.egg") self.player.setScale(0.2, 0.2, 0.2) self.player.reparentTo(self.render) self.resetPlayer() # Player destruction self.explosionModel = loader.loadModel("assets/explosion") self.explosionModel.reparentTo(self.render) self.explosionModel.setScale(0.0) self.explosionModel.setLightOff() # Only one explosion at a time self.exploding = False self.taskMgr.add(self.updateTask, "update") self.keyboardSetup() self.maxdistance = 600 self.camLens.setFar(self.maxdistance) self.camLens.setFov(60) self.createEnvironment() self.setupCollisions() self.textCounter = 0 def makeStatusLabel(self, i): return OnscreenText( style=2, fg=(0.5, 1, 0.5, 1), pos=(-1.3, 0.92 - (0.08 * i)), align=TextNode.ALeft, scale=0.08, mayChange=1 ) def createEnvironment(self): # Fog expfog = Fog("scene-wide-fog") expfog.setColor(0.5, 0.5, 0.5) expfog.setExpDensity(0.002) self.render.setFog(expfog) # Sky skysphere = self.loader.loadModel("assets/blue-sky-sphere") skysphere.setEffect(CompassEffect.make(self.render)) skysphere.setScale(0.08) skysphere.reparentTo(self.camera) # Lights ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(0.6, 0.6, 0.6, 1)) self.render.setLight(self.render.attachNewNode(ambientLight)) directionalLight = DirectionalLight("directionalLight") directionalLight.setColor(VBase4(0.8, 0.8, 0.5, 1)) dlnp = self.render.attachNewNode(directionalLight) dlnp.setPos(0, 0, 260) dlnp.lookAt(self.player) self.render.setLight(dlnp) # Water self.water = self.loader.loadModel("assets/square.egg") self.water.setSx(self.worldsize * 2) self.water.setSy(self.worldsize * 2) self.water.setPos(self.worldsize / 2, self.worldsize / 2, 25) self.water.setTransparency(TransparencyAttrib.MAlpha) newTS = TextureStage("1") self.water.setTexture(newTS, self.loader.loadTexture("assets/water.png")) self.water.setTexScale(newTS, 4) self.water.reparentTo(self.render) LerpTexOffsetInterval(self.water, 200, (1, 0), (0, 0), textureStage=newTS).loop() def keyboardSetup(self): self.keyMap = {"left": 0, "right": 0, "climb": 0, "fall": 0, "accelerate": 0, "decelerate": 0, "fire": 0} self.accept("escape", sys.exit) self.accept("a", self.setKey, ["accelerate", 1]) self.accept("a-up", self.setKey, ["accelerate", 0]) self.accept("z", self.setKey, ["decelerate", 1]) self.accept("z-up", self.setKey, ["decelerate", 0]) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_down", self.setKey, ["climb", 1]) self.accept("arrow_down-up", self.setKey, ["climb", 0]) self.accept("arrow_up", self.setKey, ["fall", 1]) self.accept("arrow_up-up", self.setKey, ["fall", 0]) self.accept("space", self.setKey, ["fire", 1]) self.accept("space-up", self.setKey, ["fire", 0]) base.disableMouse() # or updateCamera will fail! def setKey(self, key, value): self.keyMap[key] = value def updateTask(self, task): self.updatePlayer() self.updateCamera() self.collTrav.traverse(self.render) for i in range(self.playerGroundHandler.getNumEntries()): entry = self.playerGroundHandler.getEntry(i) if self.debug == True: self.collisionLabel.setText("DEAD:" + str(globalClock.getFrameTime())) if self.exploding == False: self.player.setZ(entry.getSurfacePoint(self.render).getZ() + 10) self.explosionSequence() return Task.cont def resetPlayer(self): self.player.show() self.player.setPos(self.world, self.startPos) self.player.setHpr(self.world, self.startHpr) self.speed = self.maxspeed / 2 def updatePlayer(self): scalefactor = globalClock.getDt() * self.speed climbfactor = scalefactor * 0.5 bankfactor = scalefactor speedfactor = scalefactor * 2.9 gravityfactor = ((self.maxspeed - self.speed) / 100.0) * 2.0 # Climb and Fall if self.keyMap["climb"] != 0 and self.speed > 0.00: self.player.setZ(self.player.getZ() + climbfactor) self.player.setR(self.player.getR() + climbfactor) if (self.player.getR()) >= 180: self.player.setR(-180) elif self.keyMap["fall"] != 0 and self.speed > 0.00: self.player.setZ(self.player.getZ() - climbfactor) self.player.setR(self.player.getR() - climbfactor) if (self.player.getR()) <= -180: self.player.setR(180) elif self.player.getR() > 0: self.player.setR(self.player.getR() - (climbfactor + 0.1)) if self.player.getR() < 0: self.player.setR(0) elif self.player.getR() < 0: self.player.setR(self.player.getR() + (climbfactor + 0.1)) if self.player.getR() > 0: self.player.setR(0) # Left and Right if self.keyMap["left"] != 0 and self.speed > 0.0: self.player.setH(self.player.getH() + bankfactor) self.player.setP(self.player.getP() + bankfactor) # quickest return: if self.player.getP() >= 180: self.player.setP(-180) elif self.keyMap["right"] != 0 and self.speed > 0.0: self.player.setH(self.player.getH() - bankfactor) self.player.setP(self.player.getP() - bankfactor) if self.player.getP() <= -180: self.player.setP(180) # autoreturn elif self.player.getP() > 0: self.player.setP(self.player.getP() - (bankfactor + 0.1)) if self.player.getP() < 0: self.player.setP(0) elif self.player.getP() < 0: self.player.setP(self.player.getP() + (bankfactor + 0.1)) if self.player.getP() > 0: self.player.setP(0) # throttle control if self.keyMap["accelerate"] != 0: self.speed += 1 if self.speed > self.maxspeed: self.speed = self.maxspeed elif self.keyMap["decelerate"] != 0: self.speed -= 1 if self.speed < 0.0: self.speed = 0.0 # move forwards - our X/Y is inverted if self.exploding == False: self.player.setX(self.player, -speedfactor) self.applyBoundaries() if self.exploding == False: self.player.setX(self.player, -speedfactor) self.applyBoundaries() self.player.setZ(self.player, -gravityfactor) def applyBoundaries(self): # respect max camera distance else you # cannot see the floor post loop the loop! if self.player.getZ() > self.maxdistance: self.player.setZ(self.maxdistance) # should never happen once we add collision, but in case: elif self.player.getZ() < 0: self.player.setZ(0) # X/Y world boundaries: boundary = False if self.player.getX() < 0: self.player.setX(0) boundary = True elif self.player.getX() > self.worldsize: self.player.setX(self.worldsize) boundary = True if self.player.getY() < 0: self.player.setY(0) boundary = True elif self.player.getY() > self.worldsize: self.player.setY(self.worldsize) boundary = True if boundary == True and self.textCounter > 30: self.statusLabel.setText("STATUS: MAP END; TURN AROUND") elif self.textCounter > 30: self.statusLabel.setText("STATUS: OK") if self.textCounter > 30: self.textCounter = 0 else: self.textCounter += 1 def updateCamera(self): percent = self.speed / self.maxspeed self.camera.setPos(self.player, 19.6225 + (10 * percent), 3.8807, 10.2779) self.camera.setHpr(self.player, 94.8996, -12.6549, 1.55508) def setupCollisions(self): self.collTrav = CollisionTraverser() self.playerGroundSphere = CollisionSphere(0, 1.5, -1.5, 1.5) self.playerGroundCol = CollisionNode("playersphere") self.playerGroundCol.addSolid(self.playerGroundSphere) # bitmasks self.playerGroundCol.setFromCollideMask(BitMask32.bit(0)) self.playerGroundCol.setIntoCollideMask(BitMask32.allOff()) self.world.setCollideMask(BitMask32.bit(0)) self.playerGroundColNp = self.player.attachNewNode(self.playerGroundCol) self.playerGroundHandler = CollisionHandlerQueue() self.collTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler) self.water.setCollideMask(BitMask32.bit(0)) # Debug if self.debug == True: self.playerGroundColNp.show() self.collTrav.showCollisions(self.render) def explosionSequence(self): self.exploding = True self.explosionModel.setPosHpr( Vec3(self.player.getX(), self.player.getY(), self.player.getZ()), Vec3(self.player.getH(), 0, 0) ) self.player.hide() taskMgr.add(self.expandExplosion, "expandExplosion") def expandExplosion(self, Task): if self.explosionModel.getScale() < VBase3(60.0, 60.0, 60.0): factor = globalClock.getDt() scale = self.explosionModel.getScale() scale = scale + VBase3(factor * 40, factor * 40, factor * 40) self.explosionModel.setScale(scale) return Task.cont else: self.explosionModel.setScale(0) self.exploding = False self.resetPlayer()
class Swifter: def __init__(self, model, run, walk, idle, jump, crouch, crouchWalk, startPos, scale): #(self, model, run, walk, startPos, scale): """Initialise the character. Arguments: model -- The path to the character's model file (string) run : The path to the model's run animation (string) walk : The path to the model's walk animation (string) startPos : Where in the world the character will begin (pos) scale : The amount by which the size of the model will be scaled (float) """ #Define movement map and speeds self.speedSprint = 20 self.speedWalk = 7 self.speedCrouch = 5 self.speed = self.speedWalk #Capture control status self.isMoving = False self.isJumping = False self.isIdle = False self.isCrouching = False self.movementMap = {"forward":Vec3(0,-self.speed,0), "back":Vec3(0,self.speed,0), \ "left":Vec3(self.speed,0,0), "right":Vec3(-self.speed,0,0), \ "crouch":0, "sprint":0, "jump":1, "punch":0, "kick":0, "stop":Vec3(0), "changeView":0} #Set up key state variables self.strafe_left = self.movementMap["stop"] self.strafe_right = self.movementMap["stop"] self.forward = self.movementMap["stop"] self.back = self.movementMap["stop"] self.jump = False self.sprint = False self.crouch = False #Stop player by default self.walk = self.movementMap["stop"] self.strafe = self.movementMap["stop"] #Define the actor and his animations self.actor = Actor(model, {"run":run, "walk":walk, "idle":idle, "jump":jump, "crouch":crouch, "crouchWalk":crouchWalk}) #self.actor.enableBlend() self.actor.setBlend(frameBlend = True)#Enable interpolation self.actor.reparentTo(render) self.actor.setScale(scale) self.actor.setPos(startPos) #Set up FSM controller self.FSM = ActorFSM(self.actor) taskMgr.add(self.move,"moveTask") # Note: deriving classes DO NOT need # to add their own move tasks to the # task manager. If they override # self.move, then their own self.move # function will get called by the # task manager (they must then # explicitly call Character.move in # that function if they want it). self.prevtime = 0 # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above ralph's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.groundRay = CollisionRay() self.groundRay.setOrigin(0,0,1000) self.groundRay.setDirection(0,0,-1) self.groundCol = CollisionNode('actorRay') self.groundCol.addSolid(self.groundRay) self.groundCol.setFromCollideMask(BitMask32.bit(1)) self.groundCol.setIntoCollideMask(BitMask32.allOff()) self.groundColNp = self.actor.attachNewNode(self.groundCol) self.groundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.groundColNp, self.groundHandler) # Uncomment this line to see the collision rays self.groundColNp.show() #Uncomment this line to show a visual representation of the #collisions occuring self.cTrav.showCollisions(render) """ def jumpUpdate(self,task): # this task simulates gravity and makes the player jump # get the highest Z from the down casting ray highestZ = -100 for i in range(self.nodeGroundHandler.getNumEntries()): entry = self.nodeGroundHandler.getEntry(i) z = entry.getSurfacePoint(self.render).getZ() if z > highestZ and entry.getIntoNode().getName() == "Cube": highestZ = z # gravity effects and jumps self.node.setZ(self.node.getZ()+self.jump*globalClock.getDt()) self.jump -= 1*self.globalClock.getDt() if highestZ > self.node.getZ()-.3: self.jump = 0 self.node.setZ(highestZ+.3) if self.readyToJump: self.jump = 1 return task.cont """ def move(self, task): """Move and animate the character for one frame. This is a task function that is called every frame by Panda3D. The character is moved according to which of it's movement controls are set, and the function keeps the character's feet on the ground and stops the character from moving if a collision is detected. This function also handles playing the characters movement animations. Arguments: task -- A direct.task.Task object passed to this function by Panda3D. Return: Task.cont -- To tell Panda3D to call this task function again next frame. """ elapsed = task.time - self.prevtime # save the character's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.actor.getPos() #Calculate stateful movement self.walk = self.forward + self.back self.strafe = self.strafe_left + self.strafe_right # move the character if any of the move controls are activated. self.actor.setPos(self.actor,self.walk*globalClock.getDt()*self.speed) self.actor.setPos(self.actor,self.strafe*globalClock.getDt()*self.speed) #If strafing rotate the model -90 / 90 degrees to go in the direction specified #if going backwards rotate model 180 degrees # If the character is moving, loop the run animation. # If he is standing still, stop the animation. ##CALLL CONTROLLER CLASS AND CALL FSM's INSTEAD OF DOING IT HERE #Decide what type of movement anim to use if(self.sprint is True): #If we are sprinting.. self.walkAnim = 'Run' self.speed = self.speedSprint elif(self.crouch is True): # Can't sprint while crouching ;) #If we are crouching.. print ("Crouching!") self.walkAnim = "CrouchWalk" self.idleAnim = "Crouch" self.speed = self.speedCrouch else: #Otherwise were walking.. self.walkAnim = 'Walk' self.idleAnim = 'Idle' self.speed = self.speedWalk #Idling if(self.isJumping is False and self.isMoving is False and self.isIdle is True and self.FSM.state != self.idleAnim): #If were not moving and not jumping and were supposed to be idle, play the idle anim if we aren't already self.FSM.request(self.idleAnim,1) #We are idle, feel free to do something else, setting isIdle = False. print ("We are Idle but ready to do something: isIdle = False") elif(self.isJumping is False and self.isMoving is False and self.isIdle is False): #If were not moving or jumping, were not doing anything, we should probably be idle if we aren't already self.isIdle = True #locomotion #TODO: Separate out into animations for forward, back and side stepping if( (self.walk != self.movementMap["stop"] or self.strafe != self.movementMap["stop"]) and self.isJumping is False): #Check if actor is walking forward/back if(self.walk != self.movementMap["stop"]): if(self.isMoving is False or self.FSM.state != self.walkAnim): self.isMoving = True # were now moving self.isIdle = False # were not idle right now self.FSM.request(self.walkAnim,1) print ("Started running or walking") #Check if actor is strafing if(self.strafe != self.movementMap["stop"]): if(self.isMoving is False or self.FSM.state != self.walkAnim): #MAKE THE NODE ROTATE SO THE LEGS POINT THE DIRECTION MOVING #myLegRotate = actor.controlJoint(None,"modelRoot",) #http://www.panda3d.org/manual/index.php/Controlling_a_Joint_Procedurally self.isMoving = True # were now moving self.isIdle = False # were not idle right now self.FSM.request(self.walkAnim,1) print ("Started running or walking") elif(self.isMoving is True and self.isIdle is False): #Only switch of isMoving if we were moving and not idle self.isMoving = False print ("Finished walking") #if were moving, set isMoving = 1 and call walking FSM ''' Jumping Check if the user is jumping, if they currently aren't jumping: make them not idle and mark them as jumping and request the Jump FSM. If the jump anim isn't playing but we were jumping, mark actor as not jumping. ''' if(self.jump is True): #if user pressed jump and were not already jumping, jump if(self.isJumping is False and self.FSM.state != 'Jump'): self.isJumping = True # were jumping self.isIdle = False # were not idle right now self.FSM.request('Jump',1) print ("Started jumping") #if we are jumping, check the anim has finished and stop jumping self.JumpQuery = self.actor.getAnimControl('jump') if(self.isJumping is True and self.JumpQuery.isPlaying() is False): self.isJumping = False # finished jumping print ("Finished Jumping") # Now check for collisions. self.cTrav.traverse(render) # Adjust the character's Z coordinate. If the character's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.groundHandler.getNumEntries()): entry = self.groundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.actor.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.actor.setPos(startpos) # Store the task time and continue. self.prevtime = task.time return Task.cont def setMove(self, key, moveType): """ Used by keyboard setup This gets the input from keyBoardSetup and will capture inputs """ if (moveType == "strafe_left"): self.strafe_left = self.movementMap[key] if (moveType == "strafe_right"): self.strafe_right = self.movementMap[key] if (moveType == "forward"): self.forward = self.movementMap[key] if (moveType == "back"): self.back = self.movementMap[key] if (moveType == "sprint"): self.sprint = key if (moveType == "jump"): self.jump = key if (moveType == "crouch"): self.crouch = key
class MousePicker( gizmo_core.Object ): """ Class to represent a ray fired from the input camera lens using the mouse. """ def __init__( self, name, camera=None, rootNp=None, fromCollideMask=None, pickTag=None ): gizmo_core.Object.__init__( self, name, camera, rootNp ) self.fromCollideMask = fromCollideMask self.pickTag = pickTag self.selection = [] self.node = None self.collEntry = None # Create a marquee self.marquee = gizmo_core.Marquee( '%sMarquee' % self.name ) # Create collision nodes self.collTrav = CollisionTraverser() #self.collTrav.showCollisions( render ) self.collHandler = CollisionHandlerQueue() self.pickerRay = CollisionRay() # Create collision ray pickerNode = CollisionNode( self.name ) pickerNode.addSolid( self.pickerRay ) pickerNode.setIntoCollideMask( BitMask32.allOff() ) pickerNp = camera.attachNewNode( pickerNode ) self.collTrav.addCollider( pickerNp, self.collHandler ) # Create collision mask for the ray if one is specified if self.fromCollideMask is not None: pickerNode.setFromCollideMask( self.fromCollideMask ) # Bind mouse button events eventNames = ['mouse1', 'control-mouse1', 'mouse1-up'] for eventName in eventNames: self.accept( eventName, self.FireEvent, [eventName] ) def FireEvent( self, event ): # Send a message containing the node name and the event name, including # the collision entry as arguments if self.node is not None: messenger.send( '%s-%s' % ( self.node.getName(), event ), [self.collEntry] ) def UpdateTask( self, task ): # Traverse the hierarchy and find collisions self.collTrav.traverse( self.rootNp ) if self.collHandler.getNumEntries(): # If we have hit something, sort the hits so that the closest is first self.collHandler.sortEntries() collEntry = self.collHandler.getEntry( 0 ) node = collEntry.getIntoNode() # If this node is different to the last node, send a mouse leave # event to the last node, and a mouse enter to the new node if node != self.node: if self.node is not None: messenger.send( '%s-mouse-leave' % self.node.getName(), [self.collEntry] ) messenger.send( '%s-mouse-enter' % node.getName(), [collEntry] ) # Send a message containing the node name and the event over name, # including the collision entry as arguments messenger.send( '%s-mouse-over' % node.getName(), [collEntry] ) # Keep these values self.collEntry = collEntry self.node = node elif self.node is not None: # No collisions, clear the node and send a mouse leave to the last # node that stored messenger.send( '%s-mouse-leave' % self.node.getName(), [self.collEntry] ) self.node = None # Update the ray's position if base.mouseWatcherNode.hasMouse(): mp = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens( self.camera.node(), mp.getX(), mp.getY() ) return task.cont def StartSelection( self, clearSelection=True ): # Start the marquee self.marquee.Start() # Clear selection list if required if clearSelection: self.selection = [] def StopSelection( self ): # Stop the marquee self.marquee.Stop() nodes = [] for node in self.rootNp.findAllMatches( '**' ): if self.marquee.IsPoint3Inside( self.camera, self.rootNp, node.getPos() ): if self.pickTag is not None: if node.getTag( self.pickTag ): nodes.append( node ) else: nodes.append( node ) # Add any node which was under the mouse to the selection if self.collHandler.getNumEntries(): collEntry = self.collHandler.getEntry( 0 ) node = collEntry.getIntoNodePath().getParent() nodes.append( node ) # If the node was already in the selection then remove it, otherwise # add the node to the selection for node in nodes: if node in self.selection: self.selection.remove( node ) else: self.selection.append( node ) # Remove duplicated self.selection = list( set( self.selection ) )
class MouseEvents(DirectObject.DirectObject): def __init__(self): # from gameEngine import moveUnitsNext, moveUnitsPrev # self.accept('arrow_down', moveUnitsNext ) # self.accept('arrow_up', moveUnitsPrev ) self.accept('arrow_up-repeat', self.moveCameraUp) self.accept('arrow_up', self.moveCameraUp) self.accept('arrow_down-repeat', self.moveCameraDown) self.accept('arrow_down', self.moveCameraDown) self.accept('arrow_left-repeat', self.moveCameraLeft) self.accept('arrow_left', self.moveCameraLeft) self.accept('arrow_right-repeat', self.moveCameraRight) self.accept('arrow_right', self.moveCameraRight) # Initialize the traverser. self.myTraverser = CollisionTraverser() # Initialize the handler. self.myHandler = CollisionHandlerQueue() self.accept("escape", sys.exit) #Exit the program when escape is pressed base.disableMouse() self.pickerNode = CollisionNode('mouseRay') self.pickerNP = camera.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.myTraverser.addCollider(self.pickerNP, self.myHandler) ''' the player has to double click a star or planet in order to activate them ''' self.accept("mouse1", self.handleLeftMouseClick) self.accept("mouse3", self.handleRightMouseClick) self.accept("mouse1-up", self.handleMouseDrag) self.mouseFirstPos = None cm = CardMaker('quad') # cm.setFrameFullscreenQuad() self.drag_rect_path = base.render2d.attachNewNode(cm.generate()) self.drag_rect_path.setTransparency(TransparencyAttrib.MAlpha) self.drag_rect_path.setColor(Vec4(1,1,1,0.3)) self.drag_rect_path.hide() # self.drag_rect_path = LineNodePath(base.render2d, thickness = 8.0) def selectionRectangle(self, task): if base.mouseWatcherNode.hasMouse():# and self.mouseFirstPos != None: mpos = base.mouseWatcherNode.getMouse() self.drag_rect_path.show() self.drag_rect_path.setSx(mpos.getX()-self.mouseFirstPos.getX()+0.0001) self.drag_rect_path.setSz(mpos.getY()-self.mouseFirstPos.getY()+0.0001) self.drag_rect_path.setPos(self.mouseFirstPos.getX(), 0, self.mouseFirstPos.getY()) # self.drag_rect_path.drawLines([((self.mouseFirstPos.getX(),self.mouseFirstPos.getY()),(mpos.getX(), mpos.getY()))]) # self.drag_rect_path.create() # base.win.makeDisplayRegion(self.mouseFirstPos.getX(), self.mouseFirstPos.getY(), mpos.getX(), mpos.getY()) return task.cont def handleMouseDrag(self): if base.mouseWatcherNode.hasMouse(): if self.mouseFirstPos != None: mpos = base.mouseWatcherNode.getMouse() lvec = Vec2(self.mouseFirstPos) - Vec2(mpos) if lvec.length() > 0.01: scaled_pos = Point2(self.mouseFirstPos) scaled_pos.setX(scaled_pos.getX()*base.getAspectRatio()) scaled_mpos = Point2(mpos) scaled_mpos.setX(scaled_mpos.getX()*base.getAspectRatio()) for unit in self.player.selected_units: unit.deselect() del self.player.selected_units[:] for unit in self.player.units: if unit.is3dpointIn2dRegion(scaled_pos, scaled_mpos): unit.select() self.mouseFirstPos = None self.drag_rect_path.hide() taskMgr.remove(self.rect_task) def setPlayer(self, player): self.player = player def setCamera(self, camera): self.camera = camera def moveCameraUp(self): self.camera.camera_direction = "moveUp" def moveCameraDown(self): self.camera.camera_direction = "moveDown" def moveCameraLeft(self): self.camera.camera_direction = "moveLeft" def moveCameraRight(self): self.camera.camera_direction = "moveRight" def handleLeftMouseClick(self): if base.mouseWatcherNode.hasMouse(): #get the mouse position mpos = base.mouseWatcherNode.getMouse() self.savemousePos() # This makes the ray's origin the camera and makes the ray point # to the screen coordinates of the mouse. self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.myTraverser.traverse(render) # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue. if self.myHandler.getNumEntries() > 0: # This is so we get the closest object. self.myHandler.sortEntries() pickedObj = self.myHandler.getEntry(0).getIntoNodePath() if pickedObj.hasTag('star'): self.selected(pickedObj, 'star', 'pyStar', 'leftClick') elif pickedObj.hasTag('planet'): self.selected(pickedObj, 'planet', 'pyPlanet', 'leftClick') elif pickedObj.hasTag('unit'): self.selected(pickedObj, 'unit', 'pyUnit', 'leftClick') elif pickedObj.hasTag('testUnit'): self.selected(pickedObj, 'testUnit', 'pyTestUnit', 'leftClick') self.rect_task = taskMgr.add(self.selectionRectangle, 'drag') def savemousePos(self): self.mouseFirstPos = Point2(base.mouseWatcherNode.getMouse()) # self.mouseFirstPos.setX(self.mouseFirstPos.getX()*1.33) def handleRightMouseClick(self): if base.mouseWatcherNode.hasMouse(): #get the mouse position mpos = base.mouseWatcherNode.getMouse() # This makes the ray's origin the camera and makes the ray point # to the screen coordinates of the mouse. self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.myTraverser.traverse(render) # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue. if self.myHandler.getNumEntries() > 0: # This is so we get the closest object. self.myHandler.sortEntries() pickedObj = self.myHandler.getEntry(0).getIntoNodePath() #if pickedObj.hasTag('star'): # self.selected(pickedObj, 'star', 'pyStar') if pickedObj.hasTag('planet'): self.selected(pickedObj, 'planet', 'pyPlanet', 'rightClick') #elif pickedObj.hasTag('unit'): # self.selected(pickedObj, 'unit', 'pyUnit') def selected(self, pickedObj, tag, python_tag, click): # print 'Player has selected '+ tag + ' ' + pickedObj.getTag(tag) model_path = pickedObj.getParent() #model_path.notify("starSelected") model = model_path.getPythonTag(python_tag) if(click == 'rightClick'): model.selectRight(self.player) elif(click == 'leftClick' and tag == 'unit'): if(self.player == model.player): for unit in self.player.selected_units: unit.deselect() del self.player.selected_units[:] model.select() else: model.select(self.player)
class AreaMapper(object): def __init__(self, environment): ''' Create a map of the free space in a given area. ''' self.csRadius = 1 self.csHeight = 2 self.avatarRadius = 1.4 self.cs = CollisionSphere(0, 0, 0, 1) self.csNode = CollisionNode("AreaMapperCollisionSphere") self.csNode.setFromCollideMask(OTPGlobals.WallBitmask) self.csNode.setIntoCollideMask(BitMask32.allOff()) self.csNode.addSolid(self.cs) self.environment = environment self.csNodePath = self.environment.getTop().attachNewNode(self.csNode) self.floorRay = CollisionRay() self.floorRay.setDirection(0, 0, -1) self.floorRay.setOrigin(0, 0, 0) self.floorRayNode = CollisionNode("AreaMapperFloorRay") self.floorRayNode.setFromCollideMask(OTPGlobals.FloorBitmask) self.floorRayNode.setIntoCollideMask(BitMask32.allOff()) self.floorRayNode.addSolid(self.floorRay) self.floorRayNodePath = self.environment.getTop().attachNewNode( self.floorRayNode) self.chq = CollisionHandlerQueue() self.traverser = CollisionTraverser() self.startX = 0 self.startY = 0 self.startZ = 0 self.frontierSquares = {(0, 0): 1} self.frontierSquaresQueue = [(0, 0)] self.walkableSquares = {(0, 0): 1} self.blockedSquares = {} self.setSquareSize(2) self.startAtPlayerSpawn() self.visGeom = None self.visGN = None self.visNodePath = None self.triVertexLookup = {} self.triList = [] self.minX = 500 self.maxX = -500 self.minY = 500 self.maxY = -500 self.quadTree = QuadTree(width=1024) self.squares = [] self.runDiscovery(100000) self._subdivide() #self._fixZValues() self.csNodePath.removeNode() self.floorRayNodePath.removeNode() ## def _unstashEnvironment(self): ## # Would be nice if we could just do this :( ## #for np in self.environment.findAllMatches("**/+CollisionNode;+s"): ## # np.unstash() ## b = self.environment.builder ## for s in b.sections.values(): ## s.unstash() ## for o in b.largeObjects.values(): ## o.unstash() def setStart(self, x, y): self.startX = x self.startY = y self.startZ = self.findFloor(x, y) def startAtLocalAvatar(self): startPos = localAvatar.getPos(self.environment) self.setStart(startPos.getX(), startPos.getY()) def startAtPlayerSpawn(self): # XXX Bleugh, this is really pirates-specific. Nasty. for spawnPt in self.environment.world.getAllPlayerSpawnPts(): parentDoId = self.environment.world.uidMgr.getDoId(spawnPt[1]) if parentDoId == self.environment.doId: # Sweet, we found a spawn point for this grid's gamearea. Use it! z = self.findFloor(spawnPt[0][0], spawnPt[0][1]) if not self.isSphereBlocked(spawnPt[0][0], spawnPt[0][1], z): self.setStart(spawnPt[0][0], spawnPt[0][1]) return raise "No player spawn points found for the given game area! D:" def setSquareSize(self, size): self.squareSize = size self.csRadius = math.sqrt( 2 * (self.squareSize * self.squareSize / 4)) + self.avatarRadius self.csNodePath.setScale(self.environment, self.csRadius, self.csRadius, self.csRadius) self.csHeight = self.csRadius * 2 def findFloor(self, x, y): self.floorRayNodePath.setPos(self.environment, x, y, 50000) self.chq.clearEntries() self.traverser.clearColliders() self.traverser.addCollider(self.floorRayNodePath, self.chq) self.traverser.traverse(self.environment) highestZ = -50000 for e in self.chq.getEntries(): assert e.hasInto() assert e.getInto().isTangible() assert e.hasSurfacePoint() z = e.getSurfacePoint(self.environment).getZ() if z > highestZ: highestZ = z return highestZ def isSphereBlocked(self, x, y, z): if z < self.csHeight: return True self.csNodePath.setPos(self.environment, x, y, z) self.chq.clearEntries() self.traverser.clearColliders() self.traverser.addCollider(self.csNodePath, self.chq) self.traverser.traverse(self.environment) for entry in self.chq.getEntries(): if entry.hasInto(): if entry.getInto().isTangible(): return True return False def _neighbors(self, x, y): return [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] def _explore(self, p): x, y = p x1 = self.startX + self.squareSize * x y1 = self.startY + self.squareSize * y z1 = self.findFloor(x1, y1) if self.isSphereBlocked(x1, y1, z1 + self.csHeight): self.blockedSquares[p] = z1 return else: self.walkableSquares[p] = z1 self.quadTree.fill(x, y) for n in self._neighbors(x, y): if not (n in self.frontierSquares or n in self.walkableSquares or n in self.blockedSquares): self.frontierSquares[n] = 1 self.frontierSquaresQueue.append(n) def _exploreFrontier(self): if len(self.frontierSquaresQueue) == 0: assert len(self.frontierSquares.keys()) == 0 return 0 else: qlen = len(self.frontierSquaresQueue) for i in xrange(qlen): p = self.frontierSquaresQueue.pop(0) del self.frontierSquares[p] self._explore(p) return qlen def runDiscovery(self, maxSquares): print "Discovering walkable space (this will take 30-60 seconds)..." #self._unstashEnvironment() squaresExplored = 1 self.walkableSquares[(0, 0)] = self.findFloor(self.startX, self.startY) while (squaresExplored < maxSquares) and (len( self.frontierSquaresQueue) > 0): squaresExplored += self._exploreFrontier() ## def visualize(self): ## gFormat = GeomVertexFormat.getV3cp() ## self.vertexData = GeomVertexData("OMGVERTEXDATA", gFormat, Geom.UHDynamic) ## self.vertexWriter = GeomVertexWriter(self.vertexData, "vertex") ## self.colorWriter = GeomVertexWriter(self.vertexData, "color") ## numVerts = 0 ## for xa,ya,xb,yb in self.squares: ## x1 = self.startX + self.squareSize*(xa) - self.squareSize*0.5 ## y1 = self.startY + self.squareSize*(ya) - self.squareSize*0.5 ## x2 = self.startX + self.squareSize*(xb) + self.squareSize*0.5 ## y2 = self.startY + self.squareSize*(yb) + self.squareSize*0.5 ## self.vertexWriter.addData3f(x1,y1,self.findFloor(x1,y1)+0.1) ## self.colorWriter.addData4f(0.0, 1.0, 0.0, 0.5) ## self.vertexWriter.addData3f(x2,y1,self.findFloor(x2,y1)+0.1) ## self.colorWriter.addData4f(0.0, 1.0, 0.0, 0.5) ## self.vertexWriter.addData3f(x2,y2,self.findFloor(x2,y2)+0.1) ## self.colorWriter.addData4f(0.0, 1.0, 0.0, 0.5) ## self.vertexWriter.addData3f(x1,y2,self.findFloor(x1,y2)+0.1) ## self.colorWriter.addData4f(0.0, 1.0, 0.0, 0.5) ## numVerts += 4 ## print "NUMVERTS: ", numVerts ## self.pointVis = GeomLinestrips(Geom.UHStatic) ## for i in xrange(numVerts/4): ## self.pointVis.addVertex(i*4) ## self.pointVis.addVertex(i*4+1) ## self.pointVis.addVertex(i*4+2) ## self.pointVis.addVertex(i*4+3) ## self.pointVis.addVertex(i*4) ## self.pointVis.closePrimitive() ## self.visGeom = Geom(self.vertexData) ## self.visGeom.addPrimitive(self.pointVis) ## self.visGN = GeomNode("NavigationGridVis") ## self.visGN.addGeom(self.visGeom) ## self.visNodePath = self.environment.attachNewNode(self.visGN) ## self.visNodePath.setTwoSided(True) ## self.visNodePath.setRenderModeThickness(4) ## #self.visNodePath.setTransparency(1) # ---------- Begin Triangulation Code ------------ ## def _addTriVertex(self,x,y): ## ''' ## lookup[(x,y)] is a reference to the vert located to the UPPER-LEFT of grid square (x,y) ## ''' ## if (x,y) not in self.gridCoordToVertexId: ## vId = self.vertexCounter ## self.vertexCounter += 1 ## self.gridCoordToVertexId[(x,y)] = vId ## x1 = self.startX + self.squareSize*x - (0.5 * self.squareSize) ## y1 = self.startY + self.squareSize*y - (0.5 * self.squareSize) ## z1 = self.findFloor(x1,y1) ## self.vertexIdToXYZ[vId] = (x1,y1,z1) ## self.vertexToTris[vId] = [] ## return self.gridCoordToVertexId[(x,y)] ## def _triangulateGridSquare(self,x,y,left=True): ## a = self._addTriVertex(x,y) ## b = self._addTriVertex(x+1,y) ## c = self._addTriVertex(x+1,y+1) ## d = self._addTriVertex(x,y+1) ## if x < self.minX: ## self.minX = x ## if x > self.maxX: ## self.maxX = x ## if y < self.minY: ## self.minY = y ## if y > self.maxY: ## self.maxY = y ## if left: ## self.triToVertices[self.triCounter] = [a,b,d] ## self.triToAngles[self.triCounter] = [90,45,45] ## self.triToVertices[self.triCounter+1] = [b,c,d] ## self.triToAngles[self.triCounter+1] = [45,90,45] ## self.vertexToTris[a].append(self.triCounter) ## self.vertexToTris[b].append(self.triCounter) ## self.vertexToTris[b].append(self.triCounter+1) ## self.vertexToTris[c].append(self.triCounter+1) ## self.vertexToTris[d].append(self.triCounter) ## self.vertexToTris[d].append(self.triCounter+1) ## else: ## self.triToVertices[self.triCounter] = [a,b,c] ## self.triToAngles[self.triCounter] = [45,90,45] ## self.triToVertices[self.triCounter+1] = [a,c,d] ## self.triToAngles[self.triCounter+1] = [45,45,90] ## self.vertexToTris[a].append(self.triCounter) ## self.vertexToTris[a].append(self.triCounter+1) ## self.vertexToTris[b].append(self.triCounter) ## self.vertexToTris[c].append(self.triCounter) ## self.vertexToTris[c].append(self.triCounter+1) ## self.vertexToTris[d].append(self.triCounter+1) ## self.triCounter += 2 ## def countCruft(self): ## count = 0 ## for s in self.squares: ## if (s[0] == s[2]) and (s[1] == s[3]): ## x = s[0] ## y = s[1] ## numNeighbors = 0 ## for (x1,y1) in [(x+1,y),(x-1,y),(x,y+1),(x,y-1)]: ## if (x1,y1) in self.walkableSquares: ## numNeighbors += 1 ## if numNeighbors < 3: ## count += 1 ## return count ## def killCruft(self): ## for i in xrange(len(self.squares)): ## s = self.squares[i] ## if (s[0] == s[2]) and (s[1] == s[3]): ## x = s[0] ## y = s[1] ## numNeighbors = 0 ## for (x1,y1) in [(x+1,y),(x-1,y),(x,y+1),(x,y-1)]: ## if (x1,y1) in self.walkableSquares: ## numNeighbors += 1 ## if numNeighbors < 3: ## self.squares[i] = None ## self.squares = [s for s in self.squares if s != None] def _addVertexByGridCoords(self, x, y): ''' lookup[(x,y)] is a reference to the vert located at (-0.5,-0.5) from grid square (x,y) ''' if (x, y) not in self.gridCoordToVertexId: vId = self.vertexCounter self.vertexCounter += 1 self.gridCoordToVertexId[(x, y)] = vId x1 = self.startX + self.squareSize * x - (0.5 * self.squareSize) y1 = self.startY + self.squareSize * y - (0.5 * self.squareSize) z1 = self.findFloor(x1, y1) self.vertexIdToXYZ[vId] = (x1, y1, z1) self.vertToPolys[vId] = [] return self.gridCoordToVertexId[(x, y)] def _addOpenSquare(self, gridX1, gridY1, gridX2, gridY2): curSpot = [gridX1, gridY1] verts = [] angles = [] while curSpot[0] <= gridX2: verts.append(self._addVertexByGridCoords(curSpot[0], curSpot[1])) if curSpot[0] == gridX1: angles.append(90) else: angles.append(180) self.vertToPolys[verts[-1]].append(self.polyCounter) curSpot[0] += 1 while curSpot[1] <= gridY2: verts.append(self._addVertexByGridCoords(curSpot[0], curSpot[1])) if curSpot[1] == gridY1: angles.append(90) else: angles.append(180) self.vertToPolys[verts[-1]].append(self.polyCounter) curSpot[1] += 1 while curSpot[0] > gridX1: verts.append(self._addVertexByGridCoords(curSpot[0], curSpot[1])) if curSpot[0] == gridX2 + 1: angles.append(90) else: angles.append(180) self.vertToPolys[verts[-1]].append(self.polyCounter) curSpot[0] -= 1 while curSpot[1] > gridY1: if curSpot[1] == gridY2 + 1: angles.append(90) else: angles.append(180) verts.append(self._addVertexByGridCoords(curSpot[0], curSpot[1])) self.vertToPolys[verts[-1]].append(self.polyCounter) curSpot[1] -= 1 self.polyToVerts[self.polyCounter] = verts self.polyToAngles[self.polyCounter] = angles self.polyCounter += 1 def _subdivide(self): print "Growing squares..." self.vertexCounter = 0 self.polyCounter = 0 self.gridCoordToVertexId = {} self.vertexIdToXYZ = {} self.polyToVerts = {} self.polyToAngles = {} self.vertToPolys = {} self.squares = self.quadTree.squarify() for (gridX1, gridY1, gridX2, gridY2) in self.squares: self._addOpenSquare(gridX1, gridY1, gridX2, gridY2)
class Game3T(ShowBase): def __init__(self): ShowBase.__init__(self) #base.setFrameRateMeter(True) OnscreenText(text='3T', pos=(0, 0.85), scale=0.2, fg=(0.3, 0.2, 8, 1)) OnscreenText(text='by: Hellmaster - 2011', pos=(0, -0.9), scale=0.1, fg=(0.5, 0, 8, 1)) FPS = 30 globalClock = ClockObject.getGlobalClock() globalClock.setMode(ClockObject.MLimited) globalClock.setFrameRate(FPS) # ***************** SETUP SHITS ***************** base.disableMouse() self.nextmove = True self.camera_plane_angle = 0 # ***************** LOAD GAME LOGIC AND OTHERS CLASSES ************* self.game = gameMecahnics() # ***************** LOAD MODELS AND SOUNDS ****************** self.loadModels() self.loadSounds() # ***************** SELECT PLAYER ****************** self.a = getPlayer() base.taskMgr.add(self.selectPlayer, "selectPlayer") def rotateCamera(self, task): dt = globalClock.getDt() self.camera_plane_angle += dt if self.camera_plane_angle > 360: self.camera_plane_angle = 0 self.cam.setPos(30 * math.cos(self.camera_plane_angle), 30 * math.sin(self.camera_plane_angle), 30) self.cam.lookAt(0, 0, 0) return task.cont def selectPlayer(self, task): self.player = self.a.getSelectedPlayer() if self.player != None: #print "player selectecd" base.taskMgr.add(self.gameLoop, "gameLoop") return task.done return task.cont def gameLoop(self, task): #print "game task" # ***************** SET CAMERA ****************** base.taskMgr.add(self.rotateCamera, "rotateCamera") self.game.setPlayer(self.player) # ***************** PICKABLE SHITS *************** # setup the pickable suqre planes on the board planes = [] id_plane = 0 for k in range(3): for i in range(3): #print "adding plane: ", id_plane p = addPlane(3) p.setPos(3 * i - 2.5, 3 * k - 2.5, 3.1) p.setTag('pickable', str(id_plane)) p.hide() planes.append(p) id_plane += 1 # set picks pickerNode = CollisionNode('mouseRay') pickerNP = self.cam.attachNewNode(pickerNode) pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.pickerRay = CollisionRay() pickerNode.addSolid(self.pickerRay) #pickerNP.show() self.rayQueue = CollisionHandlerQueue() self.cTrav = CollisionTraverser() self.cTrav.addCollider(pickerNP, self.rayQueue) # set action in case of pick self.accept('mouse1', self.picked) def loadModels(self): self.arena = loader.loadModel("models/arena/arena") self.arena.reparentTo(render) self.arena.setPos(0, 0, 0) self.playero = loader.loadModel("models/players/o") self.playerx = loader.loadModel("models/players/x") def loadSounds(self): self.sound1 = loader.loadSfx("sounds/sound1.ogg") self.sound2 = loader.loadSfx("sounds/sound2.ogg") # detects if mouse picks some shit # if yes => set piece if valid and must wait 3 seconds for next move else do shit def picked(self): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.cTrav.traverse(render) if self.rayQueue.getNumEntries() > 0: self.rayQueue.sortEntries() pickedNP = self.rayQueue.getEntry(0).getIntoNodePath() if pickedNP.hasNetTag('pickable'): if self.nextmove: #print "picked: ", pickedNP, " | id 1: ", pickedNP.findNetTag('pickable'), " id 2: ", pickedNP.getNetTag('pickable') move = int(pickedNP.getNetTag('pickable')) if self.game.isValidMove(move): #print "------VALID------", move self.putPieceIN(move) self.game.setMove(move) self.nextmove = False #else: #print "------INVALID------" #self.game.printBoard() def changeNextMoveValue(self, task): self.nextmove = True return task.done def putPieceIN(self, pos): if self.game.getCurrentPlayer() == 'o': self.newPiece = self.playero.copyTo(render) else: self.newPiece = self.playerx.copyTo(render) base.taskMgr.add(self.falling, "falling") if pos == 0: self.newPiece.setPos(-3, -3, STARTING_Z) return 0 if pos == 1: self.newPiece.setPos(0, -3, STARTING_Z) return 0 if pos == 2: self.newPiece.setPos(3, -3, STARTING_Z) return 0 if pos == 3: self.newPiece.setPos(-3, 0, STARTING_Z) return 0 if pos == 4: self.newPiece.setPos(0, 0, STARTING_Z) return 0 if pos == 5: self.newPiece.setPos(3, 0, STARTING_Z) return 0 if pos == 6: self.newPiece.setPos(-3, 3, STARTING_Z) return 0 if pos == 7: self.newPiece.setPos(0, 3, STARTING_Z) return 0 if pos == 8: self.newPiece.setPos(3, 3, STARTING_Z) return 0 return -1 def falling(self, task): dt = globalClock.getDt() self.newPiece.setZ(self.newPiece.getZ() - dt * 10) if self.newPiece.getZ() < 3: self.nextmove = True if self.game.isWinner() or self.game.isOver(): self.gameOver() else: self.game.setNextPlayer() if self.game.getCurrentPlayer() == 'o': self.sound1.play() else: self.sound2.play() return task.done return task.cont def gameOver(self): #print "--------------------------" #print "-------- GAME OVER -------" #print "--------------------------" if self.game.isWinner(): printWinner(self.game.getCurrentPlayer()) else: printWinner(None) print "--------------------------" button_exit = DirectButton(text='Exit Game', pos=(0, 0, -0.4), scale=0.1, command=exitProg)
class Camera: """A floating 3rd person camera that follows an actor around, and can be turned left or right around the actor. Public fields: self.controlMap -- The camera's movement controls. actor -- The Actor object that the camera will follow. Public functions: init(actor) -- Initialise the camera. move(task) -- Move the camera each frame, following the assigned actor. This task is called every frame to update the camera. setControl -- Set the camera's turn left or turn right control on or off. """ def __init__(self, actor): """Initialise the camera, setting it to follow 'actor'. Arguments: actor -- The Actor that the camera will initially follow. """ self.actor = actor self.prevtime = 0 # The camera's controls: # "left" = move the camera left, 0 = off, 1 = on # "right" = move the camera right, 0 = off, 1 = on self.controlMap = {"left": 0, "right": 0} taskMgr.add(self.move, "cameraMoveTask") # Create a "floater" object. It is used to orient the camera above the # target actor's head. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Set up the camera. base.disableMouse() base.camera.setPos(self.actor.getX(), self.actor.getY() + 2, 2) # uncomment for topdown #base.camera.setPos(self.actor.getX(),self.actor.getY()+10,2) #base.camera.setHpr(180, -50, 0) # A CollisionRay beginning above the camera and going down toward the # ground is used to detect camera collisions and the height of the # camera above the ground. A ray may hit the terrain, or it may hit a # rock or a tree. If it hits the terrain, we detect the camera's # height. If it hits anything else, the camera is in an illegal # position. self.cTrav = CollisionTraverser() self.groundRay = CollisionRay() self.groundRay.setOrigin(0, 0, 1000) self.groundRay.setDirection(0, 0, -1) self.groundCol = CollisionNode('camRay') self.groundCol.addSolid(self.groundRay) self.groundCol.setFromCollideMask(BitMask32.bit(1)) self.groundCol.setIntoCollideMask(BitMask32.allOff()) self.groundColNp = base.camera.attachNewNode(self.groundCol) self.groundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.groundColNp, self.groundHandler) # Uncomment this line to see the collision rays #self.groundColNp.show() def move(self, task): """Update the camera's position before rendering the next frame. This is a task function and is called each frame by Panda3D. The camera follows self.actor, and tries to remain above the actor and above the ground (whichever is highest) while looking at a point slightly above the actor's head. Arguments: task -- A direct.task.Task object passed to this function by Panda3D. Return: Task.cont -- To tell Panda3D to call this task function again next frame. """ # FIXME: There is a bug with the camera -- if the actor runs up a # hill and then down again, the camera's Z position follows the actor # up the hill but does not come down again when the actor goes down # the hill. elapsed = task.time - self.prevtime # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. # comment out for topdown base.camera.lookAt(self.actor) camright = base.camera.getNetTransform().getMat().getRow3(0) camright.normalize() if (self.controlMap["left"] != 0): base.camera.setPos(base.camera.getPos() - camright * (elapsed * 20)) if (self.controlMap["right"] != 0): base.camera.setPos(base.camera.getPos() + camright * (elapsed * 20)) # If the camera is too far from the actor, move it closer. # If the camera is too close to the actor, move it farther. camvec = self.actor.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 10.0): base.camera.setPos(base.camera.getPos() + camvec * (camdist - 10)) camdist = 10.0 if (camdist < 5.0): base.camera.setPos(base.camera.getPos() - camvec * (5 - camdist)) camdist = 5.0 # Now check for collisions. self.cTrav.traverse(render) # Keep the camera at one foot above the terrain, # or two feet above the actor, whichever is greater. # comment out for topdown entries = [] for i in range(self.groundHandler.getNumEntries()): entry = self.groundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x, y: cmp( y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0) if (base.camera.getZ() < self.actor.getZ() + 2.0): base.camera.setZ(self.actor.getZ() + 2.0) # The camera should look in the player's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above the player's head. self.floater.setPos(self.actor.getPos()) self.floater.setZ(self.actor.getZ() + 2.0) #self.floater.setZ(self.actor.getZ() + 10.0) #self.floater.setY(self.actor.getY() + 7.0) # comment out for topdown base.camera.lookAt(self.floater) base.camera.setPos(self.floater.getPos()) # Store the task time and continue. self.prevtime = task.time return Task.cont def setControl(self, control, value): """Set the state of one of the camera's movement controls. Arguments: See self.controlMap in __init__. control -- The control to be set, must be a string matching one of the strings in self.controlMap. value -- The value to set the control to. """ # FIXME: this function is duplicated in Camera and Character, and # keyboard control settings are spread throughout the code. Maybe # add a Controllable class? self.controlMap[control] = value
class cWorld: def __init__(self): # set background color base.setBackgroundColor(0, 0, 0) # create target self.createTarget() # create boids self.createBoids() # setup camera self.setupCamera() # setup lights self.setupLights() # setup collision detection self.setupCollision() # add task taskMgr.add(self.steer, 'steer') # steer task taskMgr.add(self.moveTarget, 'moveTarget') # mouse move target task def createBoids(self): self.redBoid = cBoid() # create red boid # setup blue boid with model path, starting location, max force, and max speed self.redBoid.setup('assets/models/boid_one.egg', Vec3(0.0, 0.0, 0.0), 4.0, 0.1) # create blue boid self.blueBoid = cBoid() # setup blue boid with model path, starting location, max force, and max speed self.blueBoid.setup('assets/models/boid_two.egg', Vec3(0.0, 0.0, 0.0), 4.0, 1.0) def createTarget(self): # load in model file self.target = loader.loadModel('assets/models/target.egg') # parent self.target.reparentTo(render) # set location self.target.setPos(Vec3(0.0, 0.0, 0.0)) def setupCamera(self): # disable auto controls base.disableMouse() # set position, heading, pitch, and roll camera.setPosHpr(Vec3(0.0, -45.0, 45.0), Vec3(0.0, -45.0, 0)) def setupLights(self): # create a point light plight = PointLight('plight') # set its color plight.setColor(VBase4(1.0, 1.0, 1.0, 1)) # attach the light to the render plnp = render.attachNewNode(plight) # set position plnp.setPos(0.0, 0.0, 2.0) # turn on light render.setLight(plnp) def setupCollision(self): # create collision traverser self.picker = CollisionTraverser() # create collision handler self.pq = CollisionHandlerQueue() # create collision node self.pickerNode = CollisionNode('mouseRay') # create collision node # attach new collision node to camera node self.pickerNP = camera.attachNewNode( self.pickerNode) # attach collision node to camera # set bit mask to one self.pickerNode.setFromCollideMask(BitMask32.bit(1)) # set bit mask # create a collision ray self.pickerRay = CollisionRay() # create collision ray # add picker ray to the picker node self.pickerNode.addSolid( self.pickerRay) # add the collision ray to the collision node # make the traverser know about the picker node and its even handler queue self.picker.addCollider( self.pickerNP, self.pq) # add the colision node path and collision handler queue #self.picker.showCollisions( render ) # render or draw the collisions #self.pickerNP.show( ) # render picker ray # create col node self.colPlane = CollisionNode('colPlane') # add solid to col node plane self.colPlane.addSolid( CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0)))) # attach new node to the render self.colPlanePath = render.attachNewNode(self.colPlane) #self.colPlanePath.show( ) # render node # make the col plane look at the camera # this makes it alway look at the camera no matter the orientation # we need this because the ray nees to intersect a plane parallel # to the camera self.colPlanePath.lookAt(camera) # prop up the col plane self.colPlanePath.setP(-45) # set bit mask to one # as I understand it, this makes all col nodes with bit mask one # create collisions while ignoring others of other masks self.colPlanePath.node().setIntoCollideMask(BitMask32.bit(1)) def steer(self, Task): # seek after target self.redBoid.seek(Vec3(self.target.getPos())) # run the algorithm self.redBoid.run() # arrive at the target self.blueBoid.arrive(Vec3(self.target.getPos())) # run the algorithm self.blueBoid.run() return Task.cont # continue task def moveTarget(self, Task): # traverse through the render tree self.picker.traverse(render) # go through the queue of collisions for i in range(self.pq.getNumEntries()): entry = self.pq.getEntry(i) # get entry surfacePoint = entry.getSurfacePoint( render) # get surface point of collision self.target.setPos( surfacePoint) # set surface point to target's position if base.mouseWatcherNode.hasMouse(): # if we have a mouse mpos = base.mouseWatcherNode.getMouse( ) # get the path to the mouse # shoot ray from camera # based on X & Y coordinate of mouse self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) return Task.cont # continue task
class DemoGame(ShowBase): def __init__(self): ShowBase.__init__(self) self.debug = False self.status_label = self.makeStatusLabel(0) self.collision_label = self.makeCollisionLabel(1) # terrain = GeoMipTerrain("worldTerrain") # terrain.setHeightfield("models/height_map.png") # terrain.setColorMap("models/colour_map_flipped.png") # terrain.setBruteforce(True) # root = terrain.getRoot() # root.reparentTo(render) # root.setSz(60) # terrain.generate() # root.writeBamFile("models/world.bam") self.world = self.loader.loadModel("models/world.bam") self.world.reparentTo(self.render) self.world_size = 1024 self.player = self.loader.loadModel("models/alliedflanker") # alliedflanker.egg by default self.max_speed = 100.0 self.start_pos = Vec3(200, 200, 65) self.start_hpr = Vec3(225, 0, 0) self.player.setScale(0.2, 0.2, 0.2) self.player.reparentTo(self.render) self.resetPlayer() self.taskMgr.add(self.updateTask, "update") self.keyboardSetup() self.max_distance = 400 if not self.debug: self.camLens.setFar(self.max_distance) else: base.oobe() self.camLens.setFov(60) self.createEnvironment() self.setupCollisions() self.text_counter = 0 # load the explosion ring self.explosion_model = loader.loadModel("models/explosion") # Panda3D Defaults to '.egg' self.explosion_model.reparentTo(self.render) self.explosion_model.setScale(0.0) self.explosion_model.setLightOff() # Only one explosion at a time self.exploding = False def makeStatusLabel(self, i): return OnscreenText(style=2, fg=(0.5, 1, 0.5, 1), pos=(-1.3, 0.92, (-0.08 * i)), align=TextNode.ALeft, scale=0.08, mayChange=1) def makeCollisionLabel(self, i): return OnscreenText(style=2, fg=(0.5, 1, 0.5, 1), pos=(-1.3, 0.92, (-0.08 * i)), align=TextNode.ALeft, scale=0.08, mayChange=1) def resetPlayer(self): self.player.show() self.player.setPos(self.world, self.start_pos) self.player.setHpr(self.world, self.start_hpr) self.speed = self.max_speed / 2 def keyboardSetup(self): self.keyMap = {"left": 0, "right": 0, "climb": 0, "fall": 0, "accelerate": 0, "decelerate": 0, "fire": 0} self.accept("escape", sys.exit) self.accept("a", self.setKey, ["accelerate", 1]) self.accept("a-up", self.setKey, ["accelerate", 0]) self.accept("z", self.setKey, ["decelerate", 1]) self.accept("z-up", self.setKey, ["decelerate", 0]) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_down", self.setKey, ["climb", 1]) self.accept("arrow_down-up", self.setKey, ["climb", 0]) self.accept("arrow_up", self.setKey, ["fall", 1]) self.accept("arrow_up-up", self.setKey, ["fall", 0]) self.accept("space", self.setKey, ["fire", 1]) self.accept("space-up", self.setKey, ["fire", 0]) base.disableMouse() # or updateCamera will fail! def setKey(self, key, value): self.keyMap[key] = value def updateTask(self, task): self.updatePlayer() self.updateCamera() self.coll_trav.traverse(self.render) for i in range(self.player_ground_handler.getNumEntries()): entry = self.player_ground_handler.getEntry(i) if self.debug: self.collision_label.setText("dead:"+str(globalClock.getFrameTime())) if not self.exploding: self.player.setZ(entry.getSurfacePoint(self.render).getZ() + 10) self.explosionSequence() return Task.cont def explosionSequence(self): self.exploding = True pos = Vec3(self.player.getX(), self.player.getY(), self.player.getZ()) hpr = Vec3(self.player.getH(), 0, 0) self.explosion_model.setPosHpr(pos, hpr) self.player.hide() taskMgr.add(self.expandExplosion, "expandExplosion") def expandExplosion(self, Task): if self.explosion_model.getScale() < VBase3(60.0, 60.0, 60.0): factor = globalClock.getDt() scale = self.explosion_model.getScale() scale += VBase3(factor*40, factor*40, factor*40) self.explosion_model.setScale(scale) return Task.cont else: self.explosion_model.setScale(0) self.exploding = False self.resetPlayer() def updatePlayer(self): # Global Clock # by default, panda runs as fast as it can frame by frame scale_factor = (globalClock.getDt()*self.speed) climb_factor = scale_factor * 0.5 bank_factor = scale_factor speed_factor = scale_factor * 2.9 gravity_factor = 2 * (self.max_speed - self.speed) / 100 # Climb and Fall if self.keyMap["climb"] != 0 and self.speed > 0.00: # The faster you go, the faster you climb self.player.setZ(self.player.getZ() + climb_factor) self.player.setR(self.player.getR() + climb_factor) # quickest return: avaoids uncoil/unwind if (self.player.getR() >= 180): self.player.setR(-180) elif self.keyMap["fall"] != 0 and self.speed > 0.00: self.player.setZ(self.player.getZ() - climb_factor) self.player.setR(self.player.getR() - climb_factor) # quickest return if (self.player.getR() <= -180): self.player.setR(180) # autoreturn - add a bit regardless to make sure it happens elif self.player.getR() > 0: self.player.setR(self.player.getR() - (climb_factor + 0.1)) if self.player.getR() < 0: self.player.setR(0) elif self.player.getR() < 0: self.player.setR(self.player.getR() + (climb_factor + 0.1)) if self.player.getR() > 0: self.player.setR(0) # Left and Right if self.keyMap["left"] != 0 and self.speed > 0.0: self.player.setH(self.player.getH() + bank_factor) self.player.setP(self.player.getP() + bank_factor) if self.player.getP() >= 180: self.player.setP(-180) elif self.keyMap["right"] != 0 and self.speed > 0.0: self.player.setH(self.player.getH() - bank_factor) self.player.setP(self.player.getP() - bank_factor) if self.player.getP() <= -180: self.player.setP(180) elif self.player.getP() > 0: self.player.setP(self.player.getP() - (bank_factor + 0.1)) if self.player.getP() < 0: self.player.setP(0) elif self.player.getP() < 0: self.player.setP(self.player.getP() + (bank_factor + 0.1)) if self.player.getP() > 0: self.player.setP(0) # throttle control if self.keyMap["accelerate"] != 0: self.speed += 1 if self.speed > self.max_speed: self.speed = self.max_speed elif self.keyMap["decelerate"] != 0: self.speed -= 1 if self.speed < 0.0: self.speed = 0.0 # move forwards - our X/Y is inverted if not self.exploding: self.player.setX(self.player, -speed_factor) self.applyBoundaries() self.player.setZ(self.player, -gravity_factor) def applyBoundaries(self): # respet max camera distance else you # cannot see the floor post loop the loop if self.player.getZ() > self.max_distance: self.player.setZ(self.max_distance) # should never happen once we add collusion, but in case: elif self.player.getZ() < 0: self.player.setZ(0) boundary = False # and now the X/Y world boundaries: if self.player.getX() < 0: self.player.setX(0) boundary = True elif self.player.getX() > self.world_size: self.player.setX(self.world_size) boundary = True if self.player.getY() < 0: self.player.setY(0) boundary = True elif self.player.getY() > self.world_size: self.player.setY(self.world_size) boundary = True # Avoid doing this every frame if boundary and self.text_counter > 30: self.status_label.setText("STATUS: MAP END; TURN AROUND") elif self.text_counter > 30: self.status_label.setText("STATUS: OK") if self.text_counter > 30: self.text_counter = 0 else: self.text_counter += 1 def updateCamera(self): self.camera.setPos(self.player, 25.6225, 3.8807, 10.2779) self.camera.setHpr(self.player, 94.8996, -16.6549, 1.55508) def createEnvironment(self): # Fog to hide a performance tweak exp_fog = Fog("scene-wide-fog") exp_fog.setColor(1, 0.8, 0.8) exp_fog.setExpDensity(0.002) render.setFog(exp_fog) # base.setBackgroundColor(*colour) # Sky Dome ''' sky_dome = loader.loadModel("models/sky") # sky_sphere.egg by default sky_dome.setEffect(CompassEffect.make(self.render)) sky_dome.setScale(self.max_distance / 2) sky_dome.setZ(-65) # sink it # NOT render - you'll fly through the sky! sky_dome.reparentTo(self.camera) ''' # Sky Sphere sky_sphere = self.loader.loadModel("models/sky_sphere") sky_sphere.setEffect(CompassEffect.make(self.render)) sky_sphere.setScale(0.08) sky_sphere.reparentTo(self.camera) # Lighting ambient_light = AmbientLight("ambientLight") ambient_colour = Vec4(0.6, 0.6, 0.6, 1) ambient_light.setColor(ambient_colour) self.render.setLight(self.render.attachNewNode(ambient_light)) directional_light = DirectionalLight("directionalLight") # direction = Vec3(0, -10, -10) # directional_light.setDirection(direction) directional_colour = Vec4(0.8, 0.8, 0.5, 1) directional_light.setColor(directional_colour) # directional_specular = Vec4(1, 1, 1, 1) # directional_light.setSpecularColor(directional_specular) dir_light_np = self.render.attachNewNode(directional_light) dir_light_np.setPos(0, 0, 260) dir_light_np.lookAt(self.player) self.render.setLight(dir_light_np) # Water self.water = self.loader.loadModel("models/square") self.water.setSx(self.world_size*2) self.water.setSy(self.world_size*2) self.water.setPos(self.world_size/2, self.world_size/2, 25) # z is sea level self.water.setTransparency(TransparencyAttrib.MAlpha) newTS = TextureStage("1") self.water.setTexture(newTS, self.loader.loadTexture("models/water.png")) self.water.setTexScale(newTS, 4) self.water.reparentTo(self.render) LerpTexOffsetInterval(self.water, 200, (1,0), (0,0), textureStage=newTS).loop() def setupCollisions(self): self.coll_trav = CollisionTraverser() self.player_ground_sphere = CollisionSphere(0, 1.5, -1.5, 1.5) self.player_ground_col = CollisionNode('playerSphere') self.player_ground_col.addSolid(self.player_ground_sphere) # bitmasks self.player_ground_col.setFromCollideMask(BitMask32.bit(0)) self.player_ground_col.setIntoCollideMask(BitMask32.allOff()) self.world.setCollideMask(BitMask32.bit(0)) self.water.setCollideMask(BitMask32.bit(0)) # and done self.player_ground_col_np = self.player.attachNewNode(self.player_ground_col) self.player_ground_handler = CollisionHandlerQueue() self.coll_trav.addCollider(self.player_ground_col_np, self.player_ground_handler) # DEBUG if self.debug: self.player_ground_col_np.show() self.coll_trav.showCollisions(self.render)
class CogdoFlyingCameraManager: def __init__(self, cam, parent, player, level): self._toon = player.toon self._camera = cam self._parent = parent self._player = player self._level = level self._enabled = False def enable(self): if self._enabled: return self._toon.detachCamera() self._prevToonY = 0.0 levelBounds = self._level.getBounds() l = Globals.Camera.LevelBoundsFactor self._bounds = ((levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]), (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]), (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2])) self._lookAtZ = self._toon.getHeight( ) + Globals.Camera.LookAtToonHeightOffset self._camParent = NodePath('CamParent') self._camParent.reparentTo(self._parent) self._camParent.setPos(self._toon, 0, 0, 0) self._camParent.setHpr(180, Globals.Camera.Angle, 0) self._camera.reparentTo(self._camParent) self._camera.setPos(0, Globals.Camera.Distance, 0) self._camera.lookAt(self._toon, 0, 0, self._lookAtZ) self._cameraLookAtNP = NodePath('CameraLookAt') self._cameraLookAtNP.reparentTo(self._camera.getParent()) self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr()) self._levelBounds = self._level.getBounds() self._enabled = True self._frozen = False self._initCollisions() def _initCollisions(self): self._camCollRay = CollisionRay() camCollNode = CollisionNode('CameraToonRay') camCollNode.addSolid(self._camCollRay) camCollNode.setFromCollideMask(OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask) camCollNode.setIntoCollideMask(0) self._camCollNP = self._camera.attachNewNode(camCollNode) self._camCollNP.show() self._collOffset = Vec3(0, 0, 0.5) self._collHandler = CollisionHandlerQueue() self._collTrav = CollisionTraverser() self._collTrav.addCollider(self._camCollNP, self._collHandler) self._betweenCamAndToon = {} self._transNP = NodePath('trans') self._transNP.reparentTo(render) self._transNP.setTransparency(True) self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon) self._transNP.setBin('fixed', 10000) def _destroyCollisions(self): self._collTrav.removeCollider(self._camCollNP) self._camCollNP.removeNode() del self._camCollNP del self._camCollRay del self._collHandler del self._collOffset del self._betweenCamAndToon self._transNP.removeNode() del self._transNP def freeze(self): self._frozen = True def unfreeze(self): self._frozen = False def disable(self): if not self._enabled: return self._destroyCollisions() self._camera.wrtReparentTo(render) self._cameraLookAtNP.removeNode() del self._cameraLookAtNP self._camParent.removeNode() del self._camParent del self._prevToonY del self._lookAtZ del self._bounds del self._frozen self._enabled = False def update(self, dt=0.0): self._updateCam(dt) self._updateCollisions() def _updateCam(self, dt): toonPos = self._toon.getPos() camPos = self._camParent.getPos() x = camPos[0] z = camPos[2] toonWorldX = self._toon.getX(render) maxX = Globals.Camera.MaxSpinX toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX) spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / ( maxX * maxX) newH = 180.0 + spinAngle self._camParent.setH(newH) spinAngle = spinAngle * (pi / 180.0) distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle) distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle) d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0]) if abs(d) > Globals.Camera.LeewayX: if d > Globals.Camera.LeewayX: x = toonPos[0] + Globals.Camera.LeewayX else: x = toonPos[0] - Globals.Camera.LeewayX x = self._toon.getX(render) + distToRightOfToon boundToonZ = min(toonPos[2], self._bounds[2][1]) d = z - boundToonZ if d > Globals.Camera.MinLeewayZ: if self._player.velocity[2] >= 0 and toonPos[ 1] != self._prevToonY or self._player.velocity[2] > 0: z = boundToonZ + d * INVERSE_E**(dt * Globals.Camera.CatchUpRateZ) elif d > Globals.Camera.MaxLeewayZ: z = boundToonZ + Globals.Camera.MaxLeewayZ elif d < -Globals.Camera.MinLeewayZ: z = boundToonZ - Globals.Camera.MinLeewayZ if self._frozen: y = camPos[1] else: y = self._toon.getY(render) - distBehindToon self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z)) if toonPos[2] < self._bounds[2][1]: h = self._cameraLookAtNP.getH() if d >= Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ) elif d <= -Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ) self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0) self._camera.setHpr( smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr())) self._prevToonY = toonPos[1] def _updateCollisions(self): pos = self._toon.getPos(self._camera) + self._collOffset self._camCollRay.setOrigin(pos) direction = -Vec3(pos) direction.normalize() self._camCollRay.setDirection(direction) self._collTrav.traverse(render) nodesInBetween = {} if self._collHandler.getNumEntries() > 0: self._collHandler.sortEntries() for entry in self._collHandler.getEntries(): name = entry.getIntoNode().getName() if name.find('col_') >= 0: np = entry.getIntoNodePath().getParent() if not np in nodesInBetween: nodesInBetween[np] = np.getParent() for np in nodesInBetween.keys(): if np in self._betweenCamAndToon: del self._betweenCamAndToon[np] else: np.setTransparency(True) np.wrtReparentTo(self._transNP) if np.getName().find('lightFixture') >= 0: if not np.find('**/*floor_mesh').isEmpty(): np.find('**/*floor_mesh').hide() elif np.getName().find('platform') >= 0: if not np.find('**/*Floor').isEmpty(): np.find('**/*Floor').hide() for np, parent in self._betweenCamAndToon.items(): np.wrtReparentTo(parent) np.setTransparency(False) if np.getName().find('lightFixture') >= 0: if not np.find('**/*floor_mesh').isEmpty(): np.find('**/*floor_mesh').show() elif np.getName().find('platform') >= 0: if not np.find('**/*Floor').isEmpty(): np.find('**/*Floor').show() self._betweenCamAndToon = nodesInBetween
class thirdPerson(DirectObject): def __init__(self, parserClass, mainClass, mapLoaderClass, modelLoaderClass): self.switchState = False #self.t = Timer() self.keyMap = {"left": 0, "right": 0, "forward": 0, "backward": 0} self.ralph = Actor( "data/models/units/ralph/ralph", { "run": "data/models/units/ralph/ralph-run", "walk": "data/models/units/ralph/ralph-walk" }) self.ralph.reparentTo(render) # self.ralph.setPos(42, 30, 0) self.ralph.setPos(6, 10, 0) self.ralph.setScale(0.1) self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_up", self.setKey, ["forward", 1]) self.accept("arrow_up-up", self.setKey, ["forward", 0]) self.accept("arrow_down", self.setKey, ["backward", 1]) self.accept("arrow_down-up", self.setKey, ["backward", 0]) self.isMoving = False self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 1000) self.ralphGroundRay.setDirection(0, 0, -1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) #self.ralphGroundCol.show() base.cam.reparentTo(self.ralph) base.cam.setPos(0, 9, 7) self.floater2 = NodePath(PandaNode("floater2")) self.floater2.reparentTo(self.ralph) self.floater2.setZ(self.floater2.getZ() + 6) base.cam.lookAt(self.floater2) # Uncomment this line to see the collision rays # self.ralphGroundColNp.show() # self.camGroundColNp.show() #Uncomment this line to show a visual representation of the #collisions occuring # self.cTrav.showCollisions(render) self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) taskMgr.add(self.move, "movingTask", extraArgs=[ mainClass, parserClass, mapLoaderClass, modelLoaderClass ]) #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value def move(self, mainClass, parserClass, mapLoaderClass, modelLoaderClass): # Get the time elapsed since last frame. We need this # for framerate-independent movement. elapsed = globalClock.getDt() # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if (self.keyMap["left"] != 0): self.ralph.setH(self.ralph.getH() + elapsed * 300) if (self.keyMap["right"] != 0): self.ralph.setH(self.ralph.getH() - elapsed * 300) if (self.keyMap["forward"] != 0): self.ralph.setY(self.ralph, -(elapsed * 50)) #25)) if (self.keyMap["backward"] != 0): self.ralph.setY(self.ralph, +(elapsed * 20)) if (self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0) or (self.keyMap["right"] != 0): if self.isMoving is False: self.ralph.loop("run") self.isMoving = True elif (self.keyMap["backward"] != 0): if self.isMoving is False: self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False # Now check for collisions. self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x, y: cmp( y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries) > 0) and (entries[0].getIntoNode().getName()[0:4] == "tile"): self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) elif (len(entries) > 0) and (entries[0].getIntoNode().getName()[0:5] == "solid"): self.ralph.setPos(startpos) x = int(entries[0].getIntoNode().getName() [len(entries[0].getIntoNode().getName()) - 6:len(entries[0].getIntoNode().getName()) - 4]) y = int(entries[0].getIntoNode().getName() [len(entries[0].getIntoNode().getName()) - 2:]) if (mapLoaderClass.tileArray[y][x].drillTime != None): mainClass.changeTile(mapLoaderClass.tileArray[y][x], 0, parserClass, modelLoaderClass, mapLoaderClass) else: self.ralph.setPos(startpos) self.ralph.setP(0) return Task.cont
class Camera: """A floating 3rd person camera that follows an actor around, and can be turned left or right around the actor. Public fields: self.controlMap -- The camera's movement controls. actor -- The Actor object that the camera will follow. Public functions: init(actor) -- Initialise the camera. move(task) -- Move the camera each frame, following the assigned actor. This task is called every frame to update the camera. setControl -- Set the camera's turn left or turn right control on or off. """ def __init__(self,actor): """Initialise the camera, setting it to follow 'actor'. Arguments: actor -- The Actor that the camera will initially follow. """ self.actor = actor self.prevtime = 0 # The camera's controls: # "left" = move the camera left, 0 = off, 1 = on # "right" = move the camera right, 0 = off, 1 = on self.controlMap = {"left":0, "right":0} taskMgr.add(self.move,"cameraMoveTask") # Create a "floater" object. It is used to orient the camera above the # target actor's head. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Set up the camera. base.disableMouse() base.camera.setPos(self.actor.getX(),self.actor.getY()+2, 2) # uncomment for topdown #base.camera.setPos(self.actor.getX(),self.actor.getY()+10,2) #base.camera.setHpr(180, -50, 0) # A CollisionRay beginning above the camera and going down toward the # ground is used to detect camera collisions and the height of the # camera above the ground. A ray may hit the terrain, or it may hit a # rock or a tree. If it hits the terrain, we detect the camera's # height. If it hits anything else, the camera is in an illegal # position. self.cTrav = CollisionTraverser() self.groundRay = CollisionRay() self.groundRay.setOrigin(0,0,1000) self.groundRay.setDirection(0,0,-1) self.groundCol = CollisionNode('camRay') self.groundCol.addSolid(self.groundRay) self.groundCol.setFromCollideMask(BitMask32.bit(1)) self.groundCol.setIntoCollideMask(BitMask32.allOff()) self.groundColNp = base.camera.attachNewNode(self.groundCol) self.groundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.groundColNp, self.groundHandler) # Uncomment this line to see the collision rays #self.groundColNp.show() def move(self,task): """Update the camera's position before rendering the next frame. This is a task function and is called each frame by Panda3D. The camera follows self.actor, and tries to remain above the actor and above the ground (whichever is highest) while looking at a point slightly above the actor's head. Arguments: task -- A direct.task.Task object passed to this function by Panda3D. Return: Task.cont -- To tell Panda3D to call this task function again next frame. """ # FIXME: There is a bug with the camera -- if the actor runs up a # hill and then down again, the camera's Z position follows the actor # up the hill but does not come down again when the actor goes down # the hill. elapsed = task.time - self.prevtime # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. # comment out for topdown base.camera.lookAt(self.actor) camright = base.camera.getNetTransform().getMat().getRow3(0) camright.normalize() if (self.controlMap["left"]!=0): base.camera.setPos(base.camera.getPos() - camright*(elapsed*20)) if (self.controlMap["right"]!=0): base.camera.setPos(base.camera.getPos() + camright*(elapsed*20)) # If the camera is too far from the actor, move it closer. # If the camera is too close to the actor, move it farther. camvec = self.actor.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 10.0): base.camera.setPos(base.camera.getPos() + camvec*(camdist-10)) camdist = 10.0 if (camdist < 5.0): base.camera.setPos(base.camera.getPos() - camvec*(5-camdist)) camdist = 5.0 # Now check for collisions. self.cTrav.traverse(render) # Keep the camera at one foot above the terrain, # or two feet above the actor, whichever is greater. # comment out for topdown entries = [] for i in range(self.groundHandler.getNumEntries()): entry = self.groundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0) if (base.camera.getZ() < self.actor.getZ() + 2.0): base.camera.setZ(self.actor.getZ() + 2.0) # The camera should look in the player's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above the player's head. self.floater.setPos(self.actor.getPos()) self.floater.setZ(self.actor.getZ() + 2.0) #self.floater.setZ(self.actor.getZ() + 10.0) #self.floater.setY(self.actor.getY() + 7.0) # comment out for topdown base.camera.lookAt(self.floater) base.camera.setPos(self.floater.getPos()) # Store the task time and continue. self.prevtime = task.time return Task.cont def setControl(self, control, value): """Set the state of one of the camera's movement controls. Arguments: See self.controlMap in __init__. control -- The control to be set, must be a string matching one of the strings in self.controlMap. value -- The value to set the control to. """ # FIXME: this function is duplicated in Camera and Character, and # keyboard control settings are spread throughout the code. Maybe # add a Controllable class? self.controlMap[control] = value
class Character: """A character with an animated avatar that moves left, right or forward according to the controls turned on or off in self.controlMap. Public fields: self.controlMap -- The character's movement controls self.actor -- The character's Actor (3D animated model) Public functions: __init__ -- Initialise the character move -- Move and animate the character for one frame. This is a task function that is called every frame by Panda3D. setControl -- Set one of the character's controls on or off. """ def __init__(self, model, run, walk, startPos, scale): """Initialise the character. Arguments: model -- The path to the character's model file (string) run : The path to the model's run animation (string) walk : The path to the model's walk animation (string) startPos : Where in the world the character will begin (pos) scale : The amount by which the size of the model will be scaled (float) """ self.controlMap = {"left":0, "right":0, "up":0, "down":0} self.actor = Actor(Config.MYDIR+model, {"run":Config.MYDIR+run, "walk":Config.MYDIR+walk}) self.actor.reparentTo(render) self.actor.setScale(scale) self.actor.setPos(startPos) self.controller = Controller.LocalController(self) taskMgr.add(self.move,"moveTask") # Note: deriving classes DO NOT need # to add their own move tasks to the # task manager. If they override # self.move, then their own self.move # function will get called by the # task manager (they must then # explicitly call Character.move in # that function if they want it). self.prevtime = 0 self.isMoving = False # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above ralph's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.groundRay = CollisionRay() self.groundRay.setOrigin(0,0,1000) self.groundRay.setDirection(0,0,-1) self.groundCol = CollisionNode('ralphRay') self.groundCol.addSolid(self.groundRay) self.groundCol.setFromCollideMask(BitMask32.bit(1)) self.groundCol.setIntoCollideMask(BitMask32.allOff()) self.groundColNp = self.actor.attachNewNode(self.groundCol) self.groundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.groundColNp, self.groundHandler) # Uncomment this line to see the collision rays # self.groundColNp.show() #Uncomment this line to show a visual representation of the #collisions occuring # self.cTrav.showCollisions(render) def move(self, task): """Move and animate the character for one frame. This is a task function that is called every frame by Panda3D. The character is moved according to which of it's movement controls are set, and the function keeps the character's feet on the ground and stops the character from moving if a collision is detected. This function also handles playing the characters movement animations. Arguments: task -- A direct.task.Task object passed to this function by Panda3D. Return: Task.cont -- To tell Panda3D to call this task function again next frame. """ elapsed = task.time - self.prevtime # save the character's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.actor.getPos() # pass on input self.controller.move(task, elapsed) # If the character is moving, loop the run animation. # If he is standing still, stop the animation. if (self.controlMap["up"]!=0) or (self.controlMap["left"]!=0) or (self.controlMap["right"]!=0) or (self.controlMap["down"]!=0): if self.isMoving is False: self.actor.loop("run") self.isMoving = True else: if self.isMoving: self.actor.stop() self.actor.pose("walk",5) self.isMoving = False # Now check for collisions. self.cTrav.traverse(render) # Adjust the character's Z coordinate. If the character's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.groundHandler.getNumEntries()): entry = self.groundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.actor.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.actor.setPos(startpos) # Store the task time and continue. self.prevtime = task.time return Task.cont def setControl(self, control, value): """Set the state of one of the character's movement controls. Arguments: See self.controlMap in __init__. control -- The control to be set, must be a string matching one of the strings in self.controlMap. value -- The value to set the control to. """ # FIXME: this function is duplicated in Camera and Character, and # keyboard control settings are spread throughout the code. Maybe # add a Controllable class? self.controlMap[control] = value
class Input1(DirectObject): def __init__(self,model): # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above ralph's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0,0,1000) self.ralphGroundRay.setDirection(0,0,-1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,1000) self.camGroundRay.setDirection(0,0,-1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays self.ralphGroundColNp.show() self.camGroundColNp.show() #Uncomment this line to show a visual representation of the #collisions occuring self.cTrav.showCollisions(render) #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # Get the time elapsed since last frame. We need this # for framerate-independent movement. elapsed = globalClock.getDt() #Has a Change in time from 0.04 to 0.09 constantly changes # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. base.camera.lookAt(self.model.getX(),self.model.getY(),0) # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.model.getPos() # If a move-key is pressed, move ralph in the specified direction. # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. camvec = self.model.getPos() - base.camera.getPos() camvec.setZ(5) camdist = camvec.length() camvec.normalize() if (camdist > 30.0): base.camera.setPos(base.camera.getPos() + camvec*(camdist-30)) camdist = 30.0 if (camdist < 15.0): base.camera.setPos(base.camera.getPos() - camvec*(15-camdist)) camdist = 15.0 # The camera should look in ralph's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above ralph's head. # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. self.floater.setPos(self.model.getPos()) base.camera.lookAt(self.floater) # Now check for collisions. self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.ralph.setPos(startpos) entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.0) return Task.cont
class cWorld: def __init__( self ): # set background color base.setBackgroundColor( 0, 0, 0 ) # create target self.createTarget( ) # create boids self.createBoids( ) # setup camera self.setupCamera( ) # setup lights self.setupLights( ) # setup collision detection self.setupCollision( ) # add task taskMgr.add( self.steer, 'steer' ) # steer task taskMgr.add( self.moveTarget, 'moveTarget' ) # mouse move target task def createBoids( self ): self.redBoid = cBoid( ) # create red boid # setup blue boid with model path, starting location, max force, and max speed self.redBoid.setup( 'assets/models/boid_one.egg', Vec3( 0.0, 0.0, 0.0 ), 4.0, 0.1 ) # create blue boid self.blueBoid = cBoid( ) # setup blue boid with model path, starting location, max force, and max speed self.blueBoid.setup( 'assets/models/boid_two.egg', Vec3( 0.0, 0.0, 0.0 ), 4.0, 1.0 ) def createTarget( self ): # load in model file self.target = loader.loadModel( 'assets/models/target.egg' ) # parent self.target.reparentTo( render ) # set location self.target.setPos( Vec3( 0.0, 0.0, 0.0 ) ) def setupCamera( self ): # disable auto controls base.disableMouse() # set position, heading, pitch, and roll camera.setPosHpr( Vec3( 0.0, -45.0, 45.0), Vec3( 0.0, -45.0, 0 ) ) def setupLights( self ): # create a point light plight = PointLight( 'plight' ) # set its color plight.setColor( VBase4( 1.0, 1.0, 1.0, 1 ) ) # attach the light to the render plnp = render.attachNewNode( plight ) # set position plnp.setPos( 0.0, 0.0, 2.0 ) # turn on light render.setLight( plnp ) def setupCollision( self ): # create collision traverser self.picker = CollisionTraverser( ) # create collision handler self.pq = CollisionHandlerQueue( ) # create collision node self.pickerNode = CollisionNode( 'mouseRay' ) # create collision node # attach new collision node to camera node self.pickerNP = camera.attachNewNode( self.pickerNode ) # attach collision node to camera # set bit mask to one self.pickerNode.setFromCollideMask( BitMask32.bit( 1 ) ) # set bit mask # create a collision ray self.pickerRay = CollisionRay( ) # create collision ray # add picker ray to the picker node self.pickerNode.addSolid( self.pickerRay ) # add the collision ray to the collision node # make the traverser know about the picker node and its even handler queue self.picker.addCollider( self.pickerNP, self.pq ) # add the colision node path and collision handler queue #self.picker.showCollisions( render ) # render or draw the collisions #self.pickerNP.show( ) # render picker ray # create col node self.colPlane = CollisionNode( 'colPlane' ) # add solid to col node plane self.colPlane.addSolid( CollisionPlane( Plane( Vec3( 0, 0, 1 ), Point3( 0, 0, 0 ) ) ) ) # attach new node to the render self.colPlanePath = render.attachNewNode( self.colPlane ) #self.colPlanePath.show( ) # render node # make the col plane look at the camera # this makes it alway look at the camera no matter the orientation # we need this because the ray nees to intersect a plane parallel # to the camera self.colPlanePath.lookAt( camera ) # prop up the col plane self.colPlanePath.setP( -45 ) # set bit mask to one # as I understand it, this makes all col nodes with bit mask one # create collisions while ignoring others of other masks self.colPlanePath.node( ).setIntoCollideMask( BitMask32.bit( 1 ) ) def steer( self, Task ): # seek after target self.redBoid.seek( Vec3( self.target.getPos( ) ) ) # run the algorithm self.redBoid.run( ) # arrive at the target self.blueBoid.arrive( Vec3( self.target.getPos( ) ) ) # run the algorithm self.blueBoid.run( ) return Task.cont # continue task def moveTarget( self, Task ): # traverse through the render tree self.picker.traverse( render ) # go through the queue of collisions for i in range( self.pq.getNumEntries( ) ): entry = self.pq.getEntry( i ) # get entry surfacePoint = entry.getSurfacePoint( render ) # get surface point of collision self.target.setPos( surfacePoint ) # set surface point to target's position if base.mouseWatcherNode.hasMouse( ): # if we have a mouse mpos = base.mouseWatcherNode.getMouse( ) # get the path to the mouse # shoot ray from camera # based on X & Y coordinate of mouse self.pickerRay.setFromLens( base.camNode, mpos.getX( ), mpos.getY( ) ) return Task.cont # continue task
class NodeRaycaster: def __init__(self, renderer): self.log = logging.getLogger('pano.raycaster') self.renderer = renderer #Stores the collisions of the camera ray with the cubemap self.collisionsQueue = None #Variables for setting up collision detection in Panda self.pickerNP = None self.pickerNode = None self.pickerRay = None self.traverser = None def initialize(self): """ To setup collision detection we need: a. A CollisionNode having a ray as its solid and placed at the position of the camera while also having the same orientation as the camera. b. A new nodepath placed in the scenegraph as an immediate child of the camera. It will be used to insert the collision node in the scenegraph. c. A CollisionRay for firing rays based on mouse clicks. d. A collisions traverser. e. A collisions queue where all found collisions will be stored for later processing. """ self.traverser = CollisionTraverser('Hotspots collision traverser') self.collisionsQueue = CollisionHandlerQueue() self.pickerNode = CollisionNode('mouseRay') self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.pickerNP = self.renderer.getCamera().attachNewNode( self.pickerNode) self.traverser.addCollider(self.pickerNP, self.collisionsQueue) def dispose(self): if self.pickerNP is not None: self.traverser.removeCollider(self.pickerNP) self.pickerNode.clearSolids() self.pickerNP.removeNode() def raycastWindow(self, x, y, returnAll=False): ''' Casts a camera ray, whose origin is implicitly defined by the given window coordinates, against the rendered scene returns information regarding the hit point, if any. @param x: The x window coordinate of the ray's origin in render2d space. @param y: The y window coordinate of the ray's origin in render2d space @param returnAll: If set to False then only the closest collided geometry is returned, otherwise all nodepaths whose collision nodes were intersected by the camera ray will be returned. @return: If returnAll was False, then a list containing a tuple of the form (topmost intersected NodePath, contact point Point3f). if returnAll was set to True, a list of tuples in the same form as above, one tuple for each intersection. None if no collision occurred. ''' #This makes the ray's origin the camera and makes the ray point #to the screen coordinates of the mouse self.pickerRay.setFromLens(self.renderer.getCamera().node(), x, y) #Check for collision only with the node self.traverser.traverse(self.renderer.getSceneRoot()) if self.collisionsQueue.getNumEntries() > 0: if not returnAll: self.collisionsQueue.sortEntries() cEntry = self.collisionsQueue.getEntry(0) if cEntry.hasInto(): return [(cEntry.getIntoNodePath(), cEntry.getSurfacePoint())] else: return None else: nodepaths = [] for i in xrange(self.collisionsQueue.getNumEntries()): cEntry = self.collisionsQueue.getEntry(i) if cEntry.hasInto(): # self.log.debug('adding collision into-nodepath: %s' % str(cEntry.getIntoNodePath())) intoNP = cEntry.getIntoNodePath() nodepaths.append( (intoNP, cEntry.getSurfacePoint(intoNP))) return nodepaths
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.cTrav = CollisionTraverser() self.cHandler = CollisionHandlerEvent() self.gameMode = "Exploring" self.countNpc = 0 self.npcName = [] self.npcX = [] self.npcY = [] self.talkies = False self.txtConvo = OnscreenText("",style=1, align = TextNode.ALeft, fg=(1,1,1,1), pos = (-1.1,-0.6,0), scale = 0.1) self.txtConvoOp1 = OnscreenText("",style=1, align = TextNode.ALeft, fg=(1,1,1,1), pos = (-1.1,-0.65,0), scale = 0.1) self.txtConvoOp2 = OnscreenText("",style=1, align = TextNode.ALeft, fg=(1,1,1,1), pos = (-1.1,-0.7,0), scale = 0.1) self.txtConvoOp3 = OnscreenText("",style=1, align = TextNode.ALeft,fg=(1,1,1,1), pos = (-1.1,-0.75,0), scale = 0.1) self.convoLineSelected = 0 self.keyboardSetup() self.cameraDistance = -50 self.camHeight = 25 self.camXAngle = 180 self.camYAngle = -15 self.camZAngle = 0 self.corrAngle = math.pi / 2 self.createPlayer() self.terrainSize = 20 self.drawTerrain() self.placeModels() self.collides() #cTrav.showCollisions(render) self.taskMgr.add(self.spinCameraTask, "SpinCameraTask") self.taskMgr.add(self.step, "GameStep") self.drawUI() def createPlayer(self): self.player = self.loader.loadModel("models/man.x") #,{"walk": "models/panda-walk4"} self.playerNode = render.attachNewNode("PlayerNode") self.playerNode.setScale(1, 1, 1) self.playerCollider = self.playerNode.attachNewNode(CollisionNode("playerCollider")) self.playerCollider.node().addSolid(CollisionSphere(0,0,0,5)) self.player.reparentTo(self.playerNode) self.cTrav.addCollider(self.playerCollider, self.cHandler) #self.playerCollider.show() self.playerY = 50 self.playerX = 50 self.playerZ = 0 self.playerDir = 0.0 self.playerMove = 0.0 self.playerTurn = 0.0 self.playerJumpHeight = 2 self.playerJumpDist = 0 self.playerJumpGrav = 0.2 self.playerJump = 0 self.playerSpeed = 6 self.playerTurnSpeed = 1 self.playerNode.setH(self.playerDir) def step(self, task): if self.gameMode == "Exploring": if (self.playerMove != 0): self.movePlayer(task) if (self.playerTurn != 0): self.turnPlayer(task) if (self.playerJumpDist > 0): self.playerJumpDist += self.playerJump self.playerJump -= self.playerJumpGrav if (self.playerJumpDist <= 1): self.playerJumpDist = 0 self.drawPlayer() task.delayTime = 0.01 return Task.again def spinCameraTask(self, task): if (self.playerMove == 0 and self.gameMode == "Exploring"): self.updateCamera() if (self.gameMode == "Conversation"): self.playerAngle = self.playerNode.getH() * math.pi / 180 self.camX = self.playerX + self.cameraDistance * math.cos( self.corrAngle - self.playerAngle ) self.camY = self.playerY + self.cameraDistance * -math.sin( self.corrAngle - self.playerAngle ) self.camZ = self.getObjectZ(self.playerX, self.playerY) + self.camHeight self.camera.setPos(self.playerX, self.playerY, self.playerZ + 10) self.camera.lookAt(self.talkiesNpc.getX(), self.talkiesNpc.getY(), self.talkiesNpc.getZ() + 10) return Task.cont def updateCamera(self): self.playerAngle = self.playerNode.getH() * math.pi / 180 self.camX = self.playerX + self.cameraDistance * math.cos( self.corrAngle - self.playerAngle ) self.camY = self.playerY + self.cameraDistance * -math.sin( self.corrAngle - self.playerAngle ) self.camZ = self.getObjectZ(self.playerX, self.playerY) + self.camHeight self.camera.setPos(self.camX, self.camY, self.camZ) self.camera.setHpr(self.playerDir + self.camXAngle, self.camYAngle, self.camZAngle) def drawUI(self): self.imgInv = dict() for box in range (0, 5): self.imgInv[box] = OnscreenImage(image = "textures/inventoryBox.png", pos = ((box * 0.22) -1, 0, -0.9), scale = (0.1, 0.1, 0.1)) self.imgInv[box].setTransparency(TransparencyAttrib.MAlpha) def getObjectZ(self, x, y): if ((x > 0) and (x < 257) and (y > 0) and (y < 257)): return(self.terrain.getElevation(x,y)*self.terrainSize) else: return 0 def placeModels(self): cubeCount = 12 cubeXInc = 24 cubeGen = 0 cubeGenX = 0 cubeGenY = -50 cubeGenScale = 10 cubeGenRot = 90 while (cubeGen < cubeCount): cube = self.loader.loadModel("models/house2.x") cube.reparentTo(self.render) cube.setScale(cubeGenScale, cubeGenScale*2, cubeGenScale) cube.setPos(0+cubeXInc*cubeGen, cubeGenY, 0) cubeGen += 1 cubeGen = 0 while (cubeGen < cubeCount): cubeGen += 1 self.placeNPC("Sally Susan",-50,-50) self.placeNPC("Gerald Fanturbett",-80,-40) self.placeNPC("Pillynostrum MacSternum",-20,-100) def placeNPC(self,name,x,y): npcScale = 1 npcTexture = loader.loadTexture("textures/texRock2.png") self.npc = self.loader.loadModel("models/man.x") self.npcNode = render.attachNewNode("NpcNode") self.npc.reparentTo(self.npcNode) self.npcName+=[name] self.npc.setName(name) self.npc.setScale(1, 1, 1) self.npc.setPos(x,y,0) self.npcX += [x] self.npcY += [y] self.npc.setTexture(npcTexture) self.npcCollider = self.npc.attachNewNode(CollisionNode("npcCollider")) self.npcCollider.node().addSolid(CollisionSphere(0, 0, 0, 5)) self.countNpc += 1 #self.npcCollider.show() def conversationWithNPC(self): if self.talkies == True and self.gameMode != "Conversation": self.txtConvo.setText("HEY! LETS TALK!") self.txtConvoOp1.setText("") self.txtConvoOp2.setText("") self.txtConvoOp3.setText("") self.gameMode = "Conversation" elif self.gameMode == "Conversation": self.gameMode = "Exploring" def drawTerrain(self): self.terrain = GeoMipTerrain("terrain") self.terrain.setHeightfield(Filename("textures/heights.png")) self.terrain.setColorMap("textures/heightColour.png") self.terrain.setBlockSize(64) self.terrain.setFactor(0) self.terrain.setNear(40) self.terrain.setFar(120) self.terrain.setMinLevel(1) self.terrain.setBruteforce(True) self.terrain.generate() self.terrain.setAutoFlatten(self.terrain.AFMLight) self.terrain.setFocalPoint(Point3(self.playerX,self.playerY,self.playerZ)) self.root = self.terrain.getRoot() self.root.reparentTo(render) self.root.setSz(self.terrainSize) def jumpPlayer(self): if (self.playerJumpDist == 0): self.playerJump = self.playerJumpHeight self.playerJumpDist += self.playerJump def movePlayer(self, task): self.dx = self.playerMove * math.cos( self.corrAngle - self.playerAngle ) self.dy = self.playerMove * -math.sin( self.corrAngle - self.playerAngle ) move = True for i in range(self.countNpc): xi = self.playerX+ self.dx / 10 xii = self.npcX[i] yi = self.playerY+ self.dy / 10 yii = self.npcY[i] sq1 = (xi-xii)*(xi-xii) sq2 = (yi-yii)*(yi-yii) distance = math.sqrt(sq1 + sq2) if distance < 5: move = False if move == True: self.playerX += self.dx / 10 self.playerY += self.dy / 10 self.playerZ = self.getObjectZ(self.playerX, self.playerY) self.playerNode.setPos(self.playerX, self.playerY, self.playerZ + self.playerJumpDist) self.updateCamera() self.terrain.setFocalPoint(Point3(self.playerX, self.playerY, self.playerZ)) self.terrain.update() def drawPlayer(self): self.playerNode.setPos(self.playerX, self.playerY, self.playerZ + self.playerJumpDist) def turnPlayer(self, task): self.playerDir += self.playerTurn self.playerNode.setH(self.playerDir) def keyboardSetup( self ): self.accept("w", self.keyW) self.accept("w-up", self.resetMove) self.accept("s", self.keyS) self.accept("s-up", self.resetMove) self.accept("a", self.keyA) self.accept("enter", self.conversationWithNPC) self.accept("a-up", self.resetDir) self.accept("d", self.keyD) self.accept("d-up", self.resetDir) self.accept("space", self.jumpPlayer) def collideEventIn(self, entry): np_into=entry.getIntoNodePath() self.txtConvo.setText("<Press Enter to talk to %s>"%np_into.getParent().getName()) np_into.getParent().setHpr(self.playerDir - 180, 0, 0) self.talkies = True self.talkiesNpc = np_into.getParent() def collideEventOut(self, entry): self.txtConvo.setText("") self.talkies = False self.gameMode = "Exploring" def collides(self): self.cHandler.addInPattern('%fn-into-%in') self.cHandler.addOutPattern('%fn-out-%in') DO=DirectObject() DO.accept("playerCollider-into-npcCollider", self.collideEventIn) DO.accept("playerCollider-out-npcCollider", self.collideEventOut) def keyW( self ): self.playerMove = self.playerSpeed def resetMove( self ): self.playerMove = 0 def resetDir( self ): self.playerTurn = 0 def keyS( self ): self.playerMove = -self.playerSpeed def keyA( self ): self.playerTurn = self.playerTurnSpeed def keyD( self ): self.playerTurn = -self.playerTurnSpeed
class MousePicker(p3d.SingleTask): """ Class to represent a ray fired from the input camera lens using the mouse. """ def __init__(self, *args, **kwargs): p3d.SingleTask.__init__(self, *args, **kwargs) self.fromCollideMask = kwargs.pop('fromCollideMask', None) self.node = None self.collEntry = None # Create collision nodes self.collTrav = CollisionTraverser() #self.collTrav.showCollisions( render ) self.collHandler = CollisionHandlerQueue() self.pickerRay = CollisionRay() # Create collision ray pickerNode = CollisionNode(self.name) pickerNode.addSolid(self.pickerRay) pickerNode.setIntoCollideMask(BitMask32.allOff()) pickerNp = self.camera.attachNewNode(pickerNode) self.collTrav.addCollider(pickerNp, self.collHandler) # Create collision mask for the ray if one is specified if self.fromCollideMask is not None: pickerNode.setFromCollideMask(self.fromCollideMask) # Bind mouse button events eventNames = ['mouse1', 'control-mouse1', 'mouse1-up'] for eventName in eventNames: self.accept(eventName, self.FireEvent, [eventName]) def OnUpdate(self, task, x=None, y=None): # Update the ray's position if self.mouseWatcherNode.hasMouse(): mp = self.mouseWatcherNode.getMouse() x, y = mp.getX(), mp.getY() if x is None or y is None: return self.pickerRay.setFromLens(self.camera.node(), x, y) # Traverse the hierarchy and find collisions self.collTrav.traverse(self.rootNp) if self.collHandler.getNumEntries(): # If we have hit something, sort the hits so that the closest is first self.collHandler.sortEntries() collEntry = self.collHandler.getEntry(0) node = collEntry.getIntoNode() # If this node is different to the last node, send a mouse leave # event to the last node, and a mouse enter to the new node if node != self.node: if self.node is not None: messenger.send('%s-mouse-leave' % self.node.getName(), [self.collEntry]) messenger.send('%s-mouse-enter' % node.getName(), [collEntry]) # Send a message containing the node name and the event over name, # including the collision entry as arguments messenger.send('%s-mouse-over' % node.getName(), [collEntry]) # Keep these values self.collEntry = collEntry self.node = node elif self.node is not None: # No collisions, clear the node and send a mouse leave to the last # node that stored messenger.send('%s-mouse-leave' % self.node.getName(), [self.collEntry]) self.node = None def FireEvent(self, event): """ Send a message containing the node name and the event name, including the collision entry as arguments. """ if self.node is not None: messenger.send('%s-%s' % (self.node.getName(), event), [self.collEntry]) def GetFirstNodePath(self): """ Return the first node in the collision queue if there is one, None otherwise. """ if self.collHandler.getNumEntries(): collEntry = self.collHandler.getEntry(0) return collEntry.getIntoNodePath() return None
class App(ShowBase.ShowBase): def setup(self): 'to be called after window is initialized' import resource resource.init(self) import asteroid import creatures self.init_skybox() self.init_ui() self.taskMgr.add(self.camera_task, "cameraTask") self.asteroid = asteroid.Asteroid.make_spheroid(asteroid.Rock, 12) asteroid.tunnel(self.asteroid) self.asteroid.nodepath.reparentTo(self.render) self.creatures = sum([[c() for i in range(5)] for c in (creatures.Human, creatures.Robot)], []) for creature in self.creatures: creature.pos = (0, 0, 0) creature.nodepath.reparentTo(self.render) self.start() self.setFrameRateMeter(True) def start(self): global LAST_TICK LAST_TICK = time.time() self.taskMgr.doMethodLater(TICK_LEN, self.do_tick, 'do_tick') def do_tick(self, task): global TICK_NUM, LAST_TICK, AVG_TICK_LEN TICK_NUM += 1 cur_time = time.time() start_time = cur_time AVG_TICK_LEN = ((cur_time - LAST_TICK) + AVG_TICK_LEN)/2 LAST_TICK = cur_time if TICK_NUM % 50 == 0: print "average tick length", AVG_TICK_LEN moves = [] for creature in self.creatures: creature.action = (creature.action + 1) % creature.speed if creature.action == 0: continue if not creature.cur_path: x = random.randint(0, 25) y = random.randint(0, 25) z = random.randint(0, 13) tile = self.asteroid.get(x,y,z) if tile and tile.passable: creature.goto((x,y,z), self.asteroid) if creature.cur_path: next = creature.cur_path.pop() moves.append(creature.nodepath.posInterval( AVG_TICK_LEN*(creature.speed-1), self.asteroid.get_pos(*next))) creature.pos = next if moves: Parallel(*moves, name="creature_moves "+str(TICK_NUM)).start() duration = time.time() - start_time self.taskMgr.doMethodLater( max(TICK_LEN-duration, 0), self.do_tick, 'do_tick') def camera_task(self, task): #re-center skybox after every camera move camPos = self.camera.getPos(render) self.skybox.setPos(camPos) #TODO: add camera-movement per-frame based on variables #than can be modified by UI return Task.cont def init_skybox(self): skybox = self.loader.loadModel("skybox/skybox.egg") skybox.setScale(512) skybox.setBin('background', 1) skybox.setDepthWrite(0) skybox.setLightOff() skybox.reparentTo(self.render) self.skybox = skybox def init_ui(self): self.cTrav = CollisionTraverser('ui_collision_traverser') self.collision_handler = CollisionHandlerQueue() picker_node = CollisionNode('mouse_click_ray') self.picker_node_path = self.camera.attachNewNode(picker_node) picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.picker_ray = CollisionRay() picker_node.addSolid(self.picker_ray) self.cTrav.addCollider(self.picker_node_path, self.collision_handler) ''' #debug: make a visible line segment from pandac.PandaModules import LineSegs, LVecBase4f, NodePath seg_drawer = LineSegs() seg_drawer.setColor(LVecBase4f(1, 0, 0, 1)) #red seg_drawer.moveTo(0,0,0) seg_drawer.drawTo(0,100,0) NodePath(seg_drawer.create()).reparentTo(self.picker_node_path) ''' self.accept('a', self.mouse_ray) def mouse_ray(app): 'cast a ray from the current mouse position, find intersections' if not app.mouseWatcherNode.hasMouse(): return None mouse_pos = app.mouseWatcherNode.getMouse() #cast a ray from the camera app.picker_ray.setFromLens(app.camNode, mouse_pos.getX(), mouse_pos.getY()) #see if it hit anything in the scene graph app.cTrav.traverse(app.render) if app.collision_handler.getNumEntries() > 0: #get closest collision app.collision_handler.sortEntries() for i in range(app.collision_handler.getNumEntries()): hit = app.collision_handler.getEntry(i) if app.asteroid.nodepath.isAncestorOf(hit.getIntoNodePath()): x,y,z = app.asteroid.get_collision_pos(hit) import asteroid app.asteroid.update(x,y,z,asteroid.Empty()) app.asteroid.redraw() break
class NavMesh(object): notify = directNotify.newCategory("NavMesh") def __init__(self, filepath=None, filename=None): if filename is not None: self._initFromFilename(filepath, filename) def initFromPolyData(self, polyToVerts, vertToPolys, polyToAngles, vertexCoords, environmentHash): ''' Initialize the mesh from a set of polygons. polyToVerts: Dictionary mapping a polygon ID to a set of N vertex IDs vertToPolys: Dictionary mapping a vertex ID to a set of poly IDs (of every poly that includes it) polyToAngles: Dictionary mapping a polygon ID to a set of N angles (in vertex order) vertexCoords: Dictionary mapping a vertex ID to the coordinates of the vertex in worldspace environmentHash: Hash value derived from the same collision geometry as the other arguments. See AreaMapper.getEnvironmentHash(). ''' self.polyToVerts = polyToVerts self.vertToPolys = vertToPolys self.polyToAngles = polyToAngles self.vertexCoords = vertexCoords self.environmentHash = environmentHash self.connectionLookup = {} self.connections = [] self._discoverInitialConnectivity() self.optimizeMesh() def visualize(self, parentNodePath, highlightVerts=[], pathVerts=[], visitedVerts=[]): ''' XXX Should move this into a product-specific class. ''' gFormat = GeomVertexFormat.getV3cp() self.visVertexData = GeomVertexData("OMGVERTEXDATA2", gFormat, Geom.UHDynamic) self.visVertexWriter = GeomVertexWriter(self.visVertexData, "vertex") self.visVertexColorWriter = GeomVertexWriter(self.visVertexData, "color") vertToWriterIndex = {} currIndex = 0 for v in self.vertexCoords.keys(): vertToWriterIndex[v] = currIndex x = self.vertexCoords[v][0] y = self.vertexCoords[v][1] z = self.vertexCoords[v][2] self.visVertexWriter.addData3f(x, y, z + 0.5) if v in highlightVerts: self.visVertexColorWriter.addData4f(1.0, 0.0, 0.0, 1.0) elif v in visitedVerts: self.visVertexColorWriter.addData4f(0.0, 0.0, 1.0, 1.0) else: self.visVertexColorWriter.addData4f(1.0, 1.0, 0.0, 1.0) currIndex += 1 pathOffsetIntoIndex = currIndex for v in pathVerts: self.visVertexWriter.addData3f(v[0], v[1], v[2] + 0.5) self.visVertexColorWriter.addData4f(0.0, 1.0, 0.0, 1.0) currIndex += 1 lines = GeomLinestrips(Geom.UHStatic) for p in self.polyToVerts.keys(): for v in self.polyToVerts[p]: lines.addVertex(vertToWriterIndex[v]) lines.addVertex(vertToWriterIndex[self.polyToVerts[p][0]]) lines.closePrimitive() if len(pathVerts) > 0: for i in xrange(len(pathVerts)): lines.addVertex(pathOffsetIntoIndex + i) lines.closePrimitive() self.visGeom = Geom(self.visVertexData) self.visGeom.addPrimitive(lines) self.visGN = GeomNode("NavMeshVis") self.visGN.addGeom(self.visGeom) self.visNodePath = parentNodePath.attachNewNode(self.visGN) self.visNodePath.setTwoSided(True) def _discoverInitialConnectivity(self): print "Building initial connectivity graph..." for pId in self.polyToVerts.keys(): verts = self.polyToVerts[pId] numVerts = len(verts) candidates = [] neighborPolys = [] for v in verts: candidates += [ p for p in self.vertToPolys[v] if (p not in candidates) and (p != pId) ] for vNum in xrange(numVerts): neighbor = [p for p in candidates if ((verts[vNum] in self.polyToVerts[p]) and \ (verts[(vNum+1)%numVerts] in self.polyToVerts[p]))] if len(neighbor) == 0: neighborPolys.append(None) elif len(neighbor) == 1: neighborPolys.append(neighbor[0]) else: raise "Two neighbors found for the same edge?!?!" self.connectionLookup[pId] = neighborPolys # --------- Begin stitching code --------- def _attemptToMergePolys(self, polyA, polyB): newVerts = [] newAngles = [] newConnections = [] vertsA = self.polyToVerts[polyA] vertsB = self.polyToVerts[polyB] lenA = len(vertsA) lenB = len(vertsB) anglesA = self.polyToAngles[polyA] anglesB = self.polyToAngles[polyB] sharedVerts = [v for v in vertsA if (v in vertsB)] locA = 0 while vertsA[locA] not in sharedVerts: locA += 1 while vertsA[locA] in sharedVerts: locA = (locA - 1) % lenA locA = (locA + 1) % lenA CCWmost = vertsA[locA] CCWmostLocA = locA while vertsA[locA] in sharedVerts: locA = (locA + 1) % lenA locA = (locA - 1) % lenA CWmost = vertsA[locA] CWmostLocA = locA # Convexity Check. # Verify that removing the edge preserves convexity and bail out if not. locA = 0 locB = 0 while vertsA[locA] != CCWmost: locA += 1 while vertsB[locB] != CCWmost: locB += 1 CCWmostAngleSum = anglesA[locA] + anglesB[locB] CCWmostLocB = locB if CCWmostAngleSum > 180: return False locA = 0 locB = 0 while vertsA[locA] != CWmost: locA += 1 while vertsB[locB] != CWmost: locB += 1 CWmostAngleSum = anglesA[locA] + anglesB[locB] if CWmostAngleSum > 180: return False # We've found the CW-most vert of the shared edge. # Now walk A clockwise until we hit the CCW-most vert of the shared edge. newVerts.append(CWmost) newAngles.append(CWmostAngleSum) newConnections.append(self.connectionLookup[polyA][locA]) locA = (locA + 1) % lenA while vertsA[locA] != CCWmost: newVerts.append(vertsA[locA]) newAngles.append(anglesA[locA]) newConnections.append(self.connectionLookup[polyA][locA]) locA = (locA + 1) % lenA # Now we've hit the CCW-most vert of the shared edge. # Walk B clockwise until we get back to the CW-most vert of the shared edge. locB = CCWmostLocB newVerts.append(CCWmost) newAngles.append(CCWmostAngleSum) neighbor = self.connectionLookup[polyB][locB] newConnections.append(neighbor) if neighbor is not None: for i in xrange(len(self.connectionLookup[neighbor])): if self.connectionLookup[neighbor][i] == polyB: self.connectionLookup[neighbor][i] = polyA locB = (locB + 1) % lenB while vertsB[locB] != CWmost: newVerts.append(vertsB[locB]) newAngles.append(anglesB[locB]) neighbor = self.connectionLookup[polyB][locB] newConnections.append(neighbor) if neighbor is not None: for i in xrange(len(self.connectionLookup[neighbor])): if self.connectionLookup[neighbor][i] == polyB: self.connectionLookup[neighbor][i] = polyA locB = (locB + 1) % lenB # We've added every vertex, its proper angle, and connectivity info # to the new polygon. Now replace A with the new guy and remove B. self.polyToVerts[polyA] = newVerts self.polyToAngles[polyA] = newAngles self.connectionLookup[polyA] = newConnections # Make sure we have vertex->poly pointers for all the new verts we added to A. for v in newVerts: if polyA not in self.vertToPolys[v]: self.vertToPolys[v].append(polyA) # Clean up all of B's old vertices. for v in vertsB: self.vertToPolys[v].remove(polyB) if len(self.vertToPolys[v]) == 0: # No one's using this vertex anymore, remove it del self.vertToPolys[v] del self.vertexCoords[v] del self.polyToVerts[polyB] del self.polyToAngles[polyB] del self.connectionLookup[polyB] return True def _attemptToGrowPoly(self, pId): for neighbor in self.connectionLookup.get(pId, []): if (neighbor is not None) and self._attemptToMergePolys( pId, neighbor): return True return False def _growEachPolyOnce(self): grewAtLeastOne = False for pId in self.connectionLookup.keys(): if self._attemptToGrowPoly(pId): grewAtLeastOne = True return grewAtLeastOne def optimizeMesh(self): ''' Takes a mesh that is already functionally complete and optimizes it for better performance. Reduces poly count and cuts out redundant vertices. Also compacts the polygon IDs into a contiguous range from 0 to N. No need to do the same for vertex IDs yet. ''' '''print "Stitching polygons: %s -> " % (len(self.polyToVerts)), orig = len(self.polyToVerts) numPasses = 1 while self._growEachPolyOnce(): print "%s -> " % (len(self.polyToVerts)), numPasses += 1 print "Done!\nPoly count reduced to %0.1f%% of original." % (len(self.polyToVerts)/float(orig)*100.0)''' self._pruneExtraVerts() self._compactPolyIds() self.numNodes = len(self.connections) biggest = 0 biggestPoly = -1 for p in self.polyToVerts: if len(self.polyToVerts[p]) > biggest: biggest = len(self.polyToVerts[p]) biggestPoly = p print "Most verts in a single poly: ", biggest assert biggest < 256 def _cleanPoly(self, polyId): verts = self.polyToVerts[polyId] angles = self.polyToAngles[polyId] neighbors = self.connectionLookup[polyId] numVerts = len(verts) newVerts = [] newAngles = [] newNeighbors = [] for i in xrange(numVerts): if (angles[i] != 180) or \ (len(self.vertToPolys.get(verts[i],[])) > 2) or \ (neighbors[i] != neighbors[(i-1)%numVerts]): # Keep vertex newVerts.append(verts[i]) newAngles.append(angles[i]) newNeighbors.append(neighbors[i]) else: # Remove vertex, this will happen twice so pop it self.vertToPolys.pop(verts[i], None) self.vertexCoords.pop(verts[i], None) if len(verts) != len(newVerts): self.polyToVerts[polyId] = newVerts self.polyToAngles[polyId] = newAngles self.connectionLookup[polyId] = newNeighbors assert len(newVerts) < 256 def _pruneExtraVerts(self): print "Pruning extra vertices..." print "Starting verts: %s" % len(self.vertToPolys) for polyId in self.connectionLookup.keys(): self._cleanPoly(polyId) print "Ending verts: %s" % len(self.vertToPolys) def _compactPolyIds(self): polyList = self.polyToVerts.keys() polyList.sort() oldToNewId = {None: None} newPolyToVerts = {} newPolyToAngles = {} self.connections = [] currId = 0 for oldId in polyList: oldToNewId[oldId] = currId self.connections.append([]) currId += 1 for oldId in polyList: newPolyToVerts[oldToNewId[oldId]] = self.polyToVerts[oldId] newPolyToAngles[oldToNewId[oldId]] = self.polyToAngles[oldId] #self.connections[oldToNewId[oldId]] = [] for edgeNum in xrange(len(self.connectionLookup[oldId])): self.connections[oldToNewId[oldId]].append( oldToNewId[self.connectionLookup[oldId][edgeNum]]) self.polyToVerts = newPolyToVerts self.polyToAngles = newPolyToAngles del self.connectionLookup # --------- Begin pathfinding code --------- def _findCentroid(self, polyId): verts = self.polyToVerts[polyId] numVerts = len(verts) x = 0 y = 0 z = 0 for v in verts: x += self.vertexCoords[v][0] y += self.vertexCoords[v][1] z += self.vertexCoords[v][2] x /= numVerts y /= numVerts z /= numVerts return (x, y, z) ## def _estimateDistanceBetweenPolys(self, polyA, polyB): ## centroidA = self._findCentroid(polyA) ## centroidB = self._findCentroid(polyB) ## dx = centroidA[0] - centroidB[0] ## dy = centroidA[1] - centroidB[1] ## dz = centroidA[2] - centroidB[2] ## return math.sqrt(dx*dx + dy*dy + dz*dz) def _walkToNeighbor(self, currPoly, neighborPoly): currVerts = self.polyToVerts[currPoly] neighborVerts = self.polyToVerts[neighborPoly] lenCurr = len(currVerts) sharedVerts = [v for v in currVerts if (v in neighborVerts)] loc = 0 while currVerts[loc] not in sharedVerts: loc += 1 while currVerts[loc] in sharedVerts: loc = (loc - 1) % lenCurr loc = (loc + 1) % lenCurr CCWmost = currVerts[loc] CCWmostLoc = loc while currVerts[loc] in sharedVerts: loc = (loc + 1) % lenCurr loc = (loc - 1) % lenCurr CWmost = currVerts[loc] CCWmostCoords = self.vertexCoords[CCWmost] CWmostCoords = self.vertexCoords[CWmost] # For now, walk to the midpoint of the connecting edge departingEdge = CCWmostLoc # Don't need this with goal->start search neighborsEdge = 0 while self.connections[neighborPoly][neighborsEdge] != currPoly: neighborsEdge += 1 return (neighborsEdge, ((CWmostCoords[0] + CCWmostCoords[0]) / 2.0, (CWmostCoords[1] + CCWmostCoords[1]) / 2.0, (CWmostCoords[2] + CCWmostCoords[2]) / 2.0)) ## def _remakePath(self,walkBack,currNode): ## if currNode in walkBack: ## p = self._remakePath(walkBack,walkBack[currNode]) ## return p + [currNode,] ## return [currNode,] ## def findRoute(self, startNode, goalNode): ## ''' ## So much love for A*. ## ''' ## nodeToF = {} ## nodeToG = {} ## nodeToH = {} ## walkBack = {} ## #nodeToEntryPoint = {} ## self.nodeToEntryPoint[startNode] = self._findCentroid(startNode) ## nodeToG[startNode] = 0 ## nodeToH[startNode] = self._estimateDistanceBetweenPolys(startNode,goalNode) ## nodeToF[startNode] = nodeToG[startNode] + nodeToH[startNode] ## closedSet = {} ## openSet = {} ## openQueue = PriQueue() # Priority = F score ## openSet[startNode] = 1 ## openQueue.push((nodeToF[startNode],startNode)) ## goalPoint = self._findCentroid(goalNode) ## while len(openSet) > 0: ## f,currNode = openQueue.pop(0) ## del openSet[currNode] ## self.aStarWasHere[currNode] = 1 ## if currNode == goalNode: ## return self._remakePath(walkBack,currNode) ## closedSet[currNode] = 1 ## currPoint = self.nodeToEntryPoint[currNode] ## for neighbor in self.connections[currNode]: ## if (neighbor is not None) and (neighbor not in closedSet): ## departingEdge,newEntryPoint = self._walkToNeighbor(currNode,currPoint,neighbor) ## newG = nodeToG[currNode] + math.sqrt((newEntryPoint[0] - currPoint[0])**2 + \ ## (newEntryPoint[1] - currPoint[1])**2 + \ ## (newEntryPoint[2] - currPoint[2])**2) ## gotHereFasterThanBefore = False ## if neighbor not in openSet: ## openSet[neighbor] = 1 ## gotHereFasterThanBefore = True ## elif newG < nodeToG[neighbor]: ## openQueue.remove((nodeToF[neighbor],neighbor)) ## gotHereFasterThanBefore = True ## if gotHereFasterThanBefore: ## walkBack[neighbor] = currNode ## self.nodeToEntryPoint[neighbor] = newEntryPoint ## nodeToH[neighbor] = math.sqrt((goalPoint[0] - newEntryPoint[0])**2 + \ ## (goalPoint[1] - newEntryPoint[1])**2 + \ ## (goalPoint[2] - newEntryPoint[2])**2) ## nodeToG[neighbor] = newG ## nodeToF[neighbor] = nodeToG[neighbor] + nodeToH[neighbor] ## openQueue.push((nodeToF[neighbor],neighbor)) ## raise "No path found! D:" def _findAllRoutesToGoal(self, goalNode): ''' Find the shortest path from ALL start nodes to the given goal node. (Djikstra) After running, self.pathData[startNode][goalNode] == outgoing edge from startNode to the next node for the given value of goalNode and ALL values of startNode. ''' nodeToG = {} walkBack = {} nodeDeparturePoint = {} nodeDeparturePoint[goalNode] = self._findCentroid(goalNode) nodeToG[goalNode] = 0 closedSet = {} openSet = {} openQueue = PriQueue() openSet[goalNode] = 1 openQueue.push((nodeToG[goalNode], goalNode)) walkBack[goalNode] = (0, goalNode) while len(openSet) > 0: f, currNode = openQueue.pop(0) del openSet[currNode] closedSet[currNode] = 1 currPoint = nodeDeparturePoint[currNode] for neighbor in self.connections[currNode]: if (neighbor is not None) and (neighbor not in closedSet): neighborsEdge, newPoint = self._walkToNeighbor( currNode, neighbor) newG = nodeToG[currNode] + math.sqrt((newPoint[0] - currPoint[0])**2 + \ (newPoint[1] - currPoint[1])**2 + \ (newPoint[2] - currPoint[2])**2) gotHereFasterThanBefore = False if neighbor not in openSet: openSet[neighbor] = 1 gotHereFasterThanBefore = True elif newG < nodeToG[neighbor]: openQueue.remove((nodeToG[neighbor], neighbor)) gotHereFasterThanBefore = True if gotHereFasterThanBefore: walkBack[neighbor] = (neighborsEdge, currNode) nodeDeparturePoint[neighbor] = newPoint nodeToG[neighbor] = newG openQueue.push((nodeToG[neighbor], neighbor)) for startNode in xrange(len(self.connections)): departingEdge = walkBack[startNode][0] assert self.pathData[startNode][goalNode] is None self.pathData[startNode][goalNode] = departingEdge def generatePathData(self, rowRange=None): ''' Entry point for path preprocessing. Solves all pairs shortest path for this mesh. Stores the result in self.pathData. SLOW. Expect 8-10 minutes on Port Royal alone. Currently runs Djikstra on every possible start node. There are faster approaches for APSP, but... ''' if rowRange is None: rowRange = (0, self.numNodes) self.initPathData() for goalNode in xrange(rowRange[0], rowRange[1]): self._findAllRoutesToGoal(goalNode) def createPathTable(self): ''' Takes a 2D array self.pathData and changes it in place. Each row is changed into a run-length encoded string. Then, feeds the data into a new PathTable instance. ''' for row in self.pathData: for val in row: if val == None: raise "Incomplete path data!" shortestPathLookup = self.pathData self.pathData = [] # Run-Length Encode the whole thing! for start in xrange(self.numNodes): row = [] lastVal = None nodesInRow = 0 for goal in xrange(self.numNodes): val = shortestPathLookup[start][goal] if val != lastVal: row.append([goal, val]) lastVal = val nodesInRow += 1 else: nodesInRow += 1 assert nodesInRow == self.numNodes stringsRow = [] # Convert row to a bytestring to save space for item in row: assert item[0] < 65536 assert item[1] < 256 stringsRow.append( chr(item[0] / 256) + chr(item[0] % 256) + chr(item[1])) assert len(stringsRow[-1]) == 3 rowString = string.join(stringsRow, "") self.pathData.append(rowString) self.pathTable = PathTable(self.pathData, self.connections) def printPathData(self): ''' Outputs the pickled path table to stdout. ''' import sys sys.stdout.write(pickle.dumps(self.pathData, protocol=0)) def initPathData(self): self.pathData = [] for i in xrange(self.numNodes): self.pathData.append([ None, ] * self.numNodes) def addPaths(self, partialData): for i in xrange(len(partialData)): for j in xrange(len(partialData[i])): if partialData[i][j] is not None: assert self.pathData[i][j] is None self.pathData[i][j] = partialData[i][j] ## def pathTableLookup(self, startNode, goalNode): ## ''' ## Look up the equivalent of pathData[goalNode][startNode] in our run-length encoded data. ## ''' ## if startNode >= self.numNodes or goalNode >= self.numNodes: ## raise "Invalid node ID. Must be less than self.numNodes (%s)." % self.numNodes ## str = self.pathData[startNode] ## pos = 0 ## while (pos < len(str)) and (256*ord(str[pos]) + ord(str[pos+1]) <= goalNode): ## #print pos, ": ",256*ord(str[pos]) + ord(str[pos+1]) ## pos += 3 ## pos -= 3 ## return ord(str[pos+2]) def findRoute(self, startNode, goalNode): ''' Returns the node-by-node route from startNode to goalNode. ''' return self.pathTable.findRoute(startNode, goalNode) def makeNodeLocator(self, environment): meshNode = CollisionNode("NavMeshNodeLocator") meshNode.setFromCollideMask(BitMask32.allOff()) meshNode.setIntoCollideMask(OTPGlobals.PathFindingBitmask) self.polyHashToPID = {} for pId in self.polyToAngles: vertCount = 0 corners = [] for angle in self.polyToAngles[pId]: if angle != 180: # It's a corner corners.append(vertCount) vertCount += 1 # XXX this code only works for square nodes at present # Unfortunately we can only make triangle or square CollisionPolygons on the fly assert len(corners) == 4 #import pdb #pdb.set_trace() verts = [] for vert in corners: verts.append( (self.vertexCoords[self.polyToVerts[pId][vert]][0], self.vertexCoords[self.polyToVerts[pId][vert]][1], 0)) #import pdb #pdb.set_trace() poly = CollisionPolygon(verts[0], verts[1], verts[2], verts[3]) assert poly not in self.polyHashToPID self.polyHashToPID[poly] = pId meshNode.addSolid(poly) ray = CollisionRay() ray.setDirection(0, 0, -1) ray.setOrigin(0, 0, 0) rayNode = CollisionNode("NavMeshRay") rayNode.setFromCollideMask(OTPGlobals.PathFindingBitmask) rayNode.setIntoCollideMask(BitMask32.allOff()) rayNode.addSolid(ray) self.meshNodePath = environment.attachNewNode(meshNode) self.rayNodePath = environment.attachNewNode(rayNode) self.meshNodePath.setTwoSided(True) self.chq = CollisionHandlerQueue() self.traverser = CollisionTraverser() self.traverser.addCollider(self.rayNodePath, self.chq) def findNodeFromPos(self, environment, x, y): self.rayNodePath.setPos(environment, x, y, 50000) self.chq.clearEntries() self.traverser.traverse(self.meshNodePath) if self.chq.getNumEntries() != 1: self.notify.warning("No node found at position: %s, %s in %s" % (x, y, environment)) return 0 e = self.chq.getEntry(0) assert e.hasInto() if not e.hasInto(): self.notify.warning("No into found for collision %s" % (e)) pId = self.polyHashToPID[e.getInto()] return pId # --------- Begin long-term storage code --------- def writeToFile(self, filename, storePathTable=True): ''' Output the contents of this mesh to the file specified. Saving to a file lets us avoid doing expensive precomputation every time a mesh instance is required. ''' if self.environmentHash is None: raise "Attempted write to file without valid environment hash!" if storePathTable and not self.pathData: raise "Attempted to write empty pathData. Call NavMesh.generatePathTable() first!" f = open(filename, 'wb') if storePathTable: pickle.dump([ self.environmentHash, self.polyToVerts, self.polyToAngles, self.vertexCoords, self.connections, self.pathData ], f, protocol=2) f.close() self.pathData = None else: pickle.dump([ self.environmentHash, self.polyToVerts, self.polyToAngles, self.vertexCoords, self.connections, None ], f, protocol=2) f.close() print "Successfully wrote to file %s." % filename def _initFromString(self, str): contents = pickle.loads(str) self.environmentHash = contents[0] self.polyToVerts = contents[1] self.polyToAngles = contents[2] self.vertexCoords = contents[3] self.connections = contents[4] self.pathData = contents[5] if self.pathData is not None: self.pathTable = PathTable(self.pathData, self.connections) self.pathData = None self.numNodes = len(self.connections) def _initFromFilename(self, filepath, filename): vfs = VirtualFileSystem.getGlobalPtr() filename = Filename(filename) searchPath = DSearchPath() #searchPath.appendDirectory(Filename('.')) #searchPath.appendDirectory(Filename('etc')) #searchPath.appendDirectory(Filename.fromOsSpecific(os.path.expandvars('~'))) #searchPath.appendDirectory(Filename.fromOsSpecific(os.path.expandvars('$HOME'))) searchPath.appendDirectory( Filename.fromOsSpecific(os.path.expandvars(filepath))) found = vfs.resolveFilename(filename, searchPath) if not found: raise IOError, "File not found!" str = vfs.readFile(filename, 1) self._initFromString(str) def checkHash(self, envHash): ''' "Does this mesh represent the environment I think it does?" If this check fails, the mesh is out of date (or being used with the wrong environment). In either case, whoever generated this instance should discard it and create a new mesh from scratch. ''' return envHash == self.environmentHash
class ArcadeFlightGame(ShowBase): def __init__(self): ShowBase.__init__(self) self.debug = False self.maxdistance = 400 self.statusLabel = self.makeStatusLabel(0) self.collisionLabel = self.makeStatusLabel(1) self.player = AlliedFlanker(self.loader, self.render, self.taskMgr) self.world = GameWorld(1024, self.loader, self.render, self.camera) self.taskMgr.add(self.updateTask, "update") self.keyboardSetup() # performance and map to player so can't fly beyond visible terrain self.player.setMaxHeight(self.maxdistance) if self.debug == False: self.camLens.setFar(self.maxdistance) else: base.oobe() self.camLens.setFov(60) self.setupCollisions() self.textCounter = 0 def makeStatusLabel(self, i): """ Create a status label at the top-left of the screen, Parameter 'i' is the row number """ return OnscreenText(style=2, fg=(.5,1,.5,1), pos=(-1.3,0.92-(.08 * i)), \ align=TextNode.ALeft, scale = .08, mayChange = 1) def keyboardSetup(self): self.keyMap = {"left":0, "right":0, "climb":0, "fall":0, \ "accelerate":0, "decelerate":0, "fire":0} self.accept("escape", sys.exit) self.accept("a", self.setKey, ["accelerate", 1]) self.accept("a-up", self.setKey, ["accelerate", 0]) self.accept("z", self.setKey, ["decelerate", 1]) self.accept("z-up", self.setKey, ["decelerate", 0]) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_down", self.setKey, ["climb", 1]) self.accept("arrow_down-up", self.setKey, ["climb", 0]) self.accept("arrow_up", self.setKey, ["fall", 1]) self.accept("arrow_up-up", self.setKey, ["fall", 0]) self.accept("space", self.setKey, ["fire", 1]) self.accept("space-up", self.setKey, ["fire", 0]) base.disableMouse() # or updateCamera will fail! def setKey(self, key, value): """ Used by keyboard setup """ self.keyMap[key] = value def setupCollisions(self): self.collTrav = CollisionTraverser() # rapid collisions detected using below plus FLUID pos self.collTrav.setRespectPrevTransform(True) self.playerGroundSphere = CollisionSphere(0, 1.5, -1.5, 1.5) self.playerGroundCol = CollisionNode('playerSphere') self.playerGroundCol.addSolid(self.playerGroundSphere) # bitmasks self.playerGroundCol.setFromCollideMask(BitMask32.bit(0)) self.playerGroundCol.setIntoCollideMask(BitMask32.allOff()) self.world.setGroundMask(BitMask32.bit(0)) self.world.setWaterMask(BitMask32.bit(0)) # and done self.playerGroundColNp = self.player.attach(self.playerGroundCol) self.playerGroundHandler = CollisionHandlerQueue() self.collTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler) # DEBUG as per video: if (self.debug == True): self.playerGroundColNp.show() self.collTrav.showCollisions(self.render) def updateTask(self, task): """ Gets added to the task manager, updates the player, deals with inputs, collisions, game logic etc. """ self.player.calculate() self.actionInput() validMove = self.player.move(self.world.getSize()) # lets not be doing this every frame... if validMove == False and self.textCounter > 30: self.statusLabel.setText("STATUS: MAP END; TURN AROUND") elif self.textCounter > 30: self.statusLabel.setText("STATUS: OK") if self.textCounter > 30: self.textCounter = 0 else: self.textCounter = self.textCounter + 1 self.updateCamera() self.collTrav.traverse(self.render) for i in range(self.playerGroundHandler.getNumEntries()): entry = self.playerGroundHandler.getEntry(i) if (self.debug == True): self.collisionLabel.setText("DEAD:" + str(globalClock.getFrameTime())) self.player.die() return Task.cont def actionInput(self): """ Used by updateTask to process keyboard input """ if (self.keyMap["climb"] != 0): self.player.climb() elif (self.keyMap["fall"] != 0): self.player.dive() else: self.player.unwindVertical() if (self.keyMap["left"] != 0): self.player.bankLeft() elif (self.keyMap["right"] != 0): self.player.bankRight() else: self.player.unwindHorizontal() if (self.keyMap["accelerate"] != 0): self.player.accelerate() elif (self.keyMap["decelerate"] != 0): self.player.brake() def updateCamera(self): self.player.lookAtMe(self.camera)