def checkcmcdlistlist(objcmlist0, objcmlist1, toggleplot=False): """ detect the collision between two collision model lists :return: True or False author: weiwei, Toyonaka date: 20190422 """ oocnp0 = NodePath("collision nodepath") oocnp1 = NodePath("collision nodepath") obj0cnplist = [] for objcm0 in objcmlist0: obj0cnplist.append(objcm0.copycdnpTo(oocnp0)) obj1cnplist = [] for objcm1 in objcmlist1: obj1cnplist.append(objcm1.copycdnpTo(oocnp1)) if toggleplot: oocnp0.reparentTo(base.render) oocnp1.reparentTo(base.render) for obj0cnp in obj0cnplist: obj0cnp.show() for obj1cnp in obj1cnplist: obj1cnp.show() ctrav = CollisionTraverser() chan = CollisionHandlerQueue() for obj0cnp in obj0cnplist: ctrav.addCollider(obj0cnp, chan) ctrav.traverse(oocnp1) if chan.getNumEntries() > 0: return True else: return False
class Boule_feu(Arme): def __init__(self, parent): Arme.__init__(self, parent) # init du rayon de la mort self.ray = CollisionRay(0, 0, 0, 0, 1, 0) rayNode = CollisionNode("boule_feu") rayNode.addSolid(self.ray) mask = BitMask32() mask.setBit(2) rayNode.setFromCollideMask(mask) maskI = BitMask32() maskI.setBit(0) rayNode.setIntoCollideMask(maskI) self.rayNodePath = render.attachNewNode(rayNode) self.rayQueue = CollisionHandlerQueue() self.parent.base.cTrav.addCollider(self.rayNodePath, self.rayQueue) self.ray.setOrigin(12, 9, 7) self.ray.setDirection(self.parent.heros.actor.getPos() - self.parent.sorcier.obj.getPos()) self.rayNodePath.show() def update(self, keys, dt): self.ray.setDirection(self.parent.heros.actor.getPos() - self.parent.sorcier.obj.getPos()) if self.rayQueue.getNumEntries() > 0: self.rayQueue.sortEntries() rayHit = self.rayQueue.getEntry(0) hitPos = rayHit.getSurfacePoint(render) hitNodePath = rayHit.getIntoNodePath() print(hitNodePath)
def checkcmcd(objcm1, objcm2, toggleplot=False): """ detect the collision between collision models :return: True or False author: weiwei, Toyonaka date: 20190312 """ oocnp = NodePath("collision nodepath") obj1cnp = objcm1.copycdnpTo(oocnp) obj2cnp = objcm2.copycdnpTo(oocnp) if toggleplot: oocnp.reparentTo(base.render) obj1cnp.show() obj2cnp.show() ctrav = CollisionTraverser() chan = CollisionHandlerQueue() ctrav.addCollider(obj1cnp, chan) ctrav.traverse(oocnp) if chan.getNumEntries() > 0: return True else: return False
def isCmListCmListCollided(objcmlist0, objcmlist1, toggleplot=False): """ detect the collision between two collision model lists :return: True or False author: weiwei, Toyonaka date: 20190422 """ oocnp = NodePath("collision nodepath") obj0cnplist = [] for objcm0 in objcmlist0: obj0cnplist.append(objcm0.copycdnpTo(oocnp)) obj1cnplist = [] for objcm1 in objcmlist1: obj1cnplist.append(objcm1.copycdnpTo(oocnp)) if toggleplot: oocnp.reparentTo(base.render) for obj0cnp in obj0cnplist: obj0cnp.show() for obj1cnp in obj1cnplist: obj1cnp.show() ctrav = CollisionTraverser() chan = CollisionHandlerQueue() for obj0cnp in obj0cnplist: obj0cnp.node().setFromCollideMask(BitMask32(0x1)) obj0cnp.setCollideMask(BitMask32(0x2)) ctrav.addCollider(obj0cnp, chan) ctrav.traverse(oocnp) if chan.getNumEntries() > 0: return True else: return False
def is_collided(objcm_list0, objcm_list1, toggle_contact_points=False, toggle_plot_cdprimit=False): """ detect the collision between collision models :param: objcm_list0, a single collision model or a list of collision models :param: objcm_list1 :return: True or False author: weiwei date: 20190312osaka, 20201214osaka """ if not isinstance(objcm_list0, list): objcm_list0 = [objcm_list0] if not isinstance(objcm_list1, list): objcm_list1 = [objcm_list1] if toggle_plot_cdprimit: for one_objcm in objcm_list0: one_objcm.show_cdprimit() for one_objcm in objcm_list1: one_objcm.show_cdprimit() tmpnp = NodePath("collision nodepath") ctrav = CollisionTraverser() chan = CollisionHandlerQueue() for one_objcm in objcm_list0: ctrav.addCollider(one_objcm.copy_cdnp_to(tmpnp), chan) for one_objcm in objcm_list1: one_objcm.copy_cdnp_to(tmpnp) ctrav.traverse(tmpnp) if chan.getNumEntries() > 0: if toggle_contact_points: contact_points = [da.pdv3_to_npv3(cd_entry.getSurfacePoint(base.render)) for cd_entry in chan.getEntries()] return True, contact_points else: return True else: return False
def isCmCmListCollided(objcm, objcmlist, toggleplot=False): """ detect the collision between a collision model and a collision model list :return: True or False author: weiwei, Toyonaka date: 20190312 """ oocnp = NodePath("collision nodepath") objcnp = objcm.copycdnpTo(oocnp) objcnplist = [] for objcm2 in objcmlist: objcnplist.append(objcm2.copycdnpTo(oocnp)) if toggleplot: oocnp.reparentTo(base.render) objcnp.show() for obj2cnp in objcnplist: obj2cnp.show() ctrav = CollisionTraverser() chan = CollisionHandlerQueue() ctrav.addCollider(objcnp, chan) ctrav.traverse(oocnp) if chan.getNumEntries() > 0: return True else: return False
class DPlayer(DistributedObject): def __init__(self, cr): DistributedObject.__init__(self, cr) self.name = "Player" self.piece = None self.pickerQueue = CollisionHandlerQueue() self.pickerRay = CollisionRay() pickerNode = CollisionNode('mouseRay') pickerNode.setFromCollideMask(BitMask32(0x80)) pickerNode.addSolid(self.pickerRay) self.pickerNP = base.camera.attachNewNode(pickerNode) base.cTrav.addCollider(self.pickerNP, self.pickerQueue) self.accept("mouse1", self.checkClick) def delete(self): """Cleanup just before the object gets deleted""" self.ignoreAll() base.cTrav.removeCollider(self.pickerNP) self.pickerNP.removeNode() if self.piece is not None: self.piece.sendDeleteMsg() DistributedObject.delete(self) def d_getName(self): self.sendUpdate("requestName") def setName(self, newName): self.name = newName base.messenger.send(self.cr.uniqueName("setPlayerName"), [self.name]) def setPiece(self, piece): self.piece = piece def checkClick(self): """Check if the player has clicked on a field and send a request to move to it to the server.""" if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.x, mpos.y) base.cTrav.traverse(render) if self.pickerQueue.getNumEntries() > 0: self.pickerQueue.sortEntries() pickedObj = self.pickerQueue.getEntry(0).getIntoNodePath() fieldName = pickedObj.getParent().getName() base.messenger.send("requestMoveToField", [fieldName]) def d_updateInventory(self): self.sendUpdate("updateInventory") def doUpdateInventory(self, level, inventoryDir): base.messenger.send("updateInventory", [level, inventoryDir]) def doUpdatePotions(self, numPotions): base.messenger.send("updateHealthPotions", [numPotions])
class Tree(object): def __init__(self, app, pos, level, index): self.hp = 200 * level self.app = app self.np = app.render.attachNewNode("tree%d" % index) self.np.setPos(pos) self.level = level self.pursuers = [] self.model = app.loader.loadModel('models/tree1') tex = app.loader.loadTexture("textures/"+'tree1'+".jpg") #Load the texture tex.setWrapU(Texture.WMClamp) # default is repeat, which will give tex.setWrapV(Texture.WMClamp) # artifacts at the edges self.model.setTexture(tex, 1) #Set the texture self.model.reparentTo(self.np) self.model.setHpr(uniform(-180,180),0,0) self.model.setScale(2) self.cn = self.np.attachNewNode(CollisionNode('tree_c_%d' % index)) self.cs = CollisionSphere(0,0.0,0.0,6) self.cn.node().addSolid(self.cs) self.cn.node().setFromCollideMask(BitMask32(0x01)) self.cn.node().setIntoCollideMask(BitMask32(0x00)) self.cqueue = CollisionHandlerQueue() app.cTrav.addCollider(self.cn, self.cqueue) def update(self, timer): for i in range(self.cqueue.getNumEntries()): collided_name = self.cqueue.getEntry(i).getIntoNodePath().getName() #enemy collision if collided_name[0] == 'e': self.app.enemy_manager.handle_collision(collided_name, self, timer) # drop loot when killed by panda if self.hp < 0: self.app.item_manager.add_item(self.np.getPos(), "upgrade", self.level) #hit by bullet if collided_name[0] == 'b': if self.hp < 0: bullet = self.app.bullet_manager.get_bullet(collided_name) bullet.apply_effect(self) self.app.bullet_manager.remove_bullet(collided_name) # tree is dead if self.hp < 0: for p in self.pursuers: p.ai_b.pursue(self.app.player.np) self.app.scene.remove(self) self.np.detachNode()
class Mouse(DirectObject): def __init__(self, levelNP): self.setCursor() # store the nodepath to the level collisions # will be used to check for intersections with the mouse ray self.levelNP = levelNP # Setup a traverser for the picking collisions self.picker = CollisionTraverser() # Setup mouse ray self.pq = CollisionHandlerQueue() # Create a collision Node pickerNode = CollisionNode('MouseRay') # set the nodes collision bitmask pickerNode.setFromCollideMask(BitMask32.bit(1))#GeomNode.getDefaultCollideMask()) # create a collision ray self.pickerRay = CollisionRay() # add the ray as a solid to the picker node pickerNode.addSolid(self.pickerRay) # create a nodepath with the camera to the picker node self.pickerNP = base.camera.attachNewNode(pickerNode) # add the nodepath to the base traverser self.picker.addCollider(self.pickerNP, self.pq) def setCursor(self): base.win.clearRejectedProperties() props = WindowProperties() if sys.platform.startswith('linux'): props.setCursorFilename("./assets/cursor.x11") else: props.setCursorFilename("./assets/cursor.ico") base.win.requestProperties(props) def getMousePos(self): # check if we have a mouse on the window if base.mouseWatcherNode.hasMouse(): # get the mouse position on the screen mpos = base.mouseWatcherNode.getMouse() # set the ray's position self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) # Now call the traverse function to let the traverser check for collisions # with the added colliders and the levelNP self.picker.traverse(self.levelNP) # check if we have a collision if self.pq.getNumEntries() > 0: # sort the entries to get the closest first self.pq.sortEntries() # This is the point at where the mouse ray and the level plane intersect hitPos = self.pq.getEntry(0).getSurfacePoint(render) return hitPos return Point3(0, 0, 0) task.cont
def get_dist_to_cell(self, pos): """Given a position, return the distance to the nearest cell below that position. If no cell is found, returns None.""" self.ray.setOrigin(pos) queue = CollisionHandlerQueue() self.traverser.addCollider(self.ray_nodepath, queue) self.traverser.traverse(self.cell_picker_world) self.traverser.removeCollider(self.ray_nodepath) queue.sortEntries() if not queue.getNumEntries(): return None entry = queue.getEntry(0) return (entry.getSurfacePoint(self.cell_picker_world) - pos).length()
class Mouse(object): def __init__(self, base): self.base = base if settings.mouse_over: taskMgr.add(self.mouse_task, 'mouse-task') self.picker = CollisionTraverser() self.pq = CollisionHandlerQueue() self.pickerNode = CollisionNode('mouseRay') self.pickerNP = self.base.cam.attachNewNode(self.pickerNode) self.pickerNode.setFromCollideMask( CollisionNode.getDefaultCollideMask() | GeomNode.getDefaultCollideMask()) self.pickerRay = CollisionRay() self.pickerNode.addSolid(self.pickerRay) self.picker.addCollider(self.pickerNP, self.pq) #self.picker.showCollisions(render) self.over = None def find_over(self): over = None if self.base.mouseWatcherNode.hasMouse(): mpos = self.base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(self.base.camNode, mpos.getX(), mpos.getY()) self.picker.traverse(render) if self.pq.getNumEntries() > 0: self.pq.sortEntries() np = self.pq.getEntry(0).getIntoNodePath().findNetPythonTag( 'owner') owner = np.getPythonTag('owner') over = owner np = self.pq.getEntry(0).getIntoNodePath().findNetPythonTag( 'patch') if np is not None: self.patch = np.getPythonTag('patch') else: self.patch = None return over def get_over(self): if settings.mouse_over: over = self.over else: over = self.find_over() return over def mouse_task(self, task): if self.mouseWatcherNode.hasMouse(): self.over = self.find_over() return Task.cont
def get_cell(self, pos): """Given a position, return the nearest cell below that position. If no cell is found, returns None.""" self.ray.setOrigin(pos) queue = CollisionHandlerQueue() self.traverser.addCollider(self.ray_nodepath, queue) self.traverser.traverse(self.cell_picker_world) self.traverser.removeCollider(self.ray_nodepath) queue.sortEntries() if not queue.getNumEntries(): return None entry = queue.getEntry(0) cnode = entry.getIntoNode() try: return self.cells_by_collider[cnode] except KeyError: raise Warning('collision ray collided with something ' 'other than a cell: %s' % cnode)
class Colisiones: def __init__(self, energy, jeep): self.bebidas = 0 self.energy = energy self.crash = [] self.jeep = jeep """ ---------------------- Prepara las Colisiones ---------------------- """ self.cs = CollisionSphere(0, 0, 0, 20) cont = 0 while (cont < 80): self.crash.append(self.energy[cont].attachNewNode( CollisionNode(str(cont)))) self.crash[cont].node().addSolid(self.cs) #self.crash[cont].show() Uncomment this line to see the colisions cont = cont + 1 self.css = CollisionSphere(0, 0, 0, 12) self.cnodePath = self.jeep.attachNewNode(CollisionNode('cnode')) self.cnodePath.node().addSolid(self.css) #self.cnodePath.show() Uncomment this line to see the colisions self.traverser = CollisionTraverser() self.queue = CollisionHandlerQueue() """ --------------------------------------------------------------------- """ taskMgr.add(self.choque, "choque") def choque(self, task): self.traverser.addCollider(self.cnodePath, self.queue) self.traverser.traverse(render) for i in range(self.queue.getNumEntries()): entry = self.queue.getEntry(i) self.energy[int(entry.getIntoNode().getName())].setPos(0, 0, 5000) self.bebidas = self.bebidas + 1 global texta texta.destroy() texta = addText( 0.9, -1.2, "Hasta Ahora LLevamos " + str(self.bebidas) + " Bebidas", 0.07) return Task.cont
def __endFireWater(self): if self.aimStart == None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return taskMgr.remove(self.waterPowerTaskName) messenger.send('wakeup') self.aimStart = None origin = self.nozzle.getPos(render) target = self.boss.getPos(render) angle = deg2Rad(self.waterPitcherNode.getH() + 90) x = math.cos(angle) y = math.sin(angle) fireVector = Point3(x, y, 0) if self.power < 0.001: self.power = 0.001 self.lastPowerFired = self.power fireVector *= self.fireLength * self.power target = origin + fireVector segment = CollisionSegment(origin[0], origin[1], origin[2], target[0], target[1], target[2]) fromObject = render.attachNewNode(CollisionNode('pitcherColNode')) fromObject.node().addSolid(segment) fromObject.node().setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) fromObject.node().setIntoCollideMask(BitMask32.allOff()) queue = CollisionHandlerQueue() base.cTrav.addCollider(fromObject, queue) base.cTrav.traverse(render) queue.sortEntries() self.hitObject = None if queue.getNumEntries(): entry = queue.getEntry(0) target = entry.getSurfacePoint(render) self.hitObject = entry.getIntoNodePath() base.cTrav.removeCollider(fromObject) fromObject.removeNode() self.d_firingWater(origin, target) self.fireWater(origin, target) self.resetPowerBar() return
class Colisiones: def __init__(self, energy, jeep): self.bebidas = 0 self.energy = energy self.crash = [] self.jeep = jeep """ ---------------------- Prepara las Colisiones ---------------------- """ self.cs = CollisionSphere(0, 0, 0, 20) cont = 0 while( cont < 80 ): self.crash.append( self.energy[cont].attachNewNode(CollisionNode(str(cont))) ) self.crash[cont].node().addSolid(self.cs) #self.crash[cont].show() Uncomment this line to see the colisions cont = cont + 1 self.css = CollisionSphere(0, 0, 0, 12) self.cnodePath = self.jeep.attachNewNode(CollisionNode('cnode')) self.cnodePath.node().addSolid(self.css) #self.cnodePath.show() Uncomment this line to see the colisions self.traverser = CollisionTraverser() self.queue = CollisionHandlerQueue() """ --------------------------------------------------------------------- """ taskMgr.add(self.choque, "choque") def choque(self, task): self.traverser.addCollider(self.cnodePath, self.queue) self.traverser.traverse(render) for i in range(self.queue.getNumEntries()): entry = self.queue.getEntry(i) self.energy[int( entry.getIntoNode().getName() )].setPos(0,0,5000) self.bebidas = self.bebidas + 1 global texta texta.destroy() texta = addText( 0.9, -1.2, "Hasta Ahora LLevamos " + str(self.bebidas) + " Bebidas", 0.07 ) return Task.cont
class Walker(): def __init__(self): colliderNode = CollisionNode(self.colliderName + "WallCollider") colliderNode.addSolid(CollisionSphere(0, 0, 0, 0.3)) self.collider = self.root.attachNewNode(colliderNode) self.collider.setPythonTag(TAG_OWNER, self) colliderNode.setFromCollideMask(MASK_WALLS) colliderNode.setIntoCollideMask(0) self.collider.setZ(self.height * 0.5) base.pusher.addCollider(self.collider, self.root) base.traverser.addCollider(self.collider, base.pusher) self.ray = CollisionRay(0, 0, self.height / 2, 0, 0, -1) rayNode = CollisionNode(self.colliderName + "Ray") rayNode.addSolid(self.ray) rayNode.setFromCollideMask(MASK_FLOORS) rayNode.setIntoCollideMask(0) self.rayNodePath = self.root.attachNewNode(rayNode) self.rayQueue = CollisionHandlerQueue() base.traverser.addCollider(self.rayNodePath, self.rayQueue) def update(self, dt): if self.rayQueue.getNumEntries() > 0: self.rayQueue.sortEntries() rayHit = self.rayQueue.getEntry(0) hitPos = rayHit.getSurfacePoint(render) self.root.setZ(hitPos.z) def cleanup(self): if self.collider is not None and not self.collider.isEmpty(): self.collider.clearPythonTag(TAG_OWNER) base.traverser.removeCollider(self.collider) base.pusher.removeCollider(self.collider) base.traverser.removeCollider(self.rayNodePath)
class MouseHandler: def __init__(self, camera, level): self.camera = camera self.level = level self.handler = CollisionHandlerQueue() self.traverser = CollisionTraverser('traverser') pickerNode = CollisionNode('mouseRay') pickerNP = self.camera.attachNewNode(pickerNode) pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.pickerRay = CollisionRay() pickerNode.addSolid(self.pickerRay) self.traverser.addCollider(pickerNP, self.handler) def pick_node(self, mpos): self.pickerRay.setFromLens(self.camera.getChild(0).node(), mpos.getX(), mpos.getY()) self.traverser.traverse(self.level) if self.handler.getNumEntries() > 0: self.handler.sortEntries() node = self.handler.getEntry(0).getIntoNodePath() if not node.isEmpty(): return node
class Player(GameObject): def __init__(self, modelName, model_anims, max_health, speed, collider_name, base, pos, hpr=Vec3(0, 0, 0), scale=1.0): GameObject.__init__(self, modelName, model_anims, max_health, speed, collider_name, base, pos, hpr, scale) self.player_init() def player_init(self): self.base.pusher.addCollider(self.collider, self.actor) self.base.cTrav.addCollider(self.collider, self.base.pusher) self.collider.setPythonTag("player", self) self.score = 0 self.score_string = str(self.score) # self.base.camLens.setFov(150) #---------------------------------------------- # self.base.camLens.setFov(5) self.textObject = OnscreenText(text='Score:' + self.score_string, pos=(-1.15, -0.95), scale=0.1) self.ray = CollisionRay(0, 0, 0, 0, -1, 0) rayNode = CollisionNode("playerRay") rayNode.addSolid(self.ray) self.rayNodePath = self.actor.attachNewNode(rayNode) self.rayQueue = CollisionHandlerQueue() self.base.cTrav.addCollider(self.rayNodePath, self.rayQueue) # self.damagePerSecond = -5.0 self.beamModel = self.base.loader.loadModel("models/frowney") self.beamModel.reparentTo(self.actor) self.beamModel.setZ(10) self.beamModel.setLightOff() self.beamModel.hide() def move(self, movement_vector): anim_controller = self.actor.getAnimControl("walk") if not anim_controller.isPlaying(): self.actor.play("walk") self.actor.setPos(self.actor, movement_vector * self.speed) def stop(self): anim_controller = self.actor.getAnimControl("walk") anim_controller.stop() def change_health(self, dHealth): GameObject.change_health(self, dHealth) if self.health == 0: # imageOnject = OnscreenImage(image = "game_over.png") self.cleanup() sys.exit() def update_score(self): self.score_string = str(self.score) self.textObject.destroy() self.textObject = OnscreenText(text='Score:' + self.score_string, pos=(-1.15, -0.95), scale=0.1) def shoot(self): dt = globalClock.getDt() # print(self.rayQueue.getNumEntries()) # print(self.rayQueue) if self.rayQueue.getNumEntries() > 0: self.rayQueue.sortEntries() rayHit = self.rayQueue.getEntry(1) hitPos = rayHit.getSurfacePoint(self.base.render) # print(hitPos, "hitpos") # print(rayHit, "rayhit") # beamLength = (hitPos - self.actor.getPos()).length() # print("length: ", beamLength) hitNodePath = rayHit.getIntoNodePath() # print(hitNodePath) # print(hitNodePath.getPythonTag) # print(hitPos) # print(hitNodePath.getTag) # print(hitNodePath.hasPythonTag("enemy")) # print(rayHit.getFrom()) if hitNodePath.hasPythonTag("enemy"): # print("here") hitObject = hitNodePath.getPythonTag("enemy") hitObject.change_health(-1) # Find out how long the beam is, and scale the # beam-model accordingly. # print(self.actor.getPos()) beamLength = (hitPos - (self.actor.getPos())).length() self.beamModel.setSy(-beamLength) self.score += 1 self.update_score() self.beamModel.show() else: # If we're not shooting, don't show the beam-model. self.beamModel.hide()
class World(DirectObject): def __init__(self): # This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Ball in Maze", style=1, fg=(1, 1, 1, 1), pos=(0.7, -0.95), scale=.07) self.instructions = OnscreenText(text="Press Esc to exit.", pos=(-1.3, .95), fg=(1, 1, 1, 1), align=TextNode.ALeft, scale=.05) base.setBackgroundColor(0, 0, 0) self.central_msg = OnscreenText(text="", pos=(0, 0), fg=(1, 1, 0, 1), scale=.1) self.central_msg.hide() self.accept("escape", sys.exit) # Escape quits base.disableMouse() # Disable mouse-based camera control camera.setPosHpr(0, 0, 25, 0, -90, 0) # Place the camera # Load the maze and place it in the scene self.maze = loader.loadModel("models/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 visable 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 # self.walls.show() # We will now find the triggers for the holes and set their masks to 0 as # well. We also set their names to make them easier to identify during # collisions self.loseTriggers = [] for i in range(6): trigger = self.maze.find("**/hole_collide" + str(i)) trigger.node().setIntoCollideMask(BitMask32.bit(0)) trigger.node().setName("loseTrigger") self.loseTriggers.append(trigger) # Uncomment this line to see the triggers # trigger.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. # 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 ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.55, .55, .55, 1)) 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)) self.ballRoot.setLight(render.attachNewNode(ambientLight)) self.ballRoot.setLight(render.attachNewNode(directionalLight)) # 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 = 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 # Create the movement task, but first make sure it is not already running taskMgr.remove("rollTask") self.mainLoop = taskMgr.add(self.rollTask, "rollTask") self.mainLoop.last = 0 # 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) # This is the task that deals with making everything interactive def rollTask(self, task): # Standard technique for finding the amount of time since the last frame dt = task.time - task.last task.last = task.time # If dt is large, then there has been a # hiccup that could cause the ball # to leave the field if this functions runs, so ignore the frame if dt > .2: return Task.cont # 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.cHandler.getNumEntries()): entry = self.cHandler.getEntry(i) name = entry.getIntoNode().getName() if name == "wall_collide": self.wallCollideHandler(entry) elif name == "ground_collide": self.groundCollideHandler(entry) elif name == "loseTrigger": self.loseGame(entry) # Read the mouse position and tilt the maze accordingly if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() # get the mouse position self.maze.setP(mpos.getY() * -10) self.maze.setR(mpos.getX() * 10) # Finally, we move the ball # Update the velocity based on acceleration self.ballV += self.accelV * dt * ACCEL # Clamp the velocity to the maximum speed if self.ballV.lengthSquared() > MAX_SPEED_SQ: self.ballV.normalize() self.ballV *= MAX_SPEED # Update the position based on the velocity self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV * dt)) # This block of code rotates the ball. It uses something called 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) return Task.cont # Continue the task indefinitely def show_message(self, message=''): if message: self.central_msg.setText(message) self.central_msg.show() else: self.central_msg.hide() # If the ball hits a hole trigger, then it should fall in the hole. # This is faked rather than dealing with the actual physics of it. def loseGame(self, entry): # The triggers are set up so that the center of the ball should move to the # collision point to be in the hole toPos = entry.getInteriorPoint(render) taskMgr.remove('rollTask') # Stop the maze task # Move the ball into the hole over a short sequence of time. Then wait a # second and call start to reset the game Sequence( Parallel( LerpFunc(self.ballRoot.setX, fromData=self.ballRoot.getX(), toData=toPos.getX(), duration=.1), LerpFunc(self.ballRoot.setY, fromData=self.ballRoot.getY(), toData=toPos.getY(), duration=.1), LerpFunc(self.ballRoot.setZ, fromData=self.ballRoot.getZ(), toData=self.ballRoot.getZ() - .9, duration=.2)), Func(self.show_message, "Try Again!"), Wait(1), Func(self.show_message, ""), Func(self.start)).start()
class Enemy(): def __init__(self, pos, index, app, manager, level, style): self.position = pos self.app = app self.np = app.render.attachNewNode("enemy%d" % index) if style == 1: self.np.setColorScale(1.0, 1.0, 1.0, 1.0) self.movespeed = 2.5 self.max_movespeed = 30 else: self.movespeed = 0.5 self.max_movespeed = 25 if style == 2: self.activate_delay = 0.01 self.np.setColorScale(0.6, 1.0, 1.0, 1.0) else: self.activate_delay = 0.1 if style == 3: self.hp = 50 * level self.np.setColorScale(0.0, 1.0, 0.5, 1.0) else: self.hp = 100 * level if style == 4: self.damage = 20 self.np.setColorScale(1.0, 1.0, 0.0, 1.0) else: self.damage = 10 self.dead = 0.0 self.level = level self.style = style self.particle_clean = False # this allows us to detach the instance nodepath # on death, but keep one with no model to attach particle effects self.dnp = app.render.attachNewNode("enemy_top%d" % index) self.np.setPos(self.position) self.np.setHpr(uniform(1,360),0,0) self.np.setScale(level) colsize = 3.0 self.cn = self.np.attachNewNode(CollisionNode('enemy_cn_%d' % index)) self.cs0 = CollisionSphere(0.0, colsize/2,0.0,colsize) self.cs1 = CollisionSphere(0.0, -colsize/2,0.0,colsize) self.cs2 = CollisionSphere(0.0, -colsize/3*4,0.0,colsize/2) self.cn.node().addSolid(self.cs0) self.cn.node().addSolid(self.cs1) self.cn.node().addSolid(self.cs2) #self.cn.show() # debug self.cqueue = CollisionHandlerQueue() app.cTrav.addCollider(self.cn, self.cqueue) self.cn.node().setIntoCollideMask(BitMask32(0x01)) self.cn.node().setFromCollideMask(BitMask32(0x10)) self.last_activated = 0.0 manager.add_instance(self) # name, nodepath, mass, move_force, max_force self.ai_char = AICharacter('enemy_ai_%d' % index, self.np, 100, self.movespeed, self.max_movespeed) app.ai_world.addAiChar(self.ai_char) self.ai_b = self.ai_char.getAiBehaviors() self.ai_b.pursue(app.player.np) self.load_particle_config() def update(self, time): a = 0 # Handle collsions for i in range(self.cqueue.getNumEntries()): collided_name = self.cqueue.getEntry(i).getIntoNodePath().getName() #handle bullets if collided_name[0] == 'b': bullet = self.app.bullet_manager.get_bullet(collided_name) bullet.apply_effect(self) self.app.bullet_manager.remove_bullet(collided_name) if self.cqueue.getNumEntries() != 0: self.np.setColorScale(1.0, self.hp / 100.0, self.hp / 100.0, 1.0) """ desired = self.app.player.position - self.np.getPos() angle = degrees(atan2(desired.y, desired.x)) hpr = self.np.getHpr() if hpr.x > 360: hpr.x = hpr.x - 360 if hpr.x < -360: hpr.x = hpr.x + 360 diff = angle - hpr.x if diff > 180.0: diff = diff - 360 if diff < -180.0: diff = diff + 360 if diff > 5.0: diff = 5.0 if diff < -5.0: diff = -5.0 new = Vec3(diff, 0, 0) + hpr #self.np.setHpr(new) # move forward r = radians(new.x) curr = self.np.getPos() diff = Vec3(self.movespeed * cos(r), self.movespeed * sin(r), 0) self.np.setPos(curr + diff)""" if self.hp < 0.0 and self.dead == 0.0: self.dead = time self.app.scene.remove(self) # Create particle effect before we go self.dnp.setPos(self.np.getPos()) self.particles.start(parent = self.dnp, renderParent = self.app.render) self.np.detachNode() # Drop some loot self.app.item_manager.add_item(self.np.getPos(), "soul", self.level) # Give the player some points self.app.player.score = self.app.player.score + 100 def apply_effect(self, target, timer): if self.last_activated - timer + self.activate_delay < 0.0: self.last_activated = timer target.hp = target.hp - self.damage if target.np.getName()[0] == 't': target.pursuers.append(self) #self.ai_b = self.ai_char.getAiBehaviors() #self.ai_b.pursue(self.np.getPos()) self.ai_b.pauseAi("pursue") def load_particle_config(self): self.particles = ParticleEffect() self.particles.reset() self.particles.setPos(0.000, 0.000, 0.000) self.particles.setHpr(0.000, 0.000, 0.000) self.particles.setScale(1.000, 1.000, 1.000) p0 = Particles('particles-1') # Particles parameters p0.setFactory("PointParticleFactory") p0.setRenderer("SpriteParticleRenderer") p0.setEmitter("SphereVolumeEmitter") p0.setPoolSize(20) p0.setBirthRate(0.0100) p0.setLitterSize(20) p0.setLitterSpread(0) p0.setSystemLifespan(1.0100) p0.setLocalVelocityFlag(1) p0.setSystemGrowsOlderFlag(1) # Factory parameters p0.factory.setLifespanBase(1.0000) p0.factory.setLifespanSpread(0.0000) p0.factory.setMassBase(1.0000) p0.factory.setMassSpread(0.0100) p0.factory.setTerminalVelocityBase(1200.0000) p0.factory.setTerminalVelocitySpread(0.0000) # Point factory parameters # Renderer parameters p0.renderer.setAlphaMode(BaseParticleRenderer.PRALPHAOUT) p0.renderer.setUserAlpha(0.05) # Sprite parameters p0.renderer.setTexture(self.app.loader.loadTexture('effects/dust.png')) p0.renderer.setColor(Vec4(1.00, 0.10, 0.10, 0.50)) p0.renderer.setXScaleFlag(2) p0.renderer.setYScaleFlag(2) p0.renderer.setAnimAngleFlag(0) p0.renderer.setInitialXScale(0.100 * self.level) p0.renderer.setFinalXScale(0.200 * self.level) p0.renderer.setInitialYScale(0.100 * self.level) p0.renderer.setFinalYScale(0.200 * self.level) p0.renderer.setNonanimatedTheta(0.0000) p0.renderer.setAlphaBlendMethod(BaseParticleRenderer.PPBLENDLINEAR) p0.renderer.setAlphaDisable(0) # Emitter parameters p0.emitter.setEmissionType(BaseParticleEmitter.ETRADIATE) p0.emitter.setAmplitude(1.0000) p0.emitter.setAmplitudeSpread(0.0000) p0.emitter.setOffsetForce(Vec3(0.0000, 0.0000, 0.0000)) p0.emitter.setExplicitLaunchVector(Vec3(1.0000, 0.0000, 0.0000)) p0.emitter.setRadiateOrigin(Point3(0.0000, 0.0000, 0.0000)) # Sphere Volume parameters p0.emitter.setRadius(0.1000) self.particles.addParticles(p0) f0 = ForceGroup('gravity') # Force parameters self.particles.addForceGroup(f0)
class World(DirectObject): def __init__(self): #This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Panda3D: Tutorial - Mouse Picking", style=1, fg=(1, 1, 1, 1), pos=(0.8, -0.95), scale=.07) self.escapeEvent = OnscreenText( text="ESC: Quit", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.95), align=TextNode.ALeft, scale=.05) self.mouse1Event = OnscreenText( text="Left-click and drag: Pick up and drag piece", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.90), align=TextNode.ALeft, scale=.05) self.accept('escape', sys.exit) #Escape quits base.disableMouse() #Disble mouse camera control camera.setPosHpr(0, -13.75, 6, 0, -25, 0) #Set the camera self.setupLights() #Setup default lighting #Since we are using collision detection to do picking, we set it up like #any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() #Make a traverser self.pq = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') #Attach that node to the camera since the ray will need to be positioned #relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() #Make our ray self.pickerNode.addSolid(self.pickerRay) #Add it to the collision node #Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) #self.picker.showCollisions(render) #Now we create the chess board and its pieces #We will attach all of the squares to their own root. This way we can do the #collision pass just on the sqaures and save the time of checking the rest #of the scene self.squareRoot = render.attachNewNode("squareRoot") #For each square self.squares = [None for i in range(64)] self.pieces = dict((i, None) for i in range(64)) #MOD for i in range(64): #Load, parent, color, and position the model (a single square polygon) self.squares[i] = loader.loadModel("models/square") self.squares[i].reparentTo(self.squareRoot) self.squares[i].setPos(SquarePos(i)) self.squares[i].setColor(SquareColor(i)) #Set the model itself to be collideable with the ray. If this model was #any more complex than a single polygon, you should set up a collision #sphere around it instead. But for single polygons this works fine. self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) #Set a tag on the square's node so we can look up what square this is #later during the collision pass self.squares[i].find("**/polygon").node().setTag('square', str(i)) #We will use this variable as a pointer to whatever piece is currently #in this square #The order of pieces on a chessboard from white's perspective. This list #contains the constructor functions for the piece classes defined below pieceOrder = (Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook) for i in range(8, 16): #Load the white pawns self.pieces[i] = Pawn(i, WHITE) for i in range(48, 56): #load the black pawns self.pieces[i] = Pawn(i, PIECEBLACK) for i in range(8): #Load the special pieces for the front row and color them white self.pieces[i] = pieceOrder[i](i, WHITE) #Load the special pieces for the back row and color them black self.pieces[i + 56] = pieceOrder[i](i + 56, PIECEBLACK) #This will represent the index of the currently highlited square self.hiSq = False #This wil represent the index of the square where currently dragged piece #was grabbed from self.dragging = False #Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') self.accept("mouse1", self.grabPiece) #left-click grabs a piece self.accept("mouse1-up", self.releasePiece) #releasing places it #This function swaps the positions of two pieces def swapPieces(self, fr, to): temp = self.pieces[fr] self.pieces[fr] = self.pieces[to] self.pieces[to] = temp if self.pieces[fr]: self.pieces[fr].square = fr self.pieces[fr].obj.setPos(SquarePos(fr)) if self.pieces[to]: self.pieces[to].square = to self.pieces[to].obj.setPos(SquarePos(to)) def mouseTask(self, task): #This task deals with the highlighting and dragging based on the mouse #First, clear the current highlight if self.hiSq is not False: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = False #Check to see if we can access the mouse. We need it to do anything else if base.mouseWatcherNode.hasMouse(): #get the mouse position mpos = base.mouseWatcherNode.getMouse() #Set the position of the ray based on the mouse position self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) #If we are dragging something, set the position of the object #to be at the appropriate point over the plane of the board if self.dragging is not False: #Gets the point described by pickerRay.getOrigin(), which is relative to #camera, relative instead to render nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin()) #Same thing with the direction of the ray nearVec = render.getRelativeVector(camera, self.pickerRay.getDirection()) self.pieces[self.dragging].obj.setPos( PointAtZ(.5, nearPoint, nearVec)) #Do the actual collision pass (Do it only on the squares for #efficiency purposes) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: #if we have hit something, sort the hits so that the closest #is first, and highlight that node self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) #Set the highlight on the picked square self.squares[i].setColor(HIGHLIGHT) self.hiSq = i return Task.cont def grabPiece(self): #If a square is highlighted and it has a piece, set it to dragging mode if (self.hiSq is not False and self.pieces[self.hiSq]): self.dragging = self.hiSq self.hiSq = False def releasePiece(self): #Letting go of a piece. If we are not on a square, return it to its original #position. Otherwise, swap it with the piece in the new square if self.dragging is not False: #Make sure we really are dragging something #We have let go of the piece, but we are not on a square if self.hiSq is False: self.pieces[self.dragging].obj.setPos( SquarePos(self.dragging)) else: #Otherwise, swap the pieces self.swapPieces(self.dragging, self.hiSq) #We are no longer dragging anything self.dragging = False def setupLights(self): #This function sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.8, .8, .8, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(0, 45, -45)) directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight))
class HitscanWeapon(Weapon): def __init__(self, mask, damage, knockback, range=None): Weapon.__init__(self, mask, range, damage, knockback) if range is None: self.ray = CollisionRay(0, 0, 0, 0, 1, 0) else: self.ray = CollisionSegment(0, 0, 0, 1, 0, 0) rayNode = CollisionNode("playerRay") rayNode.addSolid(self.ray) rayNode.setFromCollideMask(mask) rayNode.setIntoCollideMask(0) self.rayNodePath = render.attachNewNode(rayNode) self.rayQueue = CollisionHandlerQueue() self.traverser = CollisionTraverser() self.traverser.addCollider(self.rayNodePath, self.rayQueue) def performRayCast(self, origin, direction): if isinstance(self.ray, CollisionRay): self.ray.setOrigin(origin) self.ray.setDirection(direction) else: self.ray.setPointA(origin) self.ray.setPointB(origin + direction * self.range) self.traverser.traverse(render) if self.rayQueue.getNumEntries() > 0: self.rayQueue.sortEntries() rayHit = self.rayQueue.getEntry(0) return True, rayHit else: return False, None def fire(self, owner, dt): Weapon.fire(self, owner, dt) rayDir = owner.weaponNP.getQuat(render).getForward() hit, hitEntry = self.performRayCast(owner.weaponNP.getPos(render), rayDir) if hit: hitNP = hitEntry.getIntoNodePath() if hitNP.hasPythonTag(TAG_OWNER): subject = hitNP.getPythonTag(TAG_OWNER) subject.alterHealth(-self.damage, rayDir * self.knockback, self.flinchValue) def cleanup(self): self.traverser.removeCollider(self.rayNodePath) self.traverser = None if self.rayNodePath is not None: self.rayNodePath.removeNode() self.rayNodePath = None Weapon.cleanup(self)
class Physics: def __init__(self): self.rayCTrav = CollisionTraverser("collision traverser for ray tests") #self.pusher = PhysicsCollisionHandler() self.pusher = CollisionHandlerPusher() self.pusher.addInPattern('%fn-in-%in') self.pusher.addOutPattern('%fn-out-%in') self.pusher.addInPattern('%fn-in') self.pusher.addOutPattern('%fn-out') def startPhysics(self): #self.actorNode = ActorNode("playerPhysicsControler") #base.physicsMgr.attachPhysicalNode(self.actorNode) #self.actorNode.getPhysicsObject().setMass(self.player_mass) #self.mainNode = render.attachNewNode(self.actorNode) self.mainNode = render.attachNewNode("CharacterColliders") self.reparentTo(self.mainNode) charCollisions = self.mainNode.attachNewNode(CollisionNode(self.char_collision_name)) #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0, self.player_height/4.0)) #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0*3.05, self.player_height/4.0)) charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/2.0, self.player_height/4.0)) charCollisions.node().setIntoCollideMask(BitMask32(0x80)) # 1000 0000 if self.show_collisions: charCollisions.show() self.pusher.addCollider(charCollisions, self.mainNode) base.cTrav.addCollider(charCollisions, self.pusher) charFFootCollisions = self.attachNewNode(CollisionNode("floor_ray")) charFFootCollisions.node().addSolid(CollisionRay(0, 0, 0.5, 0, 0, -1)) #charFFootCollisions.node().addSolid(CollisionSegment((0, 0, 0.2), (0, 0, -1))) charFFootCollisions.node().setIntoCollideMask(BitMask32.allOff()) charFFootCollisions.node().setFromCollideMask(BitMask32(0x7f)) # 0111 1111 if self.show_collisions: charFFootCollisions.show() self.floor_handler = CollisionHandlerFloor() self.floor_handler.addCollider(charFFootCollisions, self.mainNode) #self.floor_handler.setOffset(0) self.floor_handler.setMaxVelocity(5) base.cTrav.addCollider(charFFootCollisions, self.floor_handler) self.accept("{}-in".format(self.char_collision_name), self.checkCharCollisions) self.raytest_segment = CollisionSegment(0, 1) self.raytest_np = render.attachNewNode(CollisionNode("testRay")) self.raytest_np.node().addSolid(self.raytest_segment) self.raytest_np.node().setIntoCollideMask(BitMask32.allOff()) self.raytest_np.node().setFromCollideMask(BitMask32(0x7f)) # 0111 1111 if self.show_collisions: self.raytest_np.show() self.raytest_queue = CollisionHandlerQueue() self.rayCTrav.addCollider(self.raytest_np, self.raytest_queue) def stopPhysics(self): self.raytest_segment.removeNode() self.pusher.clearColliders() self.floor_handler.clearColliders() self.rayCTrav.clearColliders() def updatePlayerPos(self, speed, heading, dt): if heading is not None: self.mainNode.setH(camera, heading) self.mainNode.setP(0) self.mainNode.setR(0) self.mainNode.setFluidPos(self.mainNode, speed) self.doStep() def checkCharCollisions(self, args): self.doStep() def doStep(self): # do the step height check tmpNP = self.mainNode.attachNewNode("temporary") tmpNP.setPos(self.mainNode, 0, 0, -self.stepheight) pointA = self.mainNode.getPos(render) pointA.setZ(pointA.getZ() + self.player_height/1.8) pointB = tmpNP.getPos(render) if pointA == pointB: return char_step_collision = self.getFirstCollisionInLine(pointA, pointB) tmpNP.removeNode() if char_step_collision is not None: self.mainNode.setFluidZ(char_step_collision.getZ()) return True return False def getFirstCollisionInLine(self, pointA, pointB): """A simple raycast check which will return the first collision point as seen from point A towards pointB""" self.raytest_segment.setPointA(pointA) self.raytest_segment.setPointB(pointB) self.rayCTrav.traverse(render) self.raytest_queue.sortEntries() pos = None if self.raytest_queue.getNumEntries() > 0: pos = self.raytest_queue.getEntry(0).getSurfacePoint(render) return pos
class World(DirectObject): def __init__(self): self.startvar = 0 self.startdialog = YesNoDialog(dialogName="START GAME", text="START GAME", command=self.endbox) self.timepass = model() self.timepass1 = model1() self.keyMap = {"left": 0, "right": 0, "forward": 0, "backward": 0} base.win.setClearColor(Vec4(0, 0, 0, 1)) # number of collectibles self.numObjects = 0 #music self.backmusic = base.loader.loadSfx("sounds/tales.mp3") self.backmusic.setLoop(True) self.backmusic.setVolume(0.2) self.backmusic.play() self.skatemusic = base.loader.loadSfx("sounds/skate.mp3") self.skatemusic.setVolume(.65) self.skatemusic.setLoop(True) self.bombmusic = base.loader.loadSfx("sounds/bomb.mp3") self.bombmusic.setVolume(.85) self.springmusic = base.loader.loadSfx("sounds/spring.mp3") self.springmusic.setVolume(.65) self.springmusic.setLoop(True) self.colmusic = base.loader.loadSfx("sounds/collect.mp3") self.colmusic.setVolume(.65) # print the number of objects printNumObj(self.numObjects) # Post the instructions # self.title = addTitle("Roaming Ralph (Edited by Adam Gressen)") # self.inst1 = addInstructions(0.95, "[ESC]: Quit") # self.inst2 = addInstructions(0.90, "[A]: Rotate Ralph Left") # self.inst3 = addInstructions(0.85, "[D]: Rotate Ralph Right") # self.inst4 = addInstructions(0.80, "[W]: Run Ralph Forward") # self.inst5 = addInstructions(0.75, "[S]: Run Ralph Backward") # self.inst6 = addInstructions(0.70, "[Space]: Run, Ralph, Run") # 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("models/world") self.environ.reparentTo(render) self.environ.setPos(0, 0, 0) # Timer to increment in the move task self.time = 0 # Get bounds of environment min, max = self.environ.getTightBounds() self.mapSize = max - min # Create the main character, Ralph self.ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor( "models/ralph", { "run": "models/ralph-run", "jump": "models/ralph-jump", "walk": "models/ralph-walk" }) self.ralph.reparentTo(render) self.ralph.setScale(.30) self.ralph.setPos(self.ralphStartPos) #skate self.skate = loader.loadModel("models/Skateboard") self.skate.reparentTo(render) self.skate.setScale(.02) self.skate.setPos(-random.randint(38, 50), -random.randint(15, 37), -0.015) # ralph's health self.health = 100 #spring self.spring = loader.loadModel("models/spring") self.spring.reparentTo(render) self.spring.setScale(.8) self.spring.setPos(-random.randint(72, 78), -random.randint(10, 15), 6.715) # ralph's stamina self.stamina = 100 # 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) # these don't work well in combination with the space bar 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("arrow_down", self.setKey, ["backward", 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("arrow_down-up", self.setKey, ["backward", 0]) 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]) # Game state variables self.isMoving = False self.isRunning = False self.onboard = 0 self.boardtime = 0 self.onspring = 0 self.isjumping = False # Set up the camera base.disableMouse() #base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,2) base.camera.setPos(0, 0, 0) base.camera.reparentTo(self.ralph) base.camera.setPos(0, 40, 2) base.camera.lookAt(self.ralph) # 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. base.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 300) 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() base.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) # camera ground collision handler self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0, 0, 300) 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() base.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Place the health items self.placeHealthItems() # Place the collectibles self.placeCollectibles() # Place the bomb self.placebombItems() # Uncomment this line to show a visual representation of the # collisions occuring #base.cTrav.showCollisions(render) # Create some lighting 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)) #print self.startvar taskMgr.add(self.move, "moveTask") #taskMgr.doMethodLater(0.5, self.healthDec, "healthTask") # Display ralph's health def displayHealth(self): healthBar['scale'] = (self.health * 0.01 * BAR_WIDTH, 0.2, 0.2) # Display ralph's stamina def displayStamina(self): sprintBar['scale'] = (self.stamina * 0.01 * BAR_WIDTH, 0.2, 0.2) # Allow ralph to collect the health items def collectHealthItems(self, entry): # refill ralph's health self.colmusic.play() if (self.health < 100): self.health = self.health + 15.5 # reposition the collectible self.placeItem(entry.getIntoNodePath().getParent()) def collectCollectibles(self, entry): # remove the collectible #entry.getIntoNodePath().getParent().removeNode() self.colmusic.play() self.placeItem(entry.getIntoNodePath().getParent()) # update the number of objects self.numObjects += 1 #self.tot=10-self.numObjects printNumObj(self.numObjects) def blastbomb(self): # remove the collectible #self.placeItem(entry.getIntoNodePath().getParent()) # blast self.fire = loader.loadModel("models/fire") self.fire.reparentTo(render) self.fire.setScale(.01) self.fire.setHpr(0, -90, 0) self.bombmusic.play() self.backmusic.stop() self.fire.setPos(self.ralph.getPos()) self.die() # Places an item randomly on the map def placeItem(self, item): # Add ground collision detector to the health item self.collectGroundRay = CollisionRay() self.collectGroundRay.setOrigin(0, 0, 300) self.collectGroundRay.setDirection(0, 0, -1) self.collectGroundCol = CollisionNode('colRay') self.collectGroundCol.addSolid(self.collectGroundRay) self.collectGroundCol.setFromCollideMask(BitMask32.bit(0)) self.collectGroundCol.setIntoCollideMask(BitMask32.allOff()) self.collectGroundColNp = item.attachNewNode(self.collectGroundCol) self.collectGroundHandler = CollisionHandlerQueue() base.cTrav.addCollider(self.collectGroundColNp, self.collectGroundHandler) placed = False while placed == False: # re-randomize position item.setPos(-random.randint(-40, 140), -random.randint(-40, 40), 0) base.cTrav.traverse(render) # Get Z position from terrain collision entries = [] for j in range(self.collectGroundHandler.getNumEntries()): entry = self.collectGroundHandler.getEntry(j) 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"): item.setZ(entries[0].getSurfacePoint(render).getZ() + 1) placed = True # remove placement collider self.collectGroundColNp.removeNode() def placeHealthItems(self): self.placeholder = render.attachNewNode("HealthItem-Placeholder") self.placeholder.setPos(0, 0, 0) # Add the health items to the placeholder node for i in range(5): # Load in the health item model self.healthy = loader.loadModel("models/sphere") self.healthy.setPos(0, 0, 0) self.healthy.setScale(.4) self.healthy.reparentTo(self.placeholder) self.placeItem(self.healthy) # Add spherical collision detection healthSphere = CollisionSphere(0, 0, 0, 1.4) sphereNode = CollisionNode('healthSphere') sphereNode.addSolid(healthSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.healthy.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) #bomb def placebombItems(self): self.placebomb = render.attachNewNode("bomb-Placeholder") self.placebomb.setPos(0, 0, 0) # Add the bomb items to the placeholder node for i in range(30): # Load in the health item model self.bomby = loader.loadModel("models/bomb") self.bomby.setPos(0, 0, 0) self.bomby.setScale(.4) self.bomby.reparentTo(self.placebomb) self.placeItem(self.bomby) # Add spherical collision detection bombSphere = CollisionSphere(0, 0, 0, 1.4) sphereNode = CollisionNode('bombSphere') sphereNode.addSolid(bombSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.bomby.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) #blue def placeCollectibles(self): self.placeCol = render.attachNewNode("Collectible-Placeholder") self.placeCol.setPos(0, 0, 0) # Add the health items to the placeCol node for i in range(50): # Load in the health item model self.collect = loader.loadModel("models/jack") self.collect.setPos(0, 0, 0) self.collect.setScale(.4) self.collect.reparentTo(self.placeCol) self.placeItem(self.collect) # Add spherical collision detection colSphere = CollisionSphere(0, 0, 0, 1.4) sphereNode = CollisionNode('colSphere') sphereNode.addSolid(colSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.collect.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Makes ralph's health decrease over time # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): #print self.ralph.getPos() self.time += globalClock.getDt() timeText['text'] = str(self.time) # 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. # and rotate the camera to remain behind ralph if (self.keyMap["left"] != 0) and (self.onboard == 0): self.ralph.setH(self.ralph.getH() + 100 * globalClock.getDt()) if (self.keyMap["right"] != 0) and (self.onboard == 0): self.ralph.setH(self.ralph.getH() - 100 * globalClock.getDt()) if (self.keyMap["forward"] != 0) and (self.onboard == 0): self.ralph.setY(self.ralph, -45 * globalClock.getDt()) if (self.keyMap["backward"] != 0) and (self.onboard == 0): self.ralph.setY(self.ralph, 45 * globalClock.getDt()) if (self.keyMap["forward"] != 0) and (self.onboard == 0) and (self.onspring > 0): self.ralph.setY(self.ralph, -65 * globalClock.getDt()) if (self.keyMap["backward"] != 0) and (self.onboard == 0) and (self.onspring > 0): self.ralph.setY(self.ralph, +65 * globalClock.getDt()) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.isMoving): if (self.health <= 0): self.ralph.setPos(10000, 10000, 1000) self.ralph.stop() self.blastbomb() else: self.health -= .07 if ((self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0) or (self.keyMap["right"] != 0) or (self.keyMap["backward"] != 0)) and (self.onboard == 0): if self.isMoving is False: self.ralph.loop("run") self.isMoving = True else: if self.isMoving and (self.onspring == 0): self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False #skate if (math.fabs(self.skate.getX() - self.ralph.getX()) < 2) and (math.fabs(self.skate.getY() - self.ralph.getY()) < 5) and (self.onspring == 0) and (self.onboard == 0): self.onboard = 1 self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False self.isjumping = False self.skatemusic.play() if (self.onboard == 1): if (self.keyMap["left"] != 0): self.ralph.setH(self.ralph.getH() + 60 * globalClock.getDt()) self.skate.setH(self.ralph.getH()) if (self.keyMap["right"] != 0): self.ralph.setH(self.ralph.getH() - 60 * globalClock.getDt()) self.skate.setH(self.ralph.getH()) if (self.keyMap["forward"] != 0): self.ralph.setY(self.ralph, -100 * globalClock.getDt()) self.skate.setY(self.ralph.getY()) self.skate.setZ(self.ralph.getZ()) self.skate.setX(self.ralph.getX()) if (self.keyMap["backward"] != 0): self.ralph.setY(self.ralph, 100 * globalClock.getDt()) self.skate.setY(self.ralph.getY()) self.skate.setZ(self.ralph.getZ()) self.skate.setX(self.ralph.getX()) self.boardtime = self.boardtime + 1 #self.ralph.stop() #self.ralph.pose("walk",5) #print self.onboard if (self.boardtime == 1000): self.onboard = 0 self.boardtime = 0 self.skate.setPos(-random.randint(72, 78), -random.randint(10, 15), 6.715) self.skatemusic.stop() #spring #spring if (math.fabs(self.spring.getX() - self.ralph.getX()) < 2) and (math.fabs(self.spring.getY() - self.ralph.getY()) < 2) and (self.onboard == 0) and (self.onspring == 0): self.onspring = 500 self.springmusic.play() self.spring.setPos(-random.randint(38, 50), -random.randint(15, 37), -0.015) if (self.onspring > 0): self.onspring = self.onspring - 1 #print self.onspring if (self.isjumping is False): self.ralph.loop("jump") self.isjumping = True else: #print self.ralph.getX() if self.isjumping: if ((self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0) or (self.keyMap["right"] != 0)): self.ralph.loop("run") self.isMoving = True else: self.ralph.stop() self.ralph.pose("walk", 5) self.isjumping = False self.onspring = 0 self.springmusic.stop() # so the following line is unnecessary base.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()) #base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+5) elif (len(entries) > 0) and (entries[0].getIntoNode().getName() == "healthSphere"): self.collectHealthItems(entries[0]) elif (len(entries) > 0) and (entries[0].getIntoNode().getName() == "colSphere"): self.collectCollectibles(entries[0]) elif (len(entries) > 0) and (entries[0].getIntoNode().getName() == "bombSphere"): self.blastbomb() else: self.ralph.setPos(startpos) # Keep the camera above the terrain 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"): modZ = entries[0].getSurfacePoint(render).getZ() base.camera.setZ(10.0 + modZ + (modZ - self.ralph.getZ())) self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + 2.0) base.camera.lookAt(self.floater) self.displayHealth() return task.cont # End def die(self): # end all running tasks self.ralph.setPos(10000, 10000, 10000) taskMgr.remove("moveTask") taskMgr.remove("healthTask") self.ralph.stop() self.skatemusic.stop() self.springmusic.stop() self.backmusic.stop() colObj = self.numObjects myscore = str(colObj) self.highscore = OkDialog(dialogName="highscoreDialog", text="Your Score: " + myscore, command=self.endResult) # Handle the dialog result def endResult(self, arg): sys.exit() def endbox(self, arg): if (arg): self.startvar = 1 self.startdialog.cleanup() # restart the game #self.restart() else: sys.exit()
class Controller(): # Конструктор def __init__(self): # значение шага перемещения клавиатурой self.key_step = 0.2 # значение шага поворота мышкой self.mouse_step = 0.2 # координаты центра экрана self.x_center = base.win.getXSize() // 2 self.y_center = base.win.getYSize() // 2 # перемещаем указатель мышки в центр экрана base.win.movePointer(0, self.x_center, self.y_center) # отключаем стандартное управление мышкой base.disableMouse() # устанавливаем поле зрения объектива base.camLens.setFov(80) # устанавливаем ближайшую границу отрисовки base.camLens.setNear(0.2) # устанавливаем текущие значения ориентации камеры self.heading = 0 self.pitch = 0 # запускаем задачу контроля камеры taskMgr.doMethodLater(0.02, self.controlCamera, "camera-task") # регистрируем на нажатие клавиши "Esc" # событие закрытия приложения base.accept("escape", base.userExit) # устанавливаем клавиши управления перемещением камеры # словарь, хранящий флаги нажатия клавиш self.keys = dict() # заполняем словарь for key in ['a', 'd', 'w', 's', 'q', 'e', 'space']: # создаём запись в словаре self.keys[key] = 0 # регистрируем событие на нажатие клавиши base.accept(key, self.setKey, [key, 1]) # регистрируем событие на отжатие клавиши base.accept(key + '-up', self.setKey, [key, 0]) # создание обходчика столкновений self.traverser = CollisionTraverser() # очередь обработки столкновений self.collisQueue = CollisionHandlerQueue() # узел для сферы столкновений self.collisNode = CollisionNode('CameraSphere') # устанавливаем маску проверки столкновений ОТ self.collisNode.setFromCollideMask(BitMask32.bit(1)) # сбрасываем маску проверки столкновений ДО self.collisNode.setIntoCollideMask(BitMask32.allOff()) # создаём сферу столкновения радиусом 0.95 collisSphere = CollisionSphere(0, 0, 0, 0.8) # и прикрепляем к созданному ранее узлу self.collisNode.addSolid(collisSphere) # закрепляем узел на камере self.collisCamNode = base.camera.attachNewNode(self.collisNode) # уведомляем обходчик о новом «объекте ОТ» self.traverser.addCollider(self.collisCamNode, self.collisQueue) # ускорение падения self.fall_acceleration = 0.015 # величина силы прыжка self.jump_power = 0.21 # скорость падения self.fall_speed = 0 # флаг касания земли self.ground = False # режим редактирования self.edit_mode = True # устанавливаем режим редактирования self.setEditMode(self.edit_mode) # Метод установки режима редактирования def setEditMode(self, mode): self.edit_mode = mode if self.edit_mode: # значение шага перемещения клавиатурой self.key_step = 0.2 else: # значение шага перемещения клавиатурой self.key_step = 0.2 # скорость падения self.fall_speed = 0 # флаг касания земли self.ground = False # поднимаем высоко камеру, чтобы избежать наложений #base.camera.setZ(20) # Метод установки состояния клавиши def setKey(self, key, value): self.keys[key] = value # Метод управления положением и ориентацией камеры def controlCamera(self, task): # если установлен режим редактирования if self.edit_mode: # рассчитываем смещения положения камеры по осям X Y Z move_x = self.key_step * (self.keys['d'] - self.keys['a']) move_y = self.key_step * (self.keys['w'] - self.keys['s']) move_z = self.key_step * (self.keys['e'] - self.keys['q']) # смещаем позицию камеры относительно предыдущего положения камеры base.camera.setPos(base.camera, move_x, move_y, move_z) # если установлен режим хождения else: # предыдущая позиция камеры old_pos = base.camera.getPos() # рассчитываем смещения положения камеры по осям X Y move_x = self.key_step * (self.keys['d'] - self.keys['a']) move_y = self.key_step * (self.keys['w'] - self.keys['s']) # сохраняем наклон камеры по вертикали pitch = base.camera.getP() # сбрасываем наклон в 0 - ходим прямо без наклона base.camera.setP(0) # смещаем позицию камеры относительно предыдущего положения камеры base.camera.setPos(base.camera, move_x, move_y, 0) # восстанавливаем наклон base.camera.setP(pitch) # если есть столкновения с блоками if self.collisionTest(): # восстанавливаем старую позицию base.camera.setPos(old_pos) # предыдущая высота камеры old_z = base.camera.getZ() # если нажат пробел и есть касание земли if self.keys['space'] and self.ground: # прыгаем вверх - сильно уменьшаем скорость падения self.fall_speed = -self.jump_power # сбрасываем флаг касания земли self.ground = False # опускаем камеру под действием гравитации base.camera.setZ(old_z - self.fall_speed) # если есть касание блоков if self.collisionTest(): # восстанавливаем высоту камеры base.camera.setZ(old_z) # сбрасываем скорость падения self.fall_speed = 0 # устанавливаем флаг касания земли self.ground = True else: # ускоряем падение self.fall_speed += self.fall_acceleration # получаем новое положение курсора мышки new_mouse_pos = base.win.getPointer(0) new_x = new_mouse_pos.getX() new_y = new_mouse_pos.getY() # пробуем установить курсор в центр экрана if base.win.movePointer(0, self.x_center, self.y_center): # рассчитываем поворот камеры по горизонтали self.heading = self.heading - (new_x - self.x_center) * self.mouse_step # рассчитываем наклон камеры по вертикали self.pitch = self.pitch - (new_y - self.y_center) * self.mouse_step # устанавливаем новую ориентацию камеры base.camera.setHpr(self.heading, self.pitch, 0) # сообщаем о необходимости повторного запуска задачи return task.again # Метод проверки столкновений с объектами def collisionTest(self): # запускаем обходчик на проверку self.traverser.traverse(base.render) # если обходчик обнаружил какие-то столкновения if self.collisQueue.getNumEntries() > 0: return True else: return False
class Weapon(DirectObject): def __init__(self, _main, _name, _fireRate, _dmg=20,_mountSlot=0, weaponType="Pistol"): self.main = _main self.name = _name self.fireRate = _fireRate self.dmg = _dmg self.weaponType = weaponType self.mountSlot = _mountSlot self.muzzleFlash = loader.loadModel("muzzleflash") if weaponType == "Pistol": self.style = "OneHand" self.model = loader.loadModel("Pistol") self.muzzleFlash.setZ(0.65) self.muzzleFlash.setX(-0.04) self.muzzleFlash.setScale(0.25) self.muzzleFlash.find('**/+SequenceNode').node().setFrameRate(20) else: self.style = "TwoHand" self.model = loader.loadModel("MG") self.muzzleFlash.setZ(0.65) self.muzzleFlash.setX(0.08) self.muzzleFlash.setScale(0.3) self.muzzleFlash.find('**/+SequenceNode').node().setFrameRate(20) self.model.setY(2) self.muzzleFlash.reparentTo(self.model) self.muzzleFlash.find('**/+SequenceNode').node().stop() self.muzzleFlash.hide() # Load bullet model self.bullet = loader.loadModel("Bullet") self.bullet.setP(-90) self.bullet.setH(180) #self.bullet.setPos(0, 0.5, 0) # Control self.isFiring = False # Collision Stuff self.wepRay = None # Make weapon ray self.setupRay() self.model.show() def setAmmo(self): pass def setupRay(self): self.shootTraverser = CollisionTraverser() self.shootingQH = CollisionHandlerQueue() #self.shootingEH = CollisionHandlerEvent() #self.shootingEH.addInPattern('into-%in') # Create a collision Node shootNode = CollisionNode('WeaponRay') # set the nodes collision bitmask shootNode.setFromCollideMask(BitMask32.bit(1)) # create a collision segment (ray like) self.shootRay = CollisionSegment() shootNode.addSolid(self.shootRay) #self.pickerNP = self.main.player.model.attachNewNode(pickerNode) self.shootNP = render.attachNewNode(shootNode) #self.shootTraverser.addCollider(self.shootNP, self.shootingEH) self.shootTraverser.addCollider(self.shootNP, self.shootingQH) #self.shootNP.show() def doFire(self, _toPos=(0, 0, 0)): self.isFiring = True if self.weaponType == "Pistol": self.muzzleFlash.find('**/+SequenceNode').node().play(0, 1) else: self.muzzleFlash.find('**/+SequenceNode').node().loop(True) self.muzzleFlash.show() # For some reason the mouse ray end up at posZ -1 (which causes a problem when we make the enemy spheres smaller in radius) # so here for now.. ill make a quick fix. adjustedZ = (_toPos[0], _toPos[1], 0) self.shootRay.setPointA(self.main.player.model.getPos()) self.shootRay.setPointB(adjustedZ) fromPos = self.main.player.model.getPos() #self.model.getPos() #self.setProjectile(fromPos, adjustedZ)#_toPos) self.shootTraverser.traverse(self.main.enemyParent) if self.shootingQH.getNumEntries() > 0: self.shootingQH.sortEntries() enemyCol = self.shootingQH.getEntry(0).getIntoNodePath().node().getName() base.messenger.send("into-" + enemyCol, [self.dmg]) def stopFire(self): if self.weaponType == "Pistol" and \ self.muzzleFlash.find('**/+SequenceNode').node().isPlaying(): taskMgr.add(self.waitForFrame, "waitForFrame") return self.muzzleFlash.find('**/+SequenceNode').node().stop() self.muzzleFlash.hide() def waitForFrame(self, task): if self.muzzleFlash.find('**/+SequenceNode').node().isPlaying(): return task.cont self.muzzleFlash.find('**/+SequenceNode').node().stop() self.muzzleFlash.hide() def reload(self): pass def setProjectile(self, _from, _to): self.bullet.reparentTo(render)#self.model) # setup the projectile interval #self.bulletProjectile = ProjectileInterval(self.bullet, # startPos = Point3(_from), # duration = 1, # endPos = Point3(_to)) #self.bulletProjectile = self.bullet.posInterval(1.0, Point3(_to), startPos=Point3(_from)) #self.bulletProjectile = LerpPosInterval(self.bullet, 2.0, _to, _from) print "POSITIONS:" print _to print _from frm = render.getPos(self.main.player.model) print frm self.bulletProjectile = LerpPosInterval(self.bullet, 1.0, _to, _from) self.bulletProjectile.start()
class World(ShowBase): def skyBoxLoad(self): self.spaceSkyBox = load_model('skybox1.egg') self.spaceSkyBox.setScale(150) self.spaceSkyBox.setLightOff() self.spaceSkyBox.reparentTo(render) self.spaceSkyBox.setPos(0,0,-200) self.spaceSkyBox.setHpr(0,0,0) def loadEnviron(self): self.environ = load_model("secondWorld.egg") self.environ.reparentTo(render) self.environ.setPos(0,0,0) def Hooh(self): """ hooh """ self.hoohActor = Actor("anim2hooh.egg", {"wing":"anim-Anim0.egg"}) self.hoohActor.reparentTo(render) self.hoohActor.loop("wing") self.hoohActor.setPos(self.ralphStartPos[0], self.ralphStartPos[1]+100, self.ralphStartPos[2]+100) self.hoohActor.setPlayRate(4.0,"wing") self.hoohActor.setHpr(180,90,0) start = Point3(self.ralphStartPos[0], self.ralphStartPos[1]+95, self.ralphStartPos[2]+100) end = Point3(self.ralphStartPos[0], self.ralphStartPos[1]-100, self.ralphStartPos[2]+100) turnHpr1 = Point3(180,90,0) turnHpr2 = Point3(0,90,0) hoohPosInt1 = self.hoohActor.posInterval(5.0, start, startPos = end) hoohPosInt2 = self.hoohActor.posInterval(5.0, end, startPos = start) hoohHprInt1 = self.hoohActor.hprInterval(1.0, turnHpr2, startHpr=turnHpr1) hoohHprInt2 = self.hoohActor.hprInterval(1.0, turnHpr1, startHpr=turnHpr2) self.hoohFly = Sequence(hoohPosInt1, hoohHprInt1, hoohPosInt2, hoohHprInt2, name="hoohFly") self.hoohFly.loop() def gold(self, task): _GOLD_PARTICLES.setPos(self.hoohActor.getPos()) return task.cont def loadPokemon(self): """ Pikachu """ self.pikachu = load_model("pikachu.egg") self.pikachu.reparentTo(render) self.pikachu.setPos(_PIKACHU_POS) self.pikachu.setHpr(_PIKACHU_HPR) """ Groudon """ self.Groudon = load_model("Groudon.egg") self.Groudon.reparentTo(render) self.Groudon.setPos(_GROUDON_POS) self.Groudon.setHpr(_GROUDON_HPR) """ Bulbasaur """ self.bulbasaur = load_model("bulbasaur.egg") self.bulbasaur.reparentTo(render) self.bulbasaur.setPos(_BULBASAUR_POS) self.bulbasaur.setHpr(_BULBASAUR_HPR) """ hooh """ self.Hooh() """ Pichu """ self.pichu = load_model("pichu.egg") self.pichu.reparentTo(render) self.pichu.setPos(_PICHU_POS) self.pichu.setHpr(_PICHU_HPR) """ Charmander """ self.charmander = load_model("char.egg") self.charmander.reparentTo(render) self.charmander.setPos(_CHARMANDER_POS) self.charmander.setHpr(_CHARMANDER_HPR) """ charizard """ self.charizard = load_model("charizard.egg") self.charizard.reparentTo(render) self.charizard.setPos(_CHARIZARD_POS) self.charizard.setHpr(_CHARIZARD_HPR) """ blastoise """ self.blastoise = load_model("blastoise.egg") self.blastoise.reparentTo(render) self.blastoise.setPos(_BLASTOISE_POS) self.blastoise.setHpr(_BLASTOISE_HPR) """ Squirtle """ self.squirtle = load_model("squirtle.egg") self.squirtle.reparentTo(render) self.squirtle.setPos(_SQUIRTLE_POS) self.squirtle.setHpr(_SQUIRTLE_HPR) """ Dragonite """ self.dragonite = load_model("dragonite.egg") self.dragonite.reparentTo(render) self.dragonite.setPos(_DRAGONITE_POS) self.dragonite.setHpr(_DRAGONITE_HPR) _FLAME.setPos(_FLAME_POS) _FLAME.setScale(0.1) _FLAME.start(parent=render, renderParent=render) """ venusaur """ self.venusaur = load_model("venusaur.egg") self.venusaur.reparentTo(render) self.venusaur.setPos(_VENUSAUR_POS) self.venusaur.setHpr(_VENUSAUR_HPR) def loadRalph(self): # Create the main character, Ralph basePath = r"../google_drive/ball/data/models/" self.ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor(basePath+"ralph",{"run":basePath+"ralph-run", "walk":basePath+"ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(self.ralphStartPos) self.ralph.hide() def loadNextMusic(self, task): # random load background music if (self.music.status()!=self.music.PLAYING): # not playing self.musicCounter += 1 index = self.musicCounter % len(_BGMUSIC) self.music = load_bgmusic(_BGMUSIC[index]) self.music.play() return task.cont def keyControl(self): 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("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("w",self.setKey,["upward",1]) self.accept("w-up",self.setKey,["upward",0]) self.accept("s",self.setKey,["downward",1]) self.accept("s-up",self.setKey,["downward",0]) self.accept("t", self.toggleMusic) self.accept("u", self.changeVolume, ['u']) self.accept("d", self.changeVolume, ['d']) self.accept("h", self.hideInstructions) def changeVolume(self, direction): if direction == 'u' and self.volume < 1: self.volume += 0.05 else: # direction == 'd' if self.volume > 0: self.volume -= 0.05 self.music.setVolume(self.volume) def toggleMusic(self): self.music.stop() self.musicCounter += 1 # increment the counter by index = self.musicCounter % len(_BGMUSIC) self.music = load_bgmusic(_BGMUSIC[index]) self.music.play() def displayInformation(self): self.title = addTitle("My Pokemon - Roam Mode") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[Arrow Keys]: Move") self.inst3 = addInstructions(0.85, "[w]: look up") self.inst4 = addInstructions(0.80, "[s]: look down") self.inst5 = addInstructions(0.75, "[t]: toggle next song") self.inst6 = addInstructions(0.70, "[u]: volume up") self.inst7 = addInstructions(0.65, "[d]: volume down") self.inst8 = addInstructions(0.60, "[h]: hide/show instructions") self.insts = [self.title, self.inst1, self.inst2, self.inst3, self.inst4, self.inst5, self.inst6, self.inst7, self.inst8] def hideInstructions(self): if self.instStatus == "show": self.instStatus = "hide" groupHide(self.insts) else: # instructions are hidden self.instStatus = "show" groupShow(self.insts) def __init__(self): base.enableParticles() self.keyMap = {"left":0, "right":0, "forward":0,"backward":0, "upward":0, "downward":0, "leftward":0,"rightward":0, "cam-left":0, "cam-right":0} _GOLD_PARTICLES.start(parent=render, renderParent=render) _GOLD_PARTICLES.setScale(200) self.instStatus = "show" self.musicCounter = 0 self.music = load_bgmusic(_BGMUSIC[0]) # self.music.play() self.volume = 0 self.music.setVolume(self.volume) base.win.setClearColor(Vec4(0,0,0,1)) self.above = 3.0 # load environment self.loadEnviron() # load ralph self.loadRalph() # load sky box self.skyBoxLoad() # load pokemon self.loadPokemon() self.displayInformation() self.keyControl() # 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) taskMgr.add(self.move,"moveTask") taskMgr.add(self.setAbove,"setAbove") taskMgr.add(self.loadNextMusic, "loadRandomMusic") taskMgr.add(self.gold, "gold") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(),self.ralph.getY(),2) 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) # Create some lighting 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)) def setAbove(self,task): if self.keyMap["upward"] == 1: self.above += 0.1 if self.keyMap["downward"] == 1: self.above -= 0.1 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): # 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() + 113 * globalClock.getDt()) base.camera.setX(base.camera, +20 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.ralph.setH(self.ralph.getH() - 113 * globalClock.getDt()) base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.ralph.setY(self.ralph, -75 * globalClock.getDt()) if (self.keyMap["backward"] != 0): pass #self.ralph.setY(self.ralph, 75 * 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):# or (self.keyMap["backward"]!=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 # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. 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 # 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) # Keep the camera at one foot above the terrain, # or two feet above ralph, 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.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.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. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + self.above)#self.above) base.camera.lookAt(self.floater) return task.cont
class World(DirectObject): mySound = base.loader.loadSfx("trial.mp3") #Used for adding a virus at a randomly generated position def random_vgen(self): print 'I am in random' for i in range(0, 5): self.a[random.randint(0, 7)][random.randint(0, 7)] = 1 def initializer(self, level): self.turns = 0 ## Level Definition def levelone(): self.a[4][4] = 1 self.a[4][5] = 1 self.a[4][6] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[4][6] = 1 self.a[5][5] = 1 def leveltwo(): self.a[4][3] = 1 self.a[4][5] = 1 self.a[4][7] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[2][2] = 1 self.a[5][3] = 1 self.a[1][2] = 1 def levelthree(): self.a[4][4] = 1 self.a[4][5] = 1 self.a[4][6] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[4][6] = 1 self.a[5][5] = 1 self.a[4][3] = 1 self.a[4][5] = 1 self.a[4][7] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[2][2] = 1 self.a[5][3] = 1 options = {1: levelone, 2: leveltwo, 3: levelthree} options[level]() print self.a temp = [] count = 0 for element in reversed(self.a): for ele in element: #print 'cheking element is 1 : ' + str(ele) if ele == 1: temp.append(count) self.pieces[count] = Monster(count, WHITE) #self.squares[count].setColor(HIGHLIGHT) count = count + 1 self.list = temp def showscore(self): try: self.score.destroy() except: pass self.score = OnscreenText(text='Number of Turns : %s' % (self.turns), pos=(0.5, 0.95), scale=0.07, mayChange=True) def menuscreen(self): # Callback function to set text def setText(): b.destroy() helptext.destroy() # Add button b = DirectButton(text=("START", "START", "START", "disabled"), scale=0.15, command=setText, pos=(0, 0, 0.85)) helptext = OnscreenText(text=''' STORY: Hello Mad Scientist! You are so close to finding the cure to aids! You understood the behaviour and can finally manipulate the virus to kill itself! But time is running out! You have a red and white blood cell sample infected with AIDS Virus. INSTRUCTIONS: The AIDS Virus obeys the Conway's Game of Life. Who would have guessed? 1. If virus is surrounded by more than 3 viruses, it dies of suffocation 2. If virus is surrounded by less than 2 viruses, it dies of underpopulation 3. If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned due to breeding. AIM: To kill all the viruses, by moving one of them every turn. ''', pos=(-0.90, 0.72), frame=(123, 123, 123, 1), wordwrap=25, align=TextNode.ALeft, bg=(0.23, 0.243, 0.13, 0.9)) def endscreen(self): def restart(): taskMgr.remove(self.mouseTask) for i in range(64): self.squares[i].setColor(SquareColor(i)) scorecard.destroy() restartb.destroy() end.destroy() nextlevelb.destroy() self.reference.destroy() self.mySound.stop() try: self.score.destroy() except: pass print 'restarting' print self.a print self.list World() def quitgame(): sys.exit() def nextLevel(): self.currlevel = self.currlevel + 1 nextlevelb.destroy() scorecard.destroy() restartb.destroy() end.destroy() self.score.destroy() self.initializer(self.currlevel) # Add button scorecard = OnscreenText(text='You finished it in %s turns! ' % (self.turns), frame=(123, 123, 123, 0), wordwrap=25, bg=(0.2, 0, 0.8, 1)) nextlevelb = DirectButton(text=("NEXT LEVEL", "NEXT LEVEL", "NEXT LEVEL", "disabled"), scale=0.15, command=nextLevel, pos=(0, 0, -0.15)) restartb = DirectButton(text=("RESTART", "RESTART", "RESTART", "disabled"), scale=0.15, command=restart, pos=(0, 0, -0.35)) end = DirectButton(text=("QUIT", "QUIT", "QUIT", "disabled"), scale=0.15, command=quitgame, pos=(0, 0, -0.55)) if self.currlevel == self.maxlevel: nextlevelb.destroy() def __init__(self): #music self.mySound.play() print 'I am being initialized' self.menuscreen() self.list = [] self.turns = 0 self.maxlevel = 3 self.currlevel = 1 self.a = [[0 for x in range(8)] for y in range(8)] #This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Game of Life : Help in ending AIDS!", style=1, fg=(1, 1, 1, 1), pos=(0, -0.95), scale=.07) self.escapeEvent = OnscreenText(text="ESC: Quit", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.95), align=TextNode.ALeft, scale=.05) ## self.mouse1Event = OnscreenText( ## text="Left-click and drag: Pick up virus and drag it to a new bloodcell", ## style=1, fg=(1,1,1,1), pos=(-1.3, 0.90), ## align=TextNode.ALeft, scale = .05) ## self.accept('escape', sys.exit) #Escape quits base.disableMouse() #Disble mouse camera control camera.setPosHpr(0, -13.75, 6, 0, -25, 0) #Set the camera self.setupLights() #Setup default lighting #Since we are using collision detection to do picking, we set it up like #any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() #Make a traverser self.pq = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') #Attach that node to the camera since the ray will need to be positioned #relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() #Make our ray self.pickerNode.addSolid(self.pickerRay) #Add it to the collision node #Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) #self.picker.showCollisions(render) #We will attach all of the squares to their own root. This way we can do the #collision pass just on the sqaures and save the time of checking the rest #of the scene self.squareRoot = render.attachNewNode("squareRoot") #For each square self.squares = [None for i in range(64)] self.pieces = [None for i in range(64)] for i in range(64): #Load, parent, color, and position the model (a single square polygon) self.squares[i] = loader.loadModel("models/square") self.squares[i].reparentTo(self.squareRoot) self.squares[i].setPos(SquarePos1(i)) self.squares[i].setColor(SquareColor(i)) #Set the model itself to be collideable with the ray. If this model was #any more complex than a single polygon, you should set up a collision #sphere around it instead. But for single polygons this works fine. self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) #Set a tag on the square's node so we can look up what square this is #later during the collision pass self.squares[i].find("**/polygon").node().setTag('square', str(i)) #We will use this variable as a pointer to whatever piece is currently #in this square self.initializer(self.currlevel) #This will represent the index of the currently highlited square self.hiSq = False #This wil represent the index of the square where currently dragged piece #was grabbed from self.dragging = False #Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') #self.trial = taskMgr.add(self.trial,'trial') self.accept("mouse1", self.grabPiece) #left-click grabs a piece self.accept("mouse1-up", self.releasePiece) #releasing places it #This function swaps the positions of two pieces def swapPieces(self, fr, to): temp = self.pieces[fr] self.pieces[fr] = self.pieces[to] self.pieces[to] = temp if self.pieces[fr]: print 'imma swapping' self.pieces[fr].square = fr print fr print SquarePos(fr) try: self.pieces[fr].obj.setPos(SquarePos(fr)) except: pass print 'done' if self.pieces[to]: self.pieces[to].square = to try: self.pieces[to].obj.setPos(SquarePos(to)) except: pass def trial(self): self.turns = self.turns + 1 try: self.reference.destroy() except: pass self.reference = OnscreenText(text=''' Reference: virus is surrounded by more than 3 viruses, it dies virus is surrounded by less than 2 viruses, it dies If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned. ''', style=1, fg=(1, 1, 1, 1), pos=(-1, 0.95), align=TextNode.ALeft, scale=.05) self.showscore() a = self.a while True: for i in self.list: #insert deletion code print 'imma deleting the sq : ' + str(i) self.pieces[i].obj.delete() self.squares[i].setColor(SquareColor(i)) count = 0 a = [[([[ sum(b[y1][x1] for b in [[[( (-1 < x2 + dx < len(a[0])) and (-1 < y2 + dy < len(a))) and a[y2 + dy][x2 + dx] or 0 for x2 in range(len(a[0]))] for y2 in range(len(a))] for (dx, dy) in [(dx, dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1] if (dy != 0 or dx != 0)]]) for x1 in range(len(a[0])) ] for y1 in range(len(a))][y][x] == 3 or ([[ sum(c[y3][x3] for c in [[[( (-1 < x4 + dx < len(a[0])) and (-1 < y4 + dy < len(a))) and a[y4 + dy][x4 + dx] or 0 for x4 in range(len(a[0]))] for y4 in range(len(a))] for (dx, dy) in [(dx, dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1] if (dy != 0 or dx != 0)]]) for x3 in range(len(a[0])) ] for y3 in range(len(a))][y][x] == 2 and a[y][x] == 1)) and 1 or 0 for x in range(len(a[0]))] for y in range(len(a))] lis = [] #insert a random virus at a probability of 1/5 diceroll = random.randint(0, 5) if diceroll == 2: self.random_vgen() for element in reversed(a): for ele in element: #print 'cheking element is 1 : ' + str(ele) if ele == 1: lis.append(count) count = count + 1 print lis self.list = lis self.a = a print self.list for i in self.list: self.pieces[i] = Monster(i, WHITE) #self.squares[i].setColor(HIGHLIGHT) print 'leaving trial' if len(self.list) == 0: self.endscreen() break return def mouseTask(self, task): #This task deals with the highlighting and dragging based on the mouse #First, clear the current highlight if self.hiSq is not False: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = False #Check to see if we can access the mouse. We need it to do anything else if base.mouseWatcherNode.hasMouse(): #get the mouse position mpos = base.mouseWatcherNode.getMouse() #Set the position of the ray based on the mouse position self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) #If we are dragging something, set the position of the object #to be at the appropriate point over the plane of the board if self.dragging is not False: #Gets the point described by pickerRay.getOrigin(), which is relative to #camera, relative instead to render nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin()) #Same thing with the direction of the ray nearVec = render.getRelativeVector( camera, self.pickerRay.getDirection()) try: self.pieces[self.dragging].obj.setPos( PointAtZ(.5, nearPoint, nearVec)) except: pass #Do the actual collision pass (Do it only on the squares for #efficiency purposes) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: #if we have hit something, sort the hits so that the closest #is first, and highlight that node self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) #Set the highlight on the picked square self.squares[i].setColor(HIGHLIGHT) self.hiSq = i #print 'selected is ' + str(i) return Task.cont def grabPiece(self): #If a square is highlighted and it has a piece, set it to dragging mode if (self.hiSq is not False and self.pieces[self.hiSq]): self.dragging = self.hiSq self.hiSq = False def releasePiece(self): #Letting go of a piece. If we are not on a square, return it to its original #position. Otherwise, swap it with the piece in the new square if self.dragging is not False: #Make sure we really are dragging something #We have let go of the piece, but we are not on a square if self.hiSq is False: try: self.pieces[self.dragging].obj.setPos( SquarePos(self.dragging)) except: pass else: #Otherwise, swap the pieces self.swapPieces(self.dragging, self.hiSq) #self.draggin is the from print self.list print 'you picked this, so Imma deleting this ' + str( self.dragging) #deletion of i after picking it up. try: self.list.remove(self.dragging) except: pass temp2 = [] temp2 = SquarePosTuple(self.dragging) self.a[temp2[0]][temp2[1]] = 0 i = self.hiSq print self.list print 'highlighted sq is ' + str(i) templis = [] templis = SquarePosTuple(i) print templis self.list.append(i) print self.list print templis self.a[templis[0]][templis[1]] = 1 for line in self.a: print line self.trial() #We are no longer dragging anything self.dragging = False def setupLights(self): #This function sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.8, .8, .8, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(0, 45, -45)) directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight))
class World(DirectObject): def __init__(self): #This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Panda3D: Tutorial - Mouse Picking", style=1, fg=(1, 1, 1, 1), pos=(0.8, -0.95), scale=.07) self.escapeEvent = OnscreenText(text="ESC: Quit", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.95), align=TextNode.ALeft, scale=.05) self.mouse1Event = OnscreenText( text="Left-click and drag: Pick up and drag piece", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.90), align=TextNode.ALeft, scale=.05) self.accept('escape', sys.exit) #Escape quits base.disableMouse() #Disble mouse camera control camera.setPosHpr(0, -13.75, 6, 0, -25, 0) #Set the camera self.setupLights() #Setup default lighting #Since we are using collision detection to do picking, we set it up like #any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() #Make a traverser self.pq = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') #Attach that node to the camera since the ray will need to be positioned #relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() #Make our ray self.pickerNode.addSolid(self.pickerRay) #Add it to the collision node #Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) #self.picker.showCollisions(render) #Now we create the chess board and its pieces #We will attach all of the squares to their own root. This way we can do the #collision pass just on the sqaures and save the time of checking the rest #of the scene self.squareRoot = render.attachNewNode("squareRoot") #For each square self.squares = [None for i in range(64)] self.pieces = [None for i in range(64)] for i in range(64): #Load, parent, color, and position the model (a single square polygon) self.squares[i] = loader.loadModel("models/square") self.squares[i].reparentTo(self.squareRoot) self.squares[i].setPos(SquarePos(i)) self.squares[i].setColor(SquareColor(i)) #Set the model itself to be collideable with the ray. If this model was #any more complex than a single polygon, you should set up a collision #sphere around it instead. But for single polygons this works fine. self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) #Set a tag on the square's node so we can look up what square this is #later during the collision pass self.squares[i].find("**/polygon").node().setTag('square', str(i)) #We will use this variable as a pointer to whatever piece is currently #in this square #The order of pieces on a chessboard from white's perspective. This list #contains the constructor functions for the piece classes defined below pieceOrder = (Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook) for i in range(8, 16): #Load the white pawns self.pieces[i] = Pawn(i, WHITE) for i in range(48, 56): #load the black pawns self.pieces[i] = Pawn(i, PIECEBLACK) for i in range(8): #Load the special pieces for the front row and color them white self.pieces[i] = pieceOrder[i](i, WHITE) #Load the special pieces for the back row and color them black self.pieces[i + 56] = pieceOrder[i](i + 56, PIECEBLACK) #This will represent the index of the currently highlited square self.hiSq = False #This wil represent the index of the square where currently dragged piece #was grabbed from self.dragging = False #Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') self.accept("mouse1", self.grabPiece) #left-click grabs a piece self.accept("mouse1-up", self.releasePiece) #releasing places it #This function swaps the positions of two pieces def swapPieces(self, fr, to): temp = self.pieces[fr] self.pieces[fr] = self.pieces[to] self.pieces[to] = temp if self.pieces[fr]: self.pieces[fr].square = fr self.pieces[fr].obj.setPos(SquarePos(fr)) if self.pieces[to]: self.pieces[to].square = to self.pieces[to].obj.setPos(SquarePos(to)) def mouseTask(self, task): #This task deals with the highlighting and dragging based on the mouse #First, clear the current highlight if self.hiSq is not False: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = False #Check to see if we can access the mouse. We need it to do anything else if base.mouseWatcherNode.hasMouse(): #get the mouse position mpos = base.mouseWatcherNode.getMouse() #Set the position of the ray based on the mouse position self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) #If we are dragging something, set the position of the object #to be at the appropriate point over the plane of the board if self.dragging is not False: #Gets the point described by pickerRay.getOrigin(), which is relative to #camera, relative instead to render nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin()) #Same thing with the direction of the ray nearVec = render.getRelativeVector( camera, self.pickerRay.getDirection()) self.pieces[self.dragging].obj.setPos( PointAtZ(.5, nearPoint, nearVec)) #Do the actual collision pass (Do it only on the squares for #efficiency purposes) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: #if we have hit something, sort the hits so that the closest #is first, and highlight that node self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) #Set the highlight on the picked square self.squares[i].setColor(HIGHLIGHT) self.hiSq = i return Task.cont def grabPiece(self): #If a square is highlighted and it has a piece, set it to dragging mode if (self.hiSq is not False and self.pieces[self.hiSq]): self.dragging = self.hiSq self.hiSq = False def releasePiece(self): #Letting go of a piece. If we are not on a square, return it to its original #position. Otherwise, swap it with the piece in the new square if self.dragging is not False: #Make sure we really are dragging something #We have let go of the piece, but we are not on a square if self.hiSq is False: self.pieces[self.dragging].obj.setPos(SquarePos(self.dragging)) else: #Otherwise, swap the pieces self.swapPieces(self.dragging, self.hiSq) #We are no longer dragging anything self.dragging = False def setupLights(self): #This function sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.8, .8, .8, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(0, 45, -45)) directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight))
class DistributedLevel(DistributedObject): """ An instance of these is created and placed in the middle of the zone. It serves to illustrate the creation of AI-side objects to populate the world, and a general mechanism for making them react to the avatars. """ def __init__(self, cr): DistributedObject.__init__(self, cr) #self.model = loader.loadModel('environment') #self.model.setZ(0) #self.builder = Builder(self, "map.txt", "development") plane = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0))) cnode = CollisionNode('cnode') cnode.setIntoCollideMask(BitMask32.bit(1)) cnode.setFromCollideMask(BitMask32.bit(1)) cnode.addSolid(plane) self.planeNP = self.model.attachNewNode(cnode) self.planeNP.show() # Setup a traverser for the picking collisions self.picker = CollisionTraverser() # Setup mouse ray self.pq = CollisionHandlerQueue() # Create a collision Node pickerNode = CollisionNode('MouseRay') # set the nodes collision bitmask pickerNode.setFromCollideMask(BitMask32.bit(1)) # create a collision ray self.pickerRay = CollisionRay() # add the ray as a solid to the picker node pickerNode.addSolid(self.pickerRay) # create a nodepath with the camera to the picker node self.pickerNP = base.camera.attachNewNode(pickerNode) # add the nodepath to the base traverser self.picker.addCollider(self.pickerNP, self.pq) print "model loaded" #TODO: check how to load multiple levels and set players in specific levels! self.accept("mouse1", self.mouseClick) def announceGenerate(self): """ This method is called after generate(), after all of the required fields have been filled in. At the time of this call, the distributed object is ready for use. """ DistributedObject.announceGenerate(self) # Now that the object has been fully manifested, we can parent # it into the scene. print "render the model" self.model.reparentTo(render) def disable(self): # Take it out of the scene graph. self.detachNode() DistributedObject.disable(self) def checkMousePos(self, mpos, camPos, camHpr): lens = LenseNode.copyLens(base.camNode) lens.setPos(camPos) lens.setHpr(camHpr) help(mpos) mpos = Point2(mpos.x, mpos.y) pos = self.getClickPosition(mpos, lens) print "mouse clicked at:", pos def mouseClick(self): """Send an event to the server that will check where the mouse will hit and what action needs to be done""" hitPos = (0, 0, 0) # check if we have a mouse on the window if base.mouseWatcherNode.hasMouse(): # get the mouse position on the screen mpos = base.mouseWatcherNode.getMouse() print mpos # set the ray's position self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) # Now call the traverse function to let the traverser check for collisions # with the added colliders and the levelNP self.picker.traverse(self.planeNP) # check if we have a collision if self.pq.getNumEntries() > 0: # sort the entries to get the closest first self.pq.sortEntries() # This is the point at where the mouse ray and the level plane intersect hitPos = self.pq.getEntry(0).getSurfacePoint(render) base.messenger.send("clickPosition", [hitPos])
class World(DirectObject): def __init__(self): # This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Panda3D: Tutorial - Collision Detection", style=1, fg=(1,1,1,1), pos=(0.7,-0.95), scale = .07) self.instructions = OnscreenText(text="Mouse pointer tilts the board", pos = (-1.3, .95), fg=(1,1,1,1), align = TextNode.ALeft, scale = .05) self.accept("escape", sys.exit) # Escape quits base.disableMouse() # Disable mouse-based camera control camera.setPosHpr(0, 0, 25, 0, -90, 0) # Place the camera # Load the maze and place it in the scene self.maze = loader.loadModel("models/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 visable 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 # self.walls.show() # We will now find the triggers for the holes and set their masks to 0 as # well. We also set their names to make them easier to identify during # collisions self.loseTriggers = [] for i in range(6): trigger = self.maze.find("**/hole_collide" + str(i)) trigger.node().setIntoCollideMask(BitMask32.bit(0)) trigger.node().setName("loseTrigger") self.loseTriggers.append(trigger) # Uncomment this line to see the triggers # trigger.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. # 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 ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.55, .55, .55, 1)) 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)) self.ballRoot.setLight(render.attachNewNode(ambientLight)) self.ballRoot.setLight(render.attachNewNode(directionalLight)) # 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 = 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 # Create the movement task, but first make sure it is not already running taskMgr.remove("rollTask") self.mainLoop = taskMgr.add(self.rollTask, "rollTask") self.mainLoop.last = 0 # 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) # This is the task that deals with making everything interactive def rollTask(self, task): # Standard technique for finding the amount of time since the last frame dt = task.time - task.last task.last = task.time # If dt is large, then there has been a # hiccup that could cause the ball # to leave the field if this functions runs, so ignore the frame if dt > .2: return Task.cont # 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.cHandler.getNumEntries()): entry = self.cHandler.getEntry(i) name = entry.getIntoNode().getName() if name == "wall_collide": self.wallCollideHandler(entry) elif name == "ground_collide": self.groundCollideHandler(entry) elif name == "loseTrigger": self.loseGame(entry) # Read the mouse position and tilt the maze accordingly if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() # get the mouse position self.maze.setP(mpos.getY() * -10) self.maze.setR(mpos.getX() * 10) # Finally, we move the ball # Update the velocity based on acceleration self.ballV += self.accelV * dt * ACCEL # Clamp the velocity to the maximum speed if self.ballV.lengthSquared() > MAX_SPEED_SQ: self.ballV.normalize() self.ballV *= MAX_SPEED # Update the position based on the velocity self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV * dt)) # This block of code rotates the ball. It uses something called 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) return Task.cont # Continue the task indefinitely # If the ball hits a hole trigger, then it should fall in the hole. # This is faked rather than dealing with the actual physics of it. def loseGame(self, entry): # The triggers are set up so that the center of the ball should move to the # collision point to be in the hole toPos = entry.getInteriorPoint(render) taskMgr.remove('rollTask') # Stop the maze task # Move the ball into the hole over a short sequence of time. Then wait a # second and call start to reset the game Sequence( Parallel( LerpFunc(self.ballRoot.setX, fromData = self.ballRoot.getX(), toData = toPos.getX(), duration = .1), LerpFunc(self.ballRoot.setY, fromData = self.ballRoot.getY(), toData = toPos.getY(), duration = .1), LerpFunc(self.ballRoot.setZ, fromData = self.ballRoot.getZ(), toData = self.ballRoot.getZ() - .9, duration = .2)), Wait(1), Func(self.start)).start()
class HexGrid(object): def __init__(self, w, h, show): self.width = w self.height = h self.loader = show.loader self.root = show.render.attachNewNode("hexgrid_root") self.base_tile = 'hex' self.diameter = 20 self.inscribed = self.diameter * sqrt(3) / 2 self.nodes = None self.show = show # 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.picker_queue = 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 = show.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 # Add it to the collision node self.pickerNode.addSolid(self.pickerRay) # Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.picker_queue) self.assemble() self.onclick_fn = None # self.mouseTask = self.taskMgr.add(self.mouseTask, 'mouseTask') # self.accept("mouse1", self.grabPiece) # left-click grabs a piece show.accept("mouse1-up", self.mouse_up) # releasing places it def mouse_up(self): # This task deals with the highlighting and dragging based on the mouse # Check to see if we can access the mouse. We need it to do anything # else if self.onclick_fn and self.show.mouseWatcherNode.hasMouse(): # get the mouse position mpos = self.show.mouseWatcherNode.getMouse() # Set the position of the ray based on the mouse position self.pickerRay.setFromLens(self.show.camNode, mpos.getX(), mpos.getY()) # Do the actual collision pass self.picker.traverse(self.root) if self.picker_queue.getNumEntries() > 0: # if we have hit something, sort the hits so that the closest # is first, and highlight that node self.picker_queue.sortEntries() i = int(self.picker_queue.getEntry(0).getIntoNode().getTag('hexmesh_i')) self.onclick_fn(self.nodes[i]) return Task.cont def onclick(self, fn): self.onclick_fn = fn def index_of(self, x, y): return x + y * self.width def xyi_iter(self, fn): for x in range(self.height): for y in range(self.width): fn(x, y, self.index_of(x, y)) def node_iter(self, fn): for node in self.nodes: fn(node) def assemble(self): random.seed(3141592) def make_node(x, y, i): row_offset = self.inscribed / 2. if y % 2 == 0 else 0 pos = Point3(x * self.inscribed + row_offset, y * self.diameter * 0.75, 0) self.nodes[i] = HexNode(self.base_tile, pos, self.root, i) self.nodes = [None for _ in range(self.width * self.height)] self.xyi_iter(make_node)
class MousePicker(object): def __init__(self, pickTag="MyPickingTag", nodeName="pickRay", showCollisions=False): self.pickTag = pickTag self.nodeName = nodeName self.showCollisions = showCollisions def create(self): self.mPickerTraverser = CollisionTraverser() self.mCollisionQue = CollisionHandlerQueue() self.mPickRay = CollisionRay() self.mPickRay.setOrigin(base.camera.getPos(base.render)) self.mPickRay.setDirection(base.render.getRelativeVector(base.camera, Vec3(0, 1, 0))) # create our collison Node to hold the ray self.mPickNode = CollisionNode(self.nodeName) self.mPickNode.addSolid(self.mPickRay) # Attach that node to the camera since the ray will need to be positioned # relative to it, returns a new nodepath # well use the default geometry mask # this is inefficent but its for mouse picking only self.mPickNP = base.camera.attachNewNode(self.mPickNode) # we'll use what panda calls the "from" node. This is reall a silly convention # but from nodes are nodes that are active, while into nodes are usually passive environments # this isnt a hard rule, but following it usually reduces processing # Everything to be picked will use bit 1. This way if we were doing other # collision we could seperate it, we use bitmasks to determine what we check other objects against # if they dont have a bitmask for bit 1 well skip them! self.mPickNode.setFromCollideMask(BitMask32(1)) # Register the ray as something that can cause collisions self.mPickerTraverser.addCollider(self.mPickNP, self.mCollisionQue) # Setup 2D picker self.mPickerTraverser2D = CollisionTraverser() self.mCollisionQue2D = CollisionHandlerQueue() self.mPickNode2D = CollisionNode("2D PickNode") self.mPickNode2D.setFromCollideMask(BitMask32(1)) self.mPickNode2D.setIntoCollideMask(BitMask32.allOff()) self.mPick2DNP = base.camera2d.attachNewNode(self.mPickNode2D) self.mPickRay2D = CollisionRay() self.mPickNode2D.addSolid(self.mPickRay2D) self.mPickerTraverser2D.addCollider(self.mPick2DNP, self.mCollisionQue2D) if self.showCollisions: self.mPickerTraverser.showCollisions(base.render) self.mPickerTraverser2D.showCollisions(base.aspect2d) def mousePick(self, traverse=None, tag=None): # do we have a mouse if base.mouseWatcherNode.hasMouse() == False: return None, None traverse = traverse or base.render tag = tag or self.pickTag mpos = base.mouseWatcherNode.getMouse() # Set the position of the ray based on the mouse position self.mPickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.mPickerTraverser.traverse(traverse) if self.mCollisionQue.getNumEntries() > 0: self.mCollisionQue.sortEntries() for entry in self.mCollisionQue.getEntries(): pickedObj = entry.getIntoNodePath() pickedObj = pickedObj.findNetTag(tag) if not pickedObj.isEmpty(): pos = entry.getSurfacePoint(base.render) return pickedObj, pos return None, None def mousePick2D(self, traverse=None, tag=None, all=False): # do we have a mouse if base.mouseWatcherNode.hasMouse() == False: return None, None traverse = traverse or base.render tag = tag or self.pickTag mpos = base.mouseWatcherNode.getMouse() self.mPickRay2D.setFromLens(base.cam2d.node(), mpos.getX(), mpos.getY()) self.mPickerTraverser2D.traverse(base.aspect2d) if self.mCollisionQue2D.getNumEntries() > 0: self.mCollisionQue2D.sortEntries() if all: return ( [ (entry.getIntoNodePath().findNetTag(tag), entry.getSurfacePoint(base.aspect2d)) for entry in self.mCollisionQue2D.getEntries() ], None, ) else: entry = self.mCollisionQue2D.getEntry(0) pickedObj = entry.getIntoNodePath() pickedObj = pickedObj.findNetTag(tag) if not pickedObj.isEmpty(): pos = entry.getSurfacePoint(base.aspect2d) return pickedObj, pos return None, None
class World(ShowBase): def __init__(self): # Load the default configuration.prc. This is recommended, as it # contains some important panda options loadPrcFile("../../Config/configuration.prc") ShowBase.__init__(self) # Create a new pipeline instance self.renderPipeline = RenderingPipeline(self) # Set the base path for the pipeline. This is required as we are in # a subdirectory self.renderPipeline.getMountManager().setBasePath("../../") # Also set the write path self.renderPipeline.getMountManager().setWritePath("../../Temp/") # Load the default settings self.renderPipeline.loadSettings("../../Config/pipeline.ini") # Now create the pipeline self.renderPipeline.create() # Add a directional light dPos = Vec3(40, 40, 15) dirLight = DirectionalLight() dirLight.setPos(dPos * 1000000.0) dirLight.setShadowMapResolution(1024) dirLight.setCastsShadows(True) dirLight.setColor(Vec3(8)) self.renderPipeline.addLight(dirLight) self.renderPipeline.setScatteringSource(dirLight) self.dirLight = dirLight self.keyMap = { "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0} base.win.setClearColor(Vec4(0, 0, 0, 1)) # Post the instructions self.title = addTitle( "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left") self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right") self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward") self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left") self.inst7 = addInstructions(0.65, "[S]: Rotate Camera Right") # 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("models/world") self.environ.reparentTo(render) self.environ.setPos(0, 0, 0) self.environ.find("**/wall").removeNode() # Create the main character, Ralph ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor("models/ralph", {"run": "models/ralph-run", "walk": "models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos) self.renderPipeline.setEffect(self.ralph, "Effects/Default/Default.effect", { "dynamic": True }) # 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("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]) # NOTICE: It is important that your update tasks have a lower priority # than -10000 taskMgr.add(self.move, "moveTask", priority=-20000) self.accept("r", self.reloadShader) # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 1.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 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) # Create some ocean self.water = ProjectedWaterGrid(self.renderPipeline) self.water.setWaterLevel(-4.0) # Create the skybox self.skybox = self.renderPipeline.getDefaultSkybox() self.skybox.reparentTo(render) self.prepareSRGB(render) self.reloadShader() self.renderPipeline.onSceneInitialized() # Add demo slider to move the sun position if self.renderPipeline.settings.displayOnscreenDebugger: self.renderPipeline.guiManager.demoSlider.node[ "command"] = self.setSunPos self.renderPipeline.guiManager.demoSlider.node[ "value"] = 50 def setSunPos(self): rawValue = self.renderPipeline.guiManager.demoSlider.node["value"] dPos = Vec3(100, 100, rawValue - 20) self.dirLight.setPos(dPos * 100000000.0) def reloadShader(self): self.renderPipeline.reloadShaders() # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value def prepareSRGB(self, np): """ Sets the correct texture format for all textures found in <np> """ for tex in np.findAllTextures(): baseFormat = tex.getFormat() if baseFormat == Texture.FRgb: tex.setFormat(Texture.FSrgb) elif baseFormat == Texture.FRgba: tex.setFormat(Texture.FSrgbAlpha) else: print "Unkown texture format:", baseFormat print "\tTexture:", tex # tex.setMinfilter(Texture.FTLinearMipmapLinear) # tex.setMagfilter(Texture.FTLinear) tex.setAnisotropicDegree(16) # 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 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 # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. camvec = self.ralph.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 7.0): base.camera.setPos(base.camera.getPos() + camvec * (camdist - 7)) camdist = 7.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) # 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) # Keep the camera at one foot above the terrain, # or two feet above ralph, 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.0) if (base.camera.getZ() < self.ralph.getZ() + 2.5): base.camera.setZ(self.ralph.getZ() + 2.5) # 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. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + 2.0) base.camera.lookAt(self.floater) return task.cont
class World(DirectObject): def __init__(self): self.keyMap = {"left":0, "right":0, "forward":0, "backward":0} base.win.setClearColor(Vec4(0,0,0,1)) # number of collectibles self.numObjects = 10; # print the number of objects printNumObj(self.numObjects) # Post the instructions self.title = addTitle("Roaming Ralph (Edited by Adam Gressen)") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[A]: Rotate Ralph Left") self.inst3 = addInstructions(0.85, "[D]: Rotate Ralph Right") self.inst4 = addInstructions(0.80, "[W]: Run Ralph Forward") self.inst5 = addInstructions(0.75, "[S]: Run Ralph Backward") self.inst6 = addInstructions(0.70, "[Space]: Run, Ralph, Run") # 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("models/world") self.environ.reparentTo(render) self.environ.setPos(0,0,0) # Timer to increment in the move task self.time = 0 # Get bounds of environment min, max = self.environ.getTightBounds() self.mapSize = max-min # Create the main character, Ralph self.ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(self.ralphStartPos) # ralph's health self.health = 100 # ralph's stamina self.stamina = 100 # 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) # these don't work well in combination with the space bar 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("arrow_down", self.setKey, ["backward",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("arrow_down-up", self.setKey, ["backward",0]) self.accept("space", self.runRalph, [True]) self.accept("space-up", self.runRalph, [False]) 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]) # Game state variables self.isMoving = False self.isRunning = False # Set up the camera base.disableMouse() #base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,2) base.camera.setPos(0, 0, 0) base.camera.reparentTo(self.ralph) base.camera.setPos(0, 40, 2) base.camera.lookAt(self.ralph) # 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. base.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0,0,300) 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() base.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) # camera ground collision handler self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,300) 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() base.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Place the health items self.placeHealthItems() # Place the collectibles self.placeCollectibles() # Uncomment this line to show a visual representation of the # collisions occuring #base.cTrav.showCollisions(render) # Create some lighting 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)) taskMgr.add(self.move,"moveTask") taskMgr.doMethodLater(0.5, self.healthDec, "healthTask") # reinitialize all necessary parts of the game def restart(self): self.numObjects = 10 printNumObj(self.numObjects) self.ralph.setPos(self.ralphStartPos) self.health = 100 self.stamina = 100 self.time = 0 base.camera.setPos(0, 0, 0) base.camera.reparentTo(self.ralph) base.camera.setPos(0, 40, 2) base.camera.lookAt(self.ralph) self.placeHealthItems() self.placeCollectibles() taskMgr.add(self.move,"moveTask") taskMgr.doMethodLater(0.5, self.healthDec, "healthTask") # Display ralph's health def displayHealth(self): healthBar['scale'] = (self.health*0.01*BAR_WIDTH,0.2,0.2) # Display ralph's stamina def displayStamina(self): sprintBar['scale'] = (self.stamina*0.01*BAR_WIDTH,0.2,0.2) # Allow ralph to collect the health items def collectHealthItems(self, entry): # refill ralph's health self.health = 100 # reposition the collectible self.placeItem(entry.getIntoNodePath().getParent()) def collectCollectibles(self, entry): # remove the collectible entry.getIntoNodePath().getParent().removeNode() # update the number of objects self.numObjects -= 1 printNumObj(self.numObjects) # Places an item randomly on the map def placeItem(self, item): # Add ground collision detector to the health item self.collectGroundRay = CollisionRay() self.collectGroundRay.setOrigin(0,0,300) self.collectGroundRay.setDirection(0,0,-1) self.collectGroundCol = CollisionNode('colRay') self.collectGroundCol.addSolid(self.collectGroundRay) self.collectGroundCol.setFromCollideMask(BitMask32.bit(0)) self.collectGroundCol.setIntoCollideMask(BitMask32.allOff()) self.collectGroundColNp = item.attachNewNode(self.collectGroundCol) self.collectGroundHandler = CollisionHandlerQueue() base.cTrav.addCollider(self.collectGroundColNp, self.collectGroundHandler) placed = False; while placed == False: # re-randomize position item.setPos(-random.randint(0,140),-random.randint(0,40),0) base.cTrav.traverse(render) # Get Z position from terrain collision entries = [] for j in range(self.collectGroundHandler.getNumEntries()): entry = self.collectGroundHandler.getEntry(j) 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"): item.setZ(entries[0].getSurfacePoint(render).getZ()+1) placed = True # remove placement collider self.collectGroundColNp.removeNode() def placeHealthItems(self): self.placeholder = render.attachNewNode("HealthItem-Placeholder") self.placeholder.setPos(0,0,0) # Add the health items to the placeholder node for i in range(5): # Load in the health item model self.healthy = loader.loadModel("models/sphere") self.healthy.setPos(0,0,0) self.healthy.reparentTo(self.placeholder) self.placeItem(self.healthy) # Add spherical collision detection healthSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('healthSphere') sphereNode.addSolid(healthSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.healthy.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) def placeCollectibles(self): self.placeCol = render.attachNewNode("Collectible-Placeholder") self.placeCol.setPos(0,0,0) # Add the health items to the placeCol node for i in range(self.numObjects): # Load in the health item model self.collect = loader.loadModel("models/jack") self.collect.setPos(0,0,0) self.collect.reparentTo(self.placeCol) self.placeItem(self.collect) # Add spherical collision detection colSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('colSphere') sphereNode.addSolid(colSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.collect.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Makes ralph's health decrease over time def healthDec(self, task): if (self.health <= 0): self.die() elif (self.numObjects != 0): self.health -= 1 print self.health return task.again else: return task.done # Make ralph's stamina regenerate def staminaReg(self, task): if (self.stamina >= 100): self.stamina = 100 return task.done else: self.stamina += 1 task.setDelay(1) return task.again # Make ralph run def runRalph(self, arg): self.isRunning = arg # 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.numObjects != 0: # print the time self.time += globalClock.getDt() timeText['text'] = str(self.time) else: self.die() # 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() # calculate ralph's speed if (self.isRunning and self.stamina > 0): taskMgr.remove("staminaTask") ralphSpeed = 45 self.stamina -= 0.5 else: taskMgr.doMethodLater(5, self.staminaReg, "staminaTask") ralphSpeed = 25 # If a move-key is pressed, move ralph in the specified direction. # and rotate the camera to remain behind ralph if (self.keyMap["left"]!=0): self.ralph.setH(self.ralph.getH() + 100 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.ralph.setH(self.ralph.getH() - 100 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.ralph.setY(self.ralph, -ralphSpeed * globalClock.getDt()) if (self.keyMap["backward"]!=0): self.ralph.setY(self.ralph, ralphSpeed *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) or (self.keyMap["backward"]!=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 # so the following line is unnecessary base.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()) #base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+5) elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "healthSphere"): self.collectHealthItems(entries[0]) elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "colSphere"): self.collectCollectibles(entries[0]) else: self.ralph.setPos(startpos) # Keep the camera above the terrain 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"): modZ = entries[0].getSurfacePoint(render).getZ() base.camera.setZ(20.0+modZ+(modZ-self.ralph.getZ())) self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ()+2.0) base.camera.lookAt(self.floater) self.displayHealth() self.displayStamina() return task.cont # Restart or End? def die(self): # end all running tasks taskMgr.remove("moveTask") taskMgr.remove("healthTask") # open the file f = open('scores.txt', 'r') # current name, time, and collected items score n = f.readline() t = f.readline() c = f.readline() # close the file f.close() # number of collected collectibles colObj = 10 - self.numObjects # enter new high score if int(c) < colObj or (int(c) == colObj and float(t) > self.time): self.label = DirectLabel(text="New High Score! Enter Your Name:", scale=.05, pos=(0,0,0.2)) self.entry = DirectEntry(text="", scale=.05, initialText="", numLines=1, focus=1, pos=(-0.25,0,0), command=self.submitScore) else: # display high score self.highscore = OkDialog(dialogName="highscoreDialog", text="Current High Score:\n\nName: " + n + "Time: " + t + "Items Collected: " + c, command=self.showDialog) def showDialog(self, arg): # cleanup highscore dialog self.highscore.cleanup() # display restart or exit dialog self.dialog = YesNoDialog(dialogName="endDialog", text="Would you like to play again?", command=self.endResult) def submitScore(self, name): f = open('scores.txt', 'w') # add new high score value = name + '\n' + str(self.time) + '\n' + str(10 - self.numObjects) f.write(value) f.close() self.entry.remove() self.label.remove() self.dialog = YesNoDialog(dialogName="endDialog", text="Would you like to play again?", command=self.endResult) # Handle the dialog result def endResult(self, arg): if (arg): # cleanup the dialog box self.dialog.cleanup() # restart the game self.restart() else: sys.exit()
class Fighter(): def __init__(self,characterPath , callOnDeath , side , name = None): #side indicates if the player is on the left or right side. #TODO: add collision tests against ring-out geometry in the arena, self.fsm = FighterFsm(self,characterPath) self.inputHandler = InputHandler(self.fsm,side) self.side = side self.wins = 0 #counting won rounds, a double-ko/draw counts as win for both. self.faceOpp = True #looking at opponent self.callOnDeath = callOnDeath self.statusBitMask = BitMask32() self.defenseBitMask = BitMask32() #active defense parts get a 1 #the attack bitmask is generated by the fsm and passed to the attack method directly if not name: name = "player"+str(1+bool(side)) self.healthBar = PlayerHud(side, name ) self.fighterNP = render.attachNewNode(name) self.collTrav = CollisionTraverser(name) fromObject = self.fighterNP.attachNewNode(CollisionNode('colNode'+name)) fromObject.node().addSolid(CollisionRay(0, 0, 2,0,0, -1)) fromObject.node().setFromCollideMask(BitMask32.bit(1)) fromObject.node().setIntoCollideMask(BitMask32.allOff()) self.queue = CollisionHandlerQueue() self.collTrav.addCollider(fromObject, self.queue) self.fsm.getNP().reparentTo(self.fighterNP) #fromObject.show() #more debug collision visuals #self.collTrav.showCollisions(render) #debug visuals for collision self.prepareFighter() def updateState(self,newState = None): if newState: if "enter" + state in dir(self.fsm): self.fsm.forceTransition(newState) else: self.inputHandler.pollEvents() def prepareFighter(self): taskMgr.remove("player"+str(self.side)) self.speed = (0,0) self.fsm.forceTransition("Idle") self.health= 100 self.healthBar.setHealth(self.health) self.healthBar.setRoundIndicator('V'*self.wins) if self.side: self.fighterNP.setX(5) else: self.fighterNP.setX(-5) self.fighterNP.setY(0) taskMgr.add(self._playertask, "player"+str(self.side)) def setStatusBitMask(self,bitmask): self.statusBitMask = bitmask def setDefenseBitMask(self,bitmask): self.defenseBitMask = bitmask #getters and setters are a bit stupid here. properties from python 3 would be nice def fighterWin(self): #request a win-anim from the fsm if there are any self.wins += 1 self.healthBar.setRoundIndicator('V'*self.wins) def getWins(self): return self.wins def getHealth(self): return self.health def getNP(self): return self.fighterNP def setOpponent(self,opponent): self.opponent = opponent self.fighterNP.lookAt(self.opponent.getNP()) def attack(self,attackBitMask,attackrange,damageHit,damageDodge=0,angle=30): #those variables will be supplied by the fsm states later on. #function is pretty redundant... for structure only, and for early days attackstatus = self.opponent.getAttacked(attackBitMask,attackrange,damageHit,damageDodge,angle) return attackstatus def _testHit(self,node1,node2,threshold=30, dist = 1): #node1 which looks for a target , node2 is the target , threshold is the max-attack-angle, dist the dist dirVec = node1.getRelativePoint(node2,Vec3(0,0,0)) dirVec = Vec3(dirVec[0],dirVec[1],dirVec[2]) dirVec.normalize() angle = dirVec.angleDeg(Vec3(0,1,0)) if angle < threshold and dist > node1.getDistance(node2): #print "hit at "+str(angle)+" degree!" return True else: #print angle,node1.getDistance(node2) return False def getAttacked(self,attackBitMask,attackrange,damageHit,damageDodge=0,angle = 30): """ returns 0 if not hit, 1 if hit was blocked, 2 if hit, 3 for hit+KO """ if self.health <=0: return 4 #player is ko already if not self._testHit(self.opponent.getNP(),self.fighterNP ,angle,attackrange ) : #instead of 0, a sligtly positive values makes thinks look better. #attack misses due to out of range. return 0 if (self.statusBitMask & attackBitMask).getWord() == 0: # attak misses cause the player avoided it. went low or so. return 0 if (self.defenseBitMask & attackBitMask).getWord(): self.health -= damageDodge self.healthBar.setHealth(self.health) return 1 #hit,... but blocked so no combos else: self.health -= damageHit self.healthBar.setHealth(self.health) if self.health <= 0 : #if KO taskMgr.remove("player"+str(self.side)) self.fsm.forceTransition("Ko") #actually make the match.py allow the other player to KO (in case of doubleKO,befor calling round end. taskMgr.doMethodLater(0.5,self.callOnDeath,"RoundEnd") return 3 #TODO: requesting the same state as you are in doesnt work well.sorta need to re-enter the hit state if "Crouch" in self.fsm.state: self.fsm.forceTransition("CrouchHit") elif self.fsm.state: self.fsm.forceTransition("Hit") return 2 #regular hit def setSpeed(self,x,y): self.speed = (x,y) def faceOpponent(self,facing): self.faceOpp = facing #true if yuo look at the other player (usualy true unless attacking), so you can dodge an attack by evading. def _playertask(self,task): oldpos = self.fighterNP.getPos() dist = self.fighterNP.getY(self.opponent.getNP()) if dist > 3 or self.speed[0]<0: #prevert players from walking throug each other , too troublesome atm self.fighterNP.setX(self.fighterNP,self.speed[1]*globalClock.getDt()) self.fighterNP.setY(self.fighterNP,self.speed[0]*globalClock.getDt()) else : self.speed = ( min(2,self.speed[0] ), self.speed[1]) #also push back other player self.opponent.getNP().setY(self.opponent.getNP(),-self.speed[0]*globalClock.getDt() ) self.collTrav.traverse(render) self.queue.sortEntries() for i in range(self.queue.getNumEntries()): entry = self.queue.getEntry(i) if "ground" in entry.getIntoNodePath().getName() : break if "out" in entry.getIntoNodePath().getName() : pass #ring out self.fighterNP.setPos(oldpos) #for now reset him as we have no ring-out anim yet #TODO: add ring out anim! break if self.queue.getNumEntries() == 0: #if there is no ground and no ring out, propably a wall or no thin like that. just reset the pos self.fighterNP.setPos(oldpos) print "resetting fighter" if self.faceOpp: self.fighterNP.lookAt(self.opponent.getNP()) return task.cont
class GameEngine( DirectObject ): def __init__(self): print 'Game Engine Started' self.lastBlock = 0 self.map = [] self.startBlock = 0 self.endBlock = 0 self.mapName = 'test2' self.loadEnvironment(self.mapName) self.loadCursorPicker() self.camera = RTS_Camera() self.loadSimpleLighting() self.waveController = WaveController(self.mapName, self.startBlock, self.map) self.towerController = TowerController(self.waveController) self.setupKeyListeners() self.EFT = taskMgr.add(self.everyFrameTask, "everyFrameTask") # The task that is run every frame def everyFrameTask(self, task): self.camera.handleMouseInput() self.checkCursorCollision() self.towerController.updateTowers() return task.cont # Loads the level from the text file. Puts each # row into an array then creates the rows in the # 1st quadrant def loadEnvironment(self, file): fileName = 'maps/' + file + '.map' rows = [] self.environmentRoot = render.attachNewNode('environmentRoot') FILE = open(fileName, 'r') while( 1 ): line = FILE.readline() if( not line ): break print line, if( line[-1] == '\n' ): line = line[:-1] rows.append(line) rows.reverse() for i, row in enumerate(rows): self.createRow( i, row ) # Loads the models corresponding to the # characters in the map file for an entire row def createRow(self, rowIndex, row): mapRow = [] for colIndex, block in enumerate(row): block = BLOCK_CHAR_TO_MODEL[block]( self.environmentRoot, colIndex + 0.5, rowIndex + 0.5 ) mapRow.append( block ) block.setIndex( str(rowIndex) + ' ' + str(colIndex) ) if( block.isType(StartBlock) ): self.startBlock = block elif( block.isType(EndBlock) ): self.endBlock = block self.map.append(mapRow) # Creates necessary collision parts to determine what object # the cursor is hovering def loadCursorPicker(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) def checkCursorCollision(self): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens( base.camNode, mpos.getX(), mpos.getY() ) self.picker.traverse( self.environmentRoot ) if( self.pq.getNumEntries() > 0 ): self.pq.sortEntries() (row, ignore, col) = self.pq.getEntry(0).getIntoNode().getTag('index').partition(' ') row = int(row) col = int(col) block = self.map[row][col] if( block != self.lastBlock ): block.highlight() if( self.lastBlock ): self.lastBlock.unHighlight() self.lastBlock = block else: if( self.lastBlock ): self.lastBlock.unHighlight() self.lastBlock = 0 def mouseClick(self): if( self.lastBlock ): self.towerController.addTower(self.lastBlock) def spawnEnemy(self): e = Enemy(self.startBlock, self.map) e.moveToEnd() def setTowerType(self, type): self.towerController.currentTowerType = type def setupKeyListeners(self): self.accept('mouse1', self.mouseClick) self.accept('q', self.waveController.start) self.accept('1', self.setTowerType, [NormalTower]) self.accept('2', self.setTowerType, [SlowTower]) self.accept('3', self.setTowerType, [StunTower]) def loadSimpleLighting(self): ambientLight = AmbientLight( "ambientLight" ) ambientLight.setColor( Vec4(.8, .8, .8, 1) ) directionalLight = DirectionalLight( "directionalLight" ) directionalLight.setDirection( Vec3( 0, 45, -45 ) ) directionalLight.setColor( Vec4( 0.2, 0.2, 0.2, 0.6 ) ) render.setLight(render.attachNewNode( directionalLight ) ) render.setLight(render.attachNewNode( ambientLight ) )
class Labryn(DirectObject): def setCamera(self, spin): self.spin = spin def spinCamera(self, task): if self.spin == 1: # spin counter-clockwise self.cameraSpinCount += 1 angleDegrees = self.cameraSpinCount angleRadians = angleDegrees * (pi/ 180) self.CAM_RAD = angleRadians camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD), _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD), (25.0/12)*self.CAM_R) camera.setHpr(angleDegrees,-65,0) elif self.spin == 2: # spin clockwise self.cameraSpinCount -= 1 angleDegrees = self.cameraSpinCount angleRadians = angleDegrees * (pi/ 180) self.CAM_RAD = angleRadians camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD), _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD), (25.0/12)*self.CAM_R) camera.setHpr(angleDegrees,-65,0) elif self.spin == 3: # ZOOM IN not spin self.cameraZoomCount += 1 deltaR = self.cameraZoomCount * 0.1 new_R = 12-deltaR self.CAM_R = new_R camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD), _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD), (25.0/12)*new_R) elif self.spin == 4: # ZOOM OUT self.cameraZoomCount -= 1 deltaR = self.cameraZoomCount * 0.1 new_R = 12-deltaR self.CAM_R = new_R camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD), _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD), (25.0/12)*self.CAM_R) return Task.cont def checkMouse(self, task): if base.mouseWatcherNode.hasMouse(): self.mouseX=base.mouseWatcherNode.getMouseX() self.mouseY=base.mouseWatcherNode.getMouseY() return Task.cont def dropRock(self): if self.pokeMoveChoice == 1: # selected Geodude result = MAZE.canDropRock(self.rockX, self.rockY) if result != False: # can place rock here MAZE.dropRock(result[0],result[1]) self.rock.setPos(self.rockX, self.rockY, 1) self.rockOnMaze = True self.pokeMoveChoice = None self.myPokeName.hide() self.myPokeName = None self.updateTwoD() self.playerCandyCount -= 1 def useFlame(self): self.onFire = True # on fire self.playerCandyCount -= 1 self.pokeStatus = 1 self.flame = ParticleEffect() self.flame.loadConfig("fireish.ptf") self.flame.setPos(self.pikachu.getPos()) self.flame.start(parent=render, renderParent=render) self.updateTwoD() def useStringShot(self): self.pokeStatus = 2 self.updateTwoD() def placeRock(self, task): if self.pokeMoveChoice == 1: # selected Geodude dX,dY = ((self.mouseX-self.rockRefX), (self.mouseY-self.rockRefY)) self.rockX, self.rockY = MAZE.translateRockPosition(self.rockRefX, self.rockRefY, dX, dY) self.rock.show() self.rock.setPos(self.rockX, self.rockY, 1) self.updateTwoD() return Task.cont def placeRareCandy(self, task): if int(task.time) % 4 == 9 and self.candyOnBoard: self.candy.hide() self.candyOnBoard = False if int(task.time) % 10 == 0 and (self.candyOnBoard == False): # every 10 seconds self.candy.setPos(MAZE.generateCandyPos()) self.candy.show() self.candyOnBoard = True return Task.cont def updateTwoD(self): # update player candy count self.playerCandyStatus.destroy() self.playerCandyStatus = candyStatus(0, self.playerCandyCount) # update pikachu candy count # TODO # update my pokes color if self.playerCandyCount == 0 : groupHide(self.myPokesBright) groupShow(self.myPokesDark) # update name if self.myPokeName != None: self.myPokeName.destroy() def clearRock(self): self.rock.hide() self.rockOnMaze = False MAZE.clearRock() # clear it in 2D def clearFlame(self): self.onFire = False self.flame.cleanup() self.pokeStatus = 0 self.pokeMoveChoice = None try: self.myPokeName.destroy() except: pass self.myPokeName = None def clearString(self): self.pokeStatus = 0 self.pokeMoveChoice = None try: self.myPokeName.destroy() except: pass self.myPokeName = None def timer(self, task): # deals with moves' lasting effects ############################################################## if self.rockOnMaze: # rock on maze self.rockCounter += 1 elif self.rockCounter != 1: # rock not on maze, counter not cleared self.rockCounter = 0 if self.onFire: self.fireCounter += 1 elif self.fireCounter != 1: self.fireCounter = 0 if self.pokeStatus == 2: # string shot self.stringCounter += 1 elif self.stringCounter != 1: self.stringCounter = 0 ################################################################## if self.rockCounter == 500: self.clearRock() if self.fireCounter == 80: self.clearFlame() if self.stringCounter == 120: self.clearString() return Task.cont def usePokeMove(self, number): if self.playerCandyCount > 0: # have more than one candy if number == 1 and self.rockOnMaze == False: if self.pokeMoveChoice != 1: # NONE or other # set to center position centerx = base.win.getProperties().getXSize()/2 centery = base.win.getProperties().getYSize()/2 base.win.movePointer(0,centerx,centery) self.pokeMoveChoice = 1 # placeRock called here self.rockRefX, self.rockRefY = 0,0 self.rock.show() self.rock.setPos(0,0,1) else: # already 1 self.pokeMoveChoice = None self.clearRock() # clear rock elif number == 2: if self.pokeMoveChoice != 2: self.pokeMoveChoice = 2 self.useFlame() else: self.pokeMoveChoice = None elif number == 3: if self.pokeMoveChoice != 3: self.pokeMoveChoice = 3 self.useStringShot() else: self.pokeMoveChoice = None if self.pokeMoveChoice == None: # no choice if self.myPokeName != None: # there is a name on board self.myPokeName.destroy() # kill it else: # no name pass else: # there is a choice if self.myPokeName != None: self.myPokeName.destroy() self.myPokeName = Two_D.writePokeName(self.pokeMoveChoice) def loadRareCandy(self): self.candy = Model_Load.loadRareCandy() self.candy.reparentTo(render) self.candy.setScale(0.1) self.candy.hide() def eatRareCandy(self, task): if self.candyOnBoard: # candy on board if checkEat(self.ballRoot.getX(), self.ballRoot.getY(), self.candy.getX(), self.candy.getY()): # ball eats self.candy.hide() # eaten self.candyOnBoard = False self.playerCandyCount += 1 # self.playerCandyStatus.destroy() # self.playerCandyStatus = candyStatus(0, # self.playerCandyCount) # update print "BALL EATS CANDY" groupShow(self.myPokesBright) elif checkEat(self.pikachu.getX(), self.pikachu.getY(), self.candy.getX(), self.candy.getY()): self.candy.hide() self.candyOnBoard = False self.pokemonCandyCount += 1 return Task.cont def setFocus(self, changing): self.changingFocus = changing if changing == True: # Just Pressed self.referenceX, self.referenceY = self.mouseX, self.mouseY else: # cursor moves up self.referenceX, self.referenceY = None, None def resetView(self): self.CAM_R, self.CAM_RAD = 12, 0 self.cameraSpinCount, self.cameraZoomCount = 0, 0 # _FOCUS = [0,0,0] does not work WHY??? _FOCUS[0], _FOCUS[1], _FOCUS[2] = 0,0,0 self.changingFocus = False self.referenceX, self.referenceY = None, None camera.setPos(_FOCUS[0], _FOCUS[1]-self.CAM_R, 25) camera.setHpr(0, -65, 0) def changeFocus(self, task): if (self.changingFocus == True and self.mouseX != None and self.mouseY != None ): dX, dY = ((self.mouseX - self.referenceX)*0.1, (self.mouseY - self.referenceY)*0.1) _FOCUS[0] += dX _FOCUS[1] += dY camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD), _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD), (25.0/12)*self.CAM_R) return Task.cont def initialize(self): #bgmusic = load_bgmusic("palette.mp3") #bgmusic.play() self.background = Two_D.loadBackground() base.cam2dp.node().getDisplayRegion(0).setSort(-20) self.candyOnBoard = False self.playerCandyCount, self.pokemonCandyCount = 2, 0 ######################Rare Candy############################### pokes=['caterpie', 'charmander', 'geodude'] self.myPokesDark = Two_D.loadMyPokemon_Dark(pokes) # my pokemons self.myPokesBright = Two_D.loadMyPokemon_Bright() groupHide(self.myPokesBright) self.loadRareCandy() # load rare candy ######################Camera Initialization#################### self.CAM_R, self.CAM_RAD = 12, 0 camera.setPos(_FOCUS[0],_FOCUS[1]-12,_FOCUS[2]+25) camera.setHpr(0, -65, 0) self.cameraSpinCount, self.cameraZoomCount = 0, 0 self.changingFocus = False self.spin = 0 #######################ICONS################################### self.myIcon = Two_D.loadMyIcon() self.pokeIcon = Two_D.loadPokeIcon() self.playerCandyStatus = candyStatus(0, self.playerCandyCount) #######################FLAMES################################## base.enableParticles() self.fireCounter = 0 self.onFire = False #######################STRINGSHOT############################# self.stringCounter = 0 #######################GLOBALS################################# self.i = 0 self.myDirection = ['zx', 'zy'] self.rockCounter = 0 self.rockX, self.rockY = None, None self.rockOnMaze = False self.pokeMoveChoice = None self.myPokeName = None self.arrowKeyPressed = False self.pokemonDirection = 'd' self.mouseX, self.mouseY = None, None # direction the ball is going self.jerkDirection = None base.disableMouse() self.jerk = (0,0,0) self.MAZE = Model_Load.loadLabyrinth() Control.keyControl(self) self.loadPokemonLevel1() self.light() self.loadBall() self.pokeStatus = 0 # 0 is normal, 1 is burned, 2 is slow-speed ########################################ROCK################### self.rock = Model_Load.loadRock() self.rock.reparentTo(render) self.rock.hide() # Do not show, but load beforehand for performance def loadPokemonLevel1(self): self.pikachu = load_model("pikachu.egg") self.pikachu.reparentTo(render) self.pikachu.setScale(0.3) endPos = self.MAZE.find("**/end").getPos() self.pikachu.setPos(endPos) def light(self): 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)) def loadBall(self): self.ballRoot = render.attachNewNode("ballRoot") self.ball = load_model("ball") self.ball.reparentTo(self.ballRoot) self.ball_tex = load_tex("pokeball.png") self.ball.setTexture(self.ball_tex,1) self.ball.setScale(0.8) # Find the collision sphere for the ball in egg. self.ballSphere = self.ball.find("**/ball") self.ballSphere.node().setFromCollideMask(BitMask32.bit(0)) self.ballSphere.node().setIntoCollideMask(BitMask32.allOff()) #self.ballSphere.show() # Now we create a ray to cast down at the ball. self.ballGroundRay = CollisionRay() self.ballGroundRay.setOrigin(0,0,10) self.ballGroundRay.setDirection(0,0,-1) # Collision solids go in CollisionNode self.ballGroundCol = CollisionNode('groundRay') self.ballGroundCol.addSolid(self.ballGroundRay) self.ballGroundCol.setFromCollideMask(BitMask32.bit(1)) self.ballGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol) # light ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.55, .55, .55, 1)) 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)) self.ballRoot.setLight(render.attachNewNode(ambientLight)) self.ballRoot.setLight(render.attachNewNode(directionalLight)) # material to the ball m = Material() m.setSpecular(Vec4(1,1,1,1)) m.setShininess(96) self.ball.setMaterial(m,1) def __init__(self): self.initialize() self.WALLS = self.MAZE.find("**/Wall.004") self.WALLS.node().setIntoCollideMask(BitMask32.bit(0)) # collision with the ground. different bit mask #self.mazeGround = self.maze.find("**/ground_collide") #self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1)) self.MAZEGROUND = self.MAZE.find("**/Cube.004") self.MAZEGROUND.node().setIntoCollideMask(BitMask32.bit(1)) # add collision to the rock cs = CollisionSphere(0, 0, 0, 0.5) self.cnodePath = self.rock.attachNewNode(CollisionNode('cnode')) self.cnodePath.node().addSolid(cs) self.cnodePath.show() self.cnodePath.node().setIntoCollideMask(BitMask32.bit(0)) # load the ball and attach it to the scene. # it is on a dummy node so that we can rotate the ball # without rotating the ray that will be attached to it # CollisionTraversers calculate collisions self.cTrav = CollisionTraverser() #self.cTrav.showCollisions(render) #self.cTrav.showCollisions(render) # A list collision handler queue self.cHandler = CollisionHandlerQueue() # add collision nodes to the traverse. # maximum nodes per traverser: 32 self.cTrav.addCollider(self.ballSphere,self.cHandler) self.cTrav.addCollider(self.ballGroundColNp,self.cHandler) self.cTrav.addCollider(self.cnodePath, self.cHandler) # collision traversers have a built-in tool to visualize collisons #self.cTrav.showCollisions(render) self.start() def pokemonTurn(self, pokemon, direction): if direction == 'l' and self.pokemonDirection != 'l': self.pokemonDirection = 'l' pokemon.setH(-90) if direction == 'r' and self.pokemonDirection != 'r': self.pokemonDirection = 'r' pokemon.setH(90) if direction == 'd' and self.pokemonDirection != 'd': self.pokemonDirection = 'd' pokemon.setH(0) if direction == 'u' and self.pokemonDirection != 'u': self.pokemonDirection = 'u' pokemon.setH(180) def pokemonMove(self, pokemon, direction): self.pokemonTurn(pokemon, direction) if self.pokeStatus == 0: speed = _SPEED elif self.pokeStatus == 1: speed = 0 else: # self.pokeStatus == 2 speed = _SPEED/2.0 if direction == 'l': newX = pokemon.getX() - speed pokemon.setX(newX) elif direction == 'r': newX = pokemon.getX() + speed pokemon.setX(newX) elif direction == 'u': newY = pokemon.getY() + speed pokemon.setY(newY) elif direction == 'd': newY = pokemon.getY() - speed pokemon.setY(newY) elif direction == "s": # stop pass def whereToGo(self, task): # this returns the direction pokemon should go # tell MAZE pokemon and ball's board position print self.myDirection MAZE.setPokeCoord(self.pikachu.getX(), self.pikachu.getY(), self.pokemonDirection) MAZE.setBallCoord(self.ballRoot.getX(), self.ballRoot.getY()) # find out which direction to go direction = MAZE.getDecision() self.pokemonMove(self.pikachu,direction) return Task.cont def getInformation(self, task): # get information on the board # TODO self.i += 1 # sample every other call to avoid if self.i % 2 == 0: dX = self.ballRoot.getX() - self.oldPos[0] dY = self.ballRoot.getY() - self.oldPos[1] if dX < 0 : # print "going left" self.myDirection[0] = 'l' elif abs(dX) < _EPSILON: # print "not moving horiz" self.myDirection[0] = 'zx' else: # print "going right" self.myDirection[0] = 'r' if dY < 0 : # print "going down" self.myDirection[1] = 'd' elif abs(dY) < _EPSILON: # print "not moving verti" self.myDirection[1] = 'zy' else: # print "going up" self.myDirection[1] = 'u' self.oldPos = self.ballRoot.getPos() return Task.cont def start(self): # maze model has a locator in it # self.ballRoot.show() self.startPos = self.MAZE.find("**/start").getPos() self.oldPos = self.MAZE.find("**/start").getPos() self.ballRoot.setPos(self.startPos) # set the ball in the pos self.ballV = Vec3(0,0,0) # initial velocity self.accelV = Vec3(0,0,0) # initial acceleration # for a traverser to work, need to call traverser.traverse() # base has a task that does this once a frame base.cTrav = self.cTrav # create the movement task, make sure its not already running taskMgr.remove("rollTask") taskMgr.add(self.placeRock, "placeRock") taskMgr.add(self.timer, "timer") taskMgr.add(self.getInformation, "getInformation") taskMgr.add(self.eatRareCandy, "eatRareCandy") taskMgr.add(self.placeRareCandy, "placeRareCandy") taskMgr.add(self.checkMouse, "checkMouse") taskMgr.add(self.spinCamera, "spinCamera") taskMgr.add(self.changeFocus, "changeFocus") taskMgr.add(self.whereToGo, "whereToGo") # taskMgr.add(lambda task: self.moveBall(task, self.jerkDirection), # "moveBall") taskMgr.add(self.moveBall, "moveBall") self.mainLoop = taskMgr.add(self.rollTask, "rollTask") self.mainLoop.last = 0 def moveBallWrapper(self, direction): if direction == False: self.arrowKeyPressed = False else: self.arrowKeyPressed = True self.jerkDirection = direction def moveBall(self, task): direction = self.jerkDirection if self.arrowKeyPressed == True: if direction == "u": self.jerk = Vec3(0,_JERK,0) elif direction == "d": self.jerk = Vec3(0,-_JERK,0) elif direction == "l": self.jerk = Vec3(-_JERK,0,0) elif direction == "r": self.jerk = Vec3(_JERK,0,0) return Task.cont """ def moveBall(self, task, direction): if self.arrowKeyPressed == True: if direction == "u": self.jerk = Vec3(0,_JERK,0) elif direction == "d": self.jerk = Vec3(0,-_JERK,0) elif direction == "l": self.jerk = Vec3(-_JERK,0,0) elif direction == "r": self.jerk = Vec3(_JERK,0,0) return Task.cont """ # collision between ray and ground # info about the interaction is passed in colEntry def groundCollideHandler(self,colEntry): # set the ball to the appropriate Z for it to be on the ground newZ = colEntry.getSurfacePoint(render).getZ() self.ballRoot.setZ(newZ+.4) # up vector X normal vector norm = colEntry.getSurfaceNormal(render) accelSide = norm.cross(UP) self.accelV = norm.cross(accelSide) # collision between the ball and a wall def wallCollideHandler(self,colEntry): # some vectors needed to do the calculation norm = colEntry.getSurfaceNormal(render) * -1 norm.normalize() curSpeed = self.ballV.length() inVec = self.ballV/curSpeed velAngle = norm.dot(inVec) # angle of incidance hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos() hitDir.normalize() hitAngle = norm.dot(hitDir) # deal with collision cases if velAngle > 0 and hitAngle >.995: # standard reflection equation reflectVec = (norm * norm.dot(inVec*-1)*2) + inVec # makes velocity half of hitting dead-on self.ballV = reflectVec * (curSpeed * (((1-velAngle)*.5)+.5)) # a collision means the ball is already a little bit buried in # move it so exactly touching the wall disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) newPos = self.ballRoot.getPos() + disp self.ballRoot.setPos(newPos) def rollTask(self,task): # standard technique for finding the amount of time # since the last frame dt = task.time - task.last task.last = task.time # If dt is large, then there is a HICCUP # ignore the frame if dt > .2: return Task.cont # dispatch which function to handle the collision based on name for i in range(self.cHandler.getNumEntries()): entry = self.cHandler.getEntry(i) name = entry.getIntoNode().getName() if name == "Wall.004": self.wallCollideHandler(entry) elif name=="Cube.004": self.groundCollideHandler(entry) else: if self.rockOnMaze == True: self.wallCollideHandler(entry) self.accelV += self.jerk # move the ball, update the velocity based on accel self.ballV += self.accelV * dt * ACCELERATION # clamp the velocity to the max speed if self.ballV.lengthSquared() > MAX_SPEED_SQ: self.ballV.normalize() self.ballV *= MAX_SPEED # update the position self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV*dt)) # uses quaternion to rotate the ball prevRot = LRotationf(self.ball.getQuat()) axis = UP.cross(self.ballV) newRot = LRotationf(axis, 45.5 * dt * self.ballV.length()) self.ball.setQuat(prevRot * newRot) return Task.cont # continue the task
class TrainingBananas(JoystickHandler): def __init__(self): """ Initialize the experiment """ pydaq_loaded = PYDAQ_LOADED self.base = ShowBase() config = {} execfile('train_config.py', config) if not unittest: JoystickHandler.__init__(self) self.base.disableMouse() sys.stdout.write('Subject is ' + str(config['subject']) + '\n') self.subject = config['subject'] self.levels_available = [[2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6], [3, 3.1], [4, 4.1, 4.2]] # set up reward system # if unit-testing, pretend like we couldn't # load the module if unittest: pydaq_loaded = False if config['reward'] and pydaq_loaded: self.reward = pydaq.GiveReward() else: self.reward = None sys.stdout.write('Warning: reward system not on \n') # setup windows if not unittest: # if doing unittests, there is no window wp = WindowProperties() # wp.setSize(1280, 800) wp.setSize(1024, 768) wp.setOrigin(0, 0) wp.setCursorHidden(True) self.base.win.requestProperties(wp) # base.setFrameRateMeter(True) # initialize training file name self.data_file_name = '' self.data_file = None self.open_data_file(config) # Get initial direction, only matters for manual, random will override later # for bananas, changing the angle from avatar to banana, so left is negative # right is positive. if config['trainingDirection'] == 'Right': self.multiplier = 1 elif config['trainingDirection'] == 'Left': self.multiplier = -1 # print config['trainingDirection'] self.last_multiplier = self.multiplier # get more variables from configuration self.side_bias = config['random_bias'] # bring some configuration parameters into memory, so we don't need to # reload the config file multiple times, also allows us to change these # variables dynamically self.num_beeps = config['numBeeps'] # not changing now, but may eventually... self.x_alpha = config['xHairAlpha'] self.reward_time = config['pulseInterval'] # usually 200ms # amount need to hold crosshair on banana to get reward (2.3) # must be more than zero. At 1.5 distance, must be greater than # 0.5 to require stopping self.hold_aim = config['hold_aim'] self.initial_speed = config['initial_turn_speed'] self.initial_forward_speed = config['initial_forward_speed'] self.forward_limit = config['forward_limit'] self.training = config['training'] if not unittest: sys.stdout.write('training level: ' + str(self.training) + '\n') if self.training < 2.2: sys.stdout.write('starting direction: ' + str(config['trainingDirection']) + '\n') # random selection used for training 2.3 and above self.all_random_selections = config['random_lists'] self.current_choice = config['random_selection'] - 1 self.random_choices = self.all_random_selections[self.current_choice] # Setup Graphics # bitmasks for collisions ray_mask = BitMask32(0x1) sphere_mask = BitMask32(0x2) self.mask_list = [ray_mask, sphere_mask, ray_mask | sphere_mask] if config['background']: field = self.base.loader.loadModel("models/play_space/field.bam") field.setPos(Point3(0, 0, 0)) field.reparentTo(self.base.render) field_node_path = field.find('**/+CollisionNode') field_node_path.node().setIntoCollideMask(0) sky = self.base.loader.loadModel("models/sky/sky.bam") sky.setPos(Point3(0, 0, 0)) sky.reparentTo(self.base.render) # set up banana self.banana = None self.banana_mask = None self.banana_node_path = None self.banana_coll_node = None self.load_fruit(config.get('fruit', 'banana')) # set up collision system and collision ray to camera self.base.cTrav = CollisionTraverser() self.collHandler = CollisionHandlerQueue() ray_node = self.base.camera.attachNewNode(CollisionNode('CrossHairRay')) # ray that comes straight out from the camera ray_solid = CollisionRay(0, 0, 0, 0, 1, 0) self.ray_node_path = self.make_coll_node_path(ray_node, ray_solid) self.ray_node_path.node().setIntoCollideMask(0) self.ray_node_path.node().setFromCollideMask(ray_mask) # add collision sphere to camera sphere_node = self.base.camera.attachNewNode(CollisionNode('CollisionSphere')) # camera_sphere = CollisionSphere(0, 0, 0, 1.3) # avatar_radius = 0.3 avatar_radius = 1 camera_sphere = CollisionSphere(0, 0, 0, avatar_radius) self.sphere_node_path = self.make_coll_node_path(sphere_node, camera_sphere) self.sphere_node_path.node().setIntoCollideMask(0) self.sphere_node_path.node().setFromCollideMask(sphere_mask) # into collide masks are set with level variables, since we change # whether between using the sphere or the ray for detecting collisions, # depending on which level we are on. self.base.cTrav.addCollider(self.ray_node_path, self.collHandler) self.base.cTrav.addCollider(self.sphere_node_path, self.collHandler) # self.base.cTrav.showCollisions(self.base.render) # self.ray_node_path.show() # self.sphere_node_path.show() # self.banana_node_path.show() # self.base.render.find('**/+CollisionNode').show() # Camera self.base.camLens.setFov(60) # set avatar position/heading # Default positions self.avatar_pos = Point3(0, -1.5, 1) self.avatar_h = 0 self.screen_edge = 30 self.config_avatar_d = -config['avatar_start_d'] self.config_avatar_h = config['avatar_start_h'] # Cross hair # color changes for crosshair self.x_start_c = Point4(1, 1, 1, self.x_alpha) self.x_stop_c = Point4(1, 0, 0, self.x_alpha) self.crosshair = TextNode('crosshair') self.crosshair.setText('+') text_node_path = self.base.aspect2d.attachNewNode(self.crosshair) text_node_path.setScale(0.2) # crosshair is always in center, but # need it to be in same place as collisionRay is, but it appears that center is # at the bottom left of the collisionRay, and the top right of the text, so they # don't have center in the same place. Makes more sense to move text than ray. # These numbers were scientifically determined. JK, moved around until the cross looked # centered on the ray # crosshair_pos = Point3(0, 0, 0) # crosshair_pos = Point3(-0.07, 0, -0.05) crosshair_pos = Point3(-0.055, 0, -0.03) # print text_node_path.getPos() text_node_path.setPos(crosshair_pos) # set level # setup variables related to training levels # initialize training variables # will be set to proper levels in set_level_variables method self.free_move = 0 self.must_release = False self.random_banana = False self.require_aim = False self.go_forward = False #self.set_level_variables(self.training) # setup keyboard/joystick inputs self.setup_inputs() # Initialize more variables # These variables are set to their initial states in reset_variables, so # does not matter what they are set to here. # DO NOT SET VARIABLES HERE, GO TO RESET_VARIABLES!!! # variable used to notify when changing direction of new target self.new_dir = None # and variable to notify when changing levels self.change_level = False self.max_angle = None self.min_angle = None self.delay_start = False self.yay_reward = False self.reward_delay = False self.reward_on = True self.reward_count = 0 self.x_mag = 0 self.y_mag = 0 self.speed = self.initial_speed # factor to slow down movement of joystick and control acceleration # speed for going in the wrong direction, when same speed as initial speed, then no change self.forward_speed = self.initial_forward_speed self.wrong_speed = 0.005 self.slow_speed = self.wrong_speed # toggle for whether moving is allowed or not self.moving = True # toggle for making sure stays on banana for min time for 2.3 self.set_zone_time = False # keeps track of how long we have held self.hold_time = 0 self.check_zone = False # self.check_time = 0 # toggle for when trial begins self.start_trial = True # print self.avatar_h # print self.base.camera.getH() # print self.avatar_pos # print self.base.camera.getPos() # print self.base.camLens.getFov() # print self.base.camLens.getNear() # print self.base.camLens.getFar() # print self.base.camLens.getAspectRatio() self.base.camLens.setNear(avatar_radius/3.0) # print self.banana.getPos() # set variables to their actual starting values self.reset_variables() self.set_level_variables(self.training) # print 'set level' self.set_camera() # print 'set camera' # start stuff happening! self.start_task() def frame_loop(self, task): # print self.training # print 'loop' dt = task.time - task.last task.last = task.time # print('dt', dt) # delay_start means we just gave reward and need to set wait # until reward pump is done to do anything if self.delay_start: task.delay = task.time + self.reward_time # print('time now', task.time) # print('delay until', task.delay) self.delay_start = False # self.reward_delay = True return task.cont # set_zone_time means we have the crosshair over the banana, # and have to set how long to leave it there if self.set_zone_time: # print 'reset zone time' self.hold_time = task.time + self.hold_aim self.set_zone_time = False self.check_zone = True # reward delay is over, on to regularly scheduled program if task.time > task.delay: # print 'past delay' # check for reward # print('beeps so far', self.reward_count) # print self.yay_reward if self.yay_reward == 'partial': # print 'giving partial reward' self.give_reward() self.yay_reward = None self.go_forward = True # since none, don't need to return, won't give more reward, but # will go on to let move elif self.yay_reward and self.reward_count < self.num_beeps: # print 'gave reward' self.reward_count += 1 self.give_reward() return task.cont elif self.yay_reward and self.reward_count == self.num_beeps: # print 'gave final reward' # done giving reward, time to start over, maybe # hide the banana self.banana.stash() # change the color of the crosshair self.x_change_color(self.x_start_c) # before we can proceed, subject may need to let go of the joystick if self.must_release: # print 'checking for release' # print self.x_mag if abs(self.x_mag) > 0 or abs(self.y_mag) > 0: # print('let go!') return task.cont # and now we can start things over again # print('start over') self.restart_bananas() # check_time is used to see how long it takes subject # to get banana from time plotted # self.check_time = task.time return task.cont # check to see if we are moving if self.moving: # moving, forward first, only bother checking if possible to go forward if self.go_forward: # forward needs a little speed boost compared to turning if self.start_trial or self.y_mag == 0: self.forward_speed = self.initial_forward_speed self.start_trial = False else: # self.y_mag (how much you push the joystick) affects # acceleration as well as speed self.forward_speed += self.initial_forward_speed * abs(self.y_mag) position = self.base.camera.getPos() # print(position) # print('y_mag', self.y_mag) # print('speed', self.speed) # print('dt', dt) # print('change in position', self.y_mag * self.speed * dt) position[1] += self.y_mag * self.forward_speed * dt # if this puts us past center, stay at center if position[1] > 0: position[1] = 0 self.base.camera.setPos(position) # Now check for rotation. Don't need to check this if going forward if not self.go_forward: # print 'rotating' heading = self.base.camera.getH() delta_heading = self.get_new_heading(heading, dt) self.base.camera.setH(heading + delta_heading) # print('camera heading', self.base.camera.getH()) # check for collision: collide_banana = self.check_banana() # print('collide', collide_banana) # if we need to be stopping and leaving (holding) crosshair over banana, # make sure still in target zone. if self.check_zone: # print('check hold') # not sure if I will use a zone for going forward yet # The 'zone' is whenever the ray is colliding with the banana. # use zone for both left-right training and for forward training, # whenever self.require_aim is true. # with forward training, use to see if we went off course, and then # lined up the crosshair and banana again. # print collide_banana if collide_banana: # print('still in the zone') if task.time > self.hold_time: # print('hold aim', self.hold_aim) # print('ok, get reward') # print self.free_move # print('hold time', task.time > self.hold_time) # stop moving and get reward if self.free_move == 4: # partial reward for lining up banana in level 4.x # print 'partial reward' self.yay_reward = 'partial' self.check_zone = False elif self.yay_reward is not None: self.x_change_color(self.x_stop_c) self.moving = False self.yay_reward = True self.check_zone = False else: pass # print('keep holding') # print('time', task.time) # print('hold until', self.hold_time) else: # print('left zone, wait for another collision') self.x_change_color(self.x_start_c) # print('require aim', self.require_aim) if self.require_aim == 'slow': # print 'aim slow' self.check_zone = None else: # print "don't slow down" self.check_zone = False else: # not currently checking zone, so either collide_banana means reward immediately # or start timer to check if leaving zone # print('camera heading before collision', self.base.camera.getH()) if collide_banana: # print('time took: ', task.time - self.check_time) # print 'collision' # print 'change xhair color to red' self.x_change_color(self.x_stop_c) # if we require aim, we start timer when we have a collision, # but if self.go_forward, than we have already aimed. if self.require_aim and not self.go_forward: self.set_zone_time = True else: # print 'yes' # reward time! # stop moving self.moving = False # move to center if self.base.camera.getH != 0: pass # print 'moved camera' # self.base.camera.setH(0) self.yay_reward = True elif collide_banana is None: # partial reward for lining up banana in level 4.x # print 'partial reward' self.yay_reward = 'partial' # self.yay_reward = True # self.reward_count = self.num_beeps - 1 return task.cont def give_reward(self): # print('beep') if self.reward: self.reward.pumpOut() if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'reward' + '\n') self.delay_start = True def check_banana(self): # print 'check banana' collide_banana = False # print self.base.camera.getPos() # if we are doing only forward, or only side, only need to check for entries, # but if doing both movement, have to check for whichever we are currently # interested in. if self.free_move == 4: # why doesn't the camera show that we see the banana, ever? wrong camera? # print self.base.camNode.isInView(self.banana.getPos()) for i in range(self.collHandler.getNumEntries()): entry = self.collHandler.getEntry(i) # in_view = self.base.camNode.isInView(entry.getIntoNodePath().getPos()) # print in_view # print entry.getIntoNodePath().getPos() if entry.getFromNodePath() == self.sphere_node_path: # print 'ran into banana going forward' collide_banana = True self.moving = False elif entry.getFromNodePath() == self.ray_node_path: # print 'collide ray' # print self.yay_reward # if we are requiring aim, than use collide_banana = True, # since this will automatically get diverted before full reward if self.yay_reward is not None and not self.require_aim: # print 'lined up banana from side' collide_banana = None elif self.yay_reward is not None and self.require_aim: # print 'lined up banana from side, need to aim' collide_banana = True # print entry.getFromNodePath() elif self.collHandler.getNumEntries() > 0: # print 'collided' # the only object we can be running into is the banana, so there you go... collide_banana = True # print self.collHandler.getEntries() # print self.base.camera.getH() # print self.base.camera.getPos() # print self.banana.getPos() return collide_banana def restart_bananas(self): # print 'restarted' # print('training', self.training) # reset a couple of variables self.yay_reward = False self.reward_count = 0 # self.check_time = 0 # used to reset speed self.start_trial = True # print self.multiplier # check to see if we are switching the banana to the other side if self.new_dir is not None: self.multiplier = self.new_dir self.new_dir = None # for some versions, subject could still be holding joystick at this point. # (for example, was going to the right, but now is suppose to be going to the left, # but since we only detect when the joystick position has changed, and it has # not, may not realize that that we are now going what is considered a 'wrong' direction # so we are essentially re-checking the the joystick position, given the other updated # parameters). # send the current joystick position through the move method to correct that. # the original signal had its sign changed, so switch the sign here as well. # print 'move' self.move('x', -self.x_mag) #print('change direction', -self.x_mag) if self.change_level: # print 'actually change level now' self.set_level_variables(self.change_level) print('angle', self.base.camera.getH()) self.change_level = False # check to see if banana is on random if self.random_banana: # print 'random' # make side not entirely random. Don't want too many in a row on one side # for MP, because he is a bit of an idiot. # First check if we care about the next direction if self.side_bias and abs(self.last_multiplier) > 1: # if there have been two in a row in the same direction, pick the opposite # direction, otherwise choose randomly # print 'change, self.last_multiplier is zero' self.multiplier = - self.multiplier else: # print 'random' self.multiplier = random.choice([1, -1]) # print('next up', self.multiplier) # multiplier should never be zero when doing this comparison # last_multiplier is the only one that can be zero, and only # very briefly # if this gives you a negative 1, than we are switching sides, # if we don't care about side_bias, we don't look at last_multiplier, # and this doesn't matter if self.last_multiplier/self.multiplier != 1: # print 'reset' self.last_multiplier = 0 self.last_multiplier += self.multiplier # print('last currently', self.last_multiplier) self.avatar_h = random.choice(self.random_choices) # for some versions, subject could still be holding joystick at this point. # this means we x_mag is at a position that might no longer be # allowed, so we are going to send the current joystick position # through the move method to correct that. move switches the sign, so switch # the sign here as well. # print 'move' self.move('x', -self.x_mag) self.set_camera() if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'banana position, ' + str(self.multiplier * self.avatar_h) + '\n') # print('min time to reward:', sqrt(2 * self.avatar_h / 0.05 * 0.01)) # for training 4, switch from going forward to left/right if self.free_move == 4: self.go_forward = False # un-hide banana self.banana.unstash() # print 'avatar can move again, new trial starting' self.moving = True # print('yay', self.yay_reward) def start_task(self): self.frameTask = self.base.taskMgr.add(self.frame_loop, "frame_loop") self.frameTask.delay = -0.1 # want initial delay less than zero self.frameTask.last = 0 # task time of the last frame #print 'set task' if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'banana position, ' + str(self.multiplier * self.avatar_h) + '\n') def set_camera(self): self.base.camera.setH(self.multiplier * abs(self.avatar_h)) self.base.camera.setPos(self.avatar_pos) #print self.base.camera.getPos() #print self.banana.getPos() # print self.base.camera.getH() sys.stdout.write('current angle: ' + str(self.base.camera.getH()) + '\n') def x_change_color(self, color): # print self.crosshair.getColor() self.crosshair.setTextColor(color) # self.cross.setColor(Point4(1, 0, 0, 1)) def move(self, js_dir, js_input): # most restrictions on movement handled in frame_loop, # both due to levels and due to environment if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + str(js_dir) + ', ' + str(-js_input) + '\n') # print(js_dir, js_input) # Threshold. If too low, noise will create movement. if abs(js_input) < 0.1: js_input = 0 # we are moving the camera in the opposite direction of the joystick, # x and y inputs will both be inverted if js_dir == 'x' or js_dir == 'x_key': # print js_input # x direction is reversed self.x_mag = -js_input # print('x_mag', self.x_mag) # hack for Mr. Peepers... # barely touch joystick and goes super speedy. speed not dependent # on how hard he touches joystick (always 2) # if self.subject == 'MP' and js_input != 0: # # print 'yes' # # need it to be the same direction as negative of js_input # self.x_mag = js_input/abs(js_input) * -2 # new hack for Mr. Peepers... # joystick pressure has more of an effect than acceleration # (0 to 2 instead of 0 to 1, trying to get him to push harder on # on the joystick) if self.subject == 'MP' and js_input != 0: self.x_mag = js_input * -2 # print('x', self.x_mag) else: # y direction is also reversed, # not allowed to go backward, ever if js_input < 0: self.y_mag = -js_input else: self.y_mag = 0 def restrict_forward(self): """ :return: As self.forward_limit increases, we require the subject to 'go straighter', iow, the subject should not be pushing the joystick to the side, only forward When forward_limit hits one, can only go forward (any side movement means don't go anywhere) """ self.go_forward = True if self.x_mag > self.forward_limit: self.go_forward = False def get_new_heading(self, heading, dt): # print 'get new heading' # set new turning speed. # if new trial or subject stopped moving, reverts to initial speed if self.start_trial or self.x_mag == 0: self.speed = self.initial_speed self.slow_speed = self.wrong_speed self.start_trial = False else: # the larger the push on the joystick, # the more the speed increases. self.slow_speed += self.wrong_speed * abs(self.x_mag) # self.speed += 0.05 * abs(self.x_mag) self.speed += self.initial_speed * abs(self.x_mag) # determine if moving towards the banana to_banana = False # first make sure we don't divide by zero, if self.x_mag != 0 and heading != 0: if self.x_mag/abs(self.x_mag) * heading/abs(heading) < 0: to_banana = True # unless there is a reason to stop movement, this is the heading delta_heading = self.x_mag * self.speed * dt # if not allowed to go past banana, stop directly at center # if self.free_move == 1: # if heading + delta_heading switches it from + to - # if heading away from banana, many opportunities to slow or # stop movement... if not to_banana: if abs(heading) >= self.screen_edge: # block off edge of screen # print 'hit a wall' delta_heading = 0 elif self.check_zone is None: # if check_zone is None, than went past banana target zone, # and we want to go slow # print 'went past zone' delta_heading = self.x_mag * self.slow_speed * dt # delta_heading = self.x_mag * self.initial_speed * dt elif self.free_move == 1: # print 'free move is 1' # self.free_move is one, only allowed to go towards banana delta_heading = 0 elif self.free_move == 2: # print 'free move is 2' # self.free_move is two, both directions allowed, but go # in direction away from banana more slowly. # print 'slow' # self.x_mag /= self.wrong_speed delta_heading = self.x_mag * self.slow_speed * dt # print self.slow_speed # delta_heading = self.x_mag * self.speed * dt # print('delta heading', delta_heading) return delta_heading def inc_angle(self): # print('old pos', self.avatar_h) # self.avatar_h[0] = self.avatar_h[0] * 1.5 # self.avatar_h *= 1.5 self.avatar_h *= 1.1 # print('would be', self.avatar_h) if abs(self.avatar_h) > self.max_angle: self.avatar_h = self.multiplier * self.max_angle # y is always going to be positive # self.avatar_h[1] = sqrt(25 - self.avatar_h[0] ** 2) sys.stdout.write('increase angle, new angle: ' + str(self.avatar_h) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, increase angle ' + str(self.multiplier * self.avatar_h) + '\n') # print('min time to reward:', sqrt(2 * self.avatar_h / 0.05 * 0.01)) def dec_angle(self): # print('old pos', self.avatar_h) # self.avatar_h /= 1.5 self.avatar_h /= 1.1 if abs(self.avatar_h) < self.min_angle: self.avatar_h = self.multiplier * self.min_angle # self.banana_pos[0] = x_sign * (abs(self.banana_pos[0]) - 1) # self.banana_pos[1] = sqrt(25 - self.banana_pos[0] ** 2) sys.stdout.write('decrease angle, new angle: ' + str(self.avatar_h) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, decrease angle ' + str(self.multiplier * self.avatar_h) + '\n') # print('min time to reward:', sqrt(2 * self.avatar_h / 0.05 * 0.01)) def inc_reward(self): self.num_beeps += 1 sys.stdout.write('increase reward, new reward: ' + str(self.num_beeps) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, increase reward ' + str(self.num_beeps) + '\n') def dec_reward(self): self.num_beeps -= 1 sys.stdout.write('decrease reward, new reward: ' + str(self.num_beeps) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, decrease reward ' + str(self.num_beeps) + '\n') def inc_level(self): # increase the level, if we are jumping multiple levels, # at once, self.training will not have increased yet, so # check to see what self.change_level is first (don't want # to change levels in the middle of a trial) training = self.training if self.change_level: training = self.change_level # print('old level', training) # get current position in sequence: seq_num = self.get_seq_num(training) if training == self.levels_available[-1][-1]: sys.stdout.write('already at most difficult level \n') self.change_level = training elif training == self.levels_available[seq_num][-1]: sys.stdout.write('switching to new sequence \n') self.change_level = self.levels_available[seq_num + 1][0] else: self.change_level = round(training + 0.1, 2) sys.stdout.write('increase level, new level: ' + str(self.change_level) + '\n') # print('new level', self.change_level) if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, increase level ' + str(self.change_level) + '\n') def dec_level(self): # decrease the level, if we are jumping multiple levels, # at once, self.training will not have increased yet, so # check to see what self.change_level is first (don't want # to change levels in the middle of a trial) training = self.training if self.change_level: training = self.change_level # print('old level', training) # get current position in sequence: seq_num = self.get_seq_num(training) if training == self.levels_available[0][0]: sys.stdout.write('already at easiest level \n') self.change_level = training elif training == self.levels_available[seq_num][0]: sys.stdout.write('switching to new sequence \n') self.change_level = self.levels_available[seq_num - 1][-1] else: self.change_level = round(training - 0.1, 2) sys.stdout.write('increase level, new level: ' + str(self.change_level) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, decrease level ' + str(self.change_level) + '\n') def get_seq_num(self, training): seq_num = 0 for seq_num, sequence in enumerate(self.levels_available): if sequence.count(training) > 0: if sequence.index(training) is not None: break return seq_num def inc_wrong_speed(self): if self.wrong_speed >= self.initial_speed: self.wrong_speed = self.initial_speed sys.stdout.write('now same speed as towards the banana \n') else: self.wrong_speed += 0.01 sys.stdout.write('increase speed in wrong direction, new: ' + str(self.wrong_speed) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, increase wrong speed ' + str(self.wrong_speed) + '\n') def dec_wrong_speed(self): self.wrong_speed -= 0.01 sys.stdout.write('decrease speed in wrong direction, new: ' + str(self.wrong_speed) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, decrease wrong speed ' + str(self.wrong_speed) + '\n') def inc_random(self): if self.current_choice == len(self.all_random_selections) - 1: sys.stdout.write('already at max \n') else: # current is the current length, which conveniently # enough is the next number to use, because of zero indexing self.current_choice += 1 self.random_choices = self.all_random_selections[self.current_choice] sys.stdout.write('increase selection of random bananas, new: ' + str(self.random_choices) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, increase random selection ' + str(self.random_choices) + '\n') def dec_random(self): if self.current_choice == 0: sys.stdout.write('already at min \n') else: # current is the current length, so we need to subtract # by two, because of zero indexing self.current_choice -= 1 self.random_choices = self.all_random_selections[self.current_choice] sys.stdout.write('decrease selection of random bananas, new: ' + str(self.random_choices) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, decrease random selection ' + str(self.random_choices) + '\n') def inc_forward_speed(self): self.initial_forward_speed += 0.01 sys.stdout.write('increase forward speed, new: ' + str(self.initial_forward_speed) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, increase forward speed ' + str(self.initial_forward_speed) + '\n') def dec_forward_speed(self): self.initial_forward_speed -= 0.01 sys.stdout.write('decrease forward speed, new: ' + str(self.initial_forward_speed) + '\n') if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, decrease forward speed ' + str(self.initial_forward_speed) + '\n') def change_left(self): self.new_dir = -1 sys.stdout.write('new dir: left \n') print('new direction', self.new_dir) if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, new dir left' + '\n') def change_right(self): self.new_dir = 1 sys.stdout.write('new dir: right \n') print('new direction', self.new_dir) if not unittest: self.data_file.write(str(self.frameTask.time) + ', ' + 'keypress, new dir right' + '\n') def extra_reward(self): sys.stdout.write('beep \n') if self.reward: self.reward.pumpOut() def reset_variables(self): # this is only called once, from init self.base.taskMgr.remove("frame_loop") # set/reset to the original state of variables # self.max_angle = 26 self.max_angle = 40 self.min_angle = 1.5 self.delay_start = False self.yay_reward = False self.reward_delay = False self.reward_on = True self.reward_count = 0 self.x_mag = 0 self.y_mag = 0 self.speed = self.initial_speed # factor to change speed of joystick and control acceleration self.forward_speed = self.initial_forward_speed # speed for going in the wrong direction, when same speed as initial speed, then no change self.wrong_speed = 0.005 self.slow_speed = self.wrong_speed # toggle for whether moving is allowed or not self.moving = True # toggle for making sure stays on banana for min time for 2.3 self.set_zone_time = False # amount need to hold crosshair on banana to get reward (2.3) # must be more than zero. At 1.5 distance, must be greater than # 0.5 to require stopping self.hold_aim = 0.6 if unittest: self.hold_aim = 0.1 # keeps track of how long we have held self.hold_time = 0 # check_zone is a toggle that happens when lined up crosshair with banana # if check_zone is False, not currently in the zone, if true checking to # see if we have left the zone. if none, left the zone and in mode where # slows down after leaving the zone. self.check_zone = False # self.check_time = 0 # speed for going in the wrong direction, 1 is no change, higher numbers slower self.wrong_speed = 0.005 self.slow_speed = self.wrong_speed # toggle for when trial begins self.start_trial = True def set_level_variables(self, training): #print 'really setting level variables' # default is lowest training level self.training = training self.free_move = 1 self.must_release = False self.random_banana = False self.require_aim = False self.go_forward = False self.banana_coll_node.setIntoCollideMask(self.mask_list[0]) self.avatar_h = self.config_avatar_h self.avatar_pos = Point3(0, -1.5, 1) self.banana_node_path.setScale(0.1) if training > self.levels_available[0][0]: # print '2.1' self.must_release = True if training > self.levels_available[0][1]: # print '2.2' self.random_banana = True if training > self.levels_available[0][2]: # print '2.3' self.free_move = 2 if training > self.levels_available[0][3]: # print '2.4' self.free_move = 3 if training > self.levels_available[0][4]: # print '2.5' self.require_aim = 'slow' if training > self.levels_available[0][5]: # print '2.6' self.require_aim = True # print self.levels_available[0][-1] # level 3 training if training > self.levels_available[0][-1]: # print '3.0' self.avatar_pos = Point3(0.01, self.config_avatar_d, 1) self.banana_coll_node.setIntoCollideMask(self.mask_list[1]) # defaults for level 3 training self.go_forward = True self.free_move = 0 self.must_release = False self.random_banana = False self.require_aim = True if training > self.levels_available[1][0]: # print '3.1' self.must_release = True # level 4 training if training > self.levels_available[1][-1]: #self.banana_node_path.setScale(0.2) # print '4.0' self.banana_coll_node.setIntoCollideMask(self.mask_list[2]) self.go_forward = False self.free_move = 4 self.must_release = False self.random_banana = False self.require_aim = False if training > self.levels_available[2][0]: # print '4.1' self.random_banana = True if training > self.levels_available[2][1]: # print '4.2' self.require_aim = 'slow' if training > self.levels_available[2][2]: # print '4.3' self.require_aim = True #print('what sequence?', self.get_seq_num(training)) # In case random_bananas changed: if self.random_banana: self.random_choices = self.all_random_selections[self.current_choice] self.avatar_h = random.choice(self.random_choices) sys.stdout.write('current angles available ' + str(self.random_choices) + '\n') elif self.get_seq_num(training) == 1: # really should have started out with training zero, # then numbering would be better... # print 'sequence 3?' self.avatar_h = 0 else: self.avatar_h = self.config_avatar_h # print self.banana.getH() # print self.avatar_pos # print self.avatar_h sys.stdout.write('forward: ' + str(self.go_forward) + '\n') sys.stdout.write('free move: ' + str(self.free_move) + '\n') sys.stdout.write('random: ' + str(self.random_banana) + '\n') sys.stdout.write('require aim: ' + str(self.require_aim) + '\n') def load_fruit(self, fruit): if fruit == 'banana': self.banana = self.base.loader.loadModel("models/bananas/banana.bam") self.banana.setH(280) # self.banana.setH(0) self.banana.setScale(0.5) # banana always in the same position, just move avatar. self.banana.setPos(Point3(0, 0, 1)) self.banana_node_path = self.banana.find('**/+CollisionNode') self.banana.reparentTo(self.base.render) elif fruit == 'cherry': # or cherry as banana? self.banana = self.base.render.attachNewNode('root') # banana center is off, re-center with new node new_node_path = self.base.loader.loadModel("models/fruit/cherries_no_cn.egg") new_node_path.reparentTo(self.banana) new_node_path.setPos(0, 0, 0) #new_node_path.setScale(0.08) self.banana.setScale(0.08) # cherry # move the center of the cherries self.banana.setPos(Point3(0.08, 0, 1)) # can't get built in cherry collision node to work properly... cs = CollisionSphere(-10, 0, 0, 11) self.banana_node_path = new_node_path.attachNewNode(CollisionNode('c_node')) self.banana_node_path.node().addSolid(cs) # usually 0.1 for banana # self.banana_node_path = self.banana.find('**/+CollisionNode') # self.banana_node_path.setScale(1) self.banana_mask = BitMask32(0x1) # banana intoCollideMask will change depending on which level we # are training on. self.banana_coll_node = self.banana_node_path.node() self.banana_coll_node.setIntoCollideMask(self.mask_list[0]) def open_data_file(self, config): # open file for recording eye data data_dir = 'data/' + config['subject'] if not os.path.exists(data_dir): os.makedirs(data_dir) self.data_file_name = data_dir + '/' + config['subject'] + '_TR_' + \ datetime.datetime.now().strftime("%y_%m_%d_%H_%M") sys.stdout.write('data file: ' + str(self.data_file_name) + '\n') # open file for recording eye positions self.data_file = open(self.data_file_name, 'w') self.data_file.write('timestamp, joystick input, for subject: ' + config['subject'] + '\n') # Closing methods def close_files(self): self.data_file.close() def close(self): if not unittest: self.close_files() sys.exit() def setup_inputs(self): self.accept('x_axis', self.move, ['x']) self.accept('y_axis', self.move, ['y']) self.accept('arrow_right', self.move, ['x_key', 0.5]) self.accept('arrow_left', self.move, ['x_key', -0.5]) self.accept('arrow_right-up', self.move, ['x_key', 0]) self.accept('arrow_left-up', self.move, ['x_key', 0]) self.accept('arrow_right-repeat', self.move, ['x_key', 0.5]) self.accept('arrow_left-repeat', self.move, ['x_key', -0.5]) self.accept('arrow_up', self.move, ['y_key', -0.5]) self.accept('arrow_up-up', self.move, ['y_key', 0]) self.accept('arrow_up-repeat', self.move, ['y_key', -0.5]) self.accept('q', self.close) self.accept('w', self.inc_reward) self.accept('s', self.dec_reward) self.accept('e', self.inc_angle) self.accept('d', self.dec_angle) self.accept('t', self.inc_level) self.accept('g', self.dec_level) self.accept('y', self.inc_wrong_speed) self.accept('h', self.dec_wrong_speed) self.accept('u', self.inc_random) self.accept('j', self.dec_random) self.accept('i', self.inc_forward_speed) self.accept('k', self.dec_forward_speed) self.accept('r', self.change_right) self.accept('l', self.change_left) self.accept('space', self.extra_reward) @staticmethod def make_coll_node_path(node_path, solid): # Creates a collision node and attaches the collision solid to the # supplied NodePath. Returns the nodepath of the collision node. # Creates a collision node named after the name of the NodePath. coll_node = CollisionNode("%s c_node" % node_path.getName()) coll_node.addSolid(solid) collision_node_path = node_path.attachNewNode(coll_node) # Show the collision node, which makes the solids show up. # actually, it appears to do nothing... # collision_node_path.show() return collision_node_path
class p3dApp(ShowBase): def __init__(self): ShowBase.__init__(self); # setup the environment or model self.model = \ self.loader.loadModel("/Developer/Panda3D/models/box.egg.pz"); self.model.reparentTo(self.render); self.model.setTag('Model', '1'); self.model.setScale(1.5, 1.5, 1.5); # setup camera self.camera.setPos(5,5,5) self.camera.lookAt(0,0,0) # Disable mouse control self.disableMouse(); # Handle mouse events. self.accept('mouse1', self.mouse_down); # convert image from opencv to panda3d texture # self.taskMgr.add(self.read_image_cv, "cvImageTask"); # Setup collision handler self.handler = CollisionHandlerQueue() self.traverser = CollisionTraverser('ColTraverser') self.traverser.traverse(self.model) self.ray = CollisionRay() pickerNode = CollisionNode('MouseRay') pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) pickerNP = self.camera.attachNewNode(pickerNode) pickerNode.addSolid(self.ray) self.traverser.addCollider(pickerNP, self.handler) self.load_shader(); self.first_frame_loaded = False; def read_image_cv(self): """ Pulls the next frame from the opencv part, and converts to a panda3d texture and display it on the screen. """ cvim = self.cvapp.pull_frame() w = cvim.shape[1]; h = cvim.shape[0]; cvim = cv2.flip(cvim, 0); self.im = Texture("cvIm"); self.im.setCompression(Texture.CMOff); self.im.setup2dTexture(w, h, Texture.TUnsignedByte, Texture.FLuminance); self.im.setRamImage(cvim); self.screen_im = OnscreenImage(parent=self.render2d, image=self.im, scale=(1, 1, 1), pos=(0, 0, 0)); self.cam2d.node().getDisplayRegion(0).setSort(-20); def load_shader(self): """ The function loads the vertex and fragment shader. It provides an example of sending the model-view-projection matrix to the shader program when it's calculated. """ self.shader = Shader.load(Shader.SL_GLSL, "vertex.glsl", "fragment.glsl"); self.model.set_shader(self.shader) self.model.set_shader_input("my_ModelViewProjectionMatrix", LMatrix4f()) def mouse_down(self): """ This function is called as a result of a mouse click. It gets the vertex that was clicked by the mouse. It sends the mouse position and the vertex position to the cv app. """ if (self.first_frame_loaded == False): self.first_frame_loaded = True self.read_image_cv() return; xPos = self.mouseWatcherNode.getMouseX() yPos = self.mouseWatcherNode.getMouseY() self.ray.setFromLens(self.camNode, xPos, yPos) self.traverser.traverse(self.model) self.handler.sortEntries() if (self.handler.getNumEntries() > 0): entry = self.handler.getEntry(0) # CollisionEntry vpos = entry.getSurfacePoint(self.model) res = self.cvapp.mouse_clicked(LPoint3f(xPos, yPos), vpos) if (res == 1): self.read_image_cv() def set_cv_app(self, cvapp): self.cvapp = cvapp;
class GameApp: def __init__(self): self.gameEventHandler = GameEventHandler(self) self.camLimits = ((-5, 5), (-6.5, 5), (1, 10)) self.gameReady = False self.hovered = None self.clicked = None self.modelToFigure = {} self.modelToField = {} self.modelToSeaField = {} self.modelToBuildingField = {} self.modelToBuilding = {} # self.highlightableObjects = render.attachNewNode('highlightables') self.setupColisionForHighlight() self.songMenu = None self.buildMenu = None def setupColisionForHighlight(self): # Since we are using collision detection to do picking, we set it up like # any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() # Make a traverser self.pq = CollisionHandlerQueue() # Make a handler # Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') # Attach that node to the camera since the ray will need to be positioned # relative to it self.pickerNP = self.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 # Add it to the collision node self.pickerNode.addSolid(self.pickerRay) # Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) def getCameraCoords(self): return self.camera.getPos() def setCameraCoords(self, x, y, z): self.camera.setPos(x, y, z) def getMouseCoords(self): if self.mouseWatcherNode.hasMouse(): return self.mouseWatcherNode.getMouse() return None def drawIsland(self, island, suppressRot=False): island.model.setPos(island.pos[0], island.pos[1], 0.001) island.model.setScale(0.05, 0.05, 0.05) island.model.reparentTo(self.render) for f in range(0, 6): circle = self.loader.loadModel('models/circle') pos = (island.fields[f].x, island.fields[f].y, 0.4) circle.setPos(pos) circle.setScale(0.4) circle.reparentTo(island.model) circle.setTag('clickable', 'true') cs = CollisionSphere(0, 0, 0, 1) cnodePath = circle.attachNewNode(CollisionNode('cnode')) cnodePath.node().addSolid(cs) island.fields[f].model = circle self.modelToField[circle.getKey()] = island.fields[f] for i in range(0, 3): buildingField = island.buildingFields[i] circle = self.loader.loadModel('models/circle') pos = (buildingField.x, buildingField.y, 0.1) circle.setPos(pos) circle.setScale(0.6) circle.reparentTo(island.model) circle.setTag('clickable', 'true') cs = CollisionSphere(0, 0, 0, 1) cnodePath = circle.attachNewNode(CollisionNode('cnode')) cnodePath.node().addSolid(cs) buildingField.model = circle self.modelToBuildingField[circle.getKey()] = buildingField # put the bay field circle = self.loader.loadModel('models/circle') pos = (island.bay.x, island.bay.y, 0.2) circle.setPos(pos) circle.setScale(0.6) circle.reparentTo(island.model) circle.setTag('clickable', 'true') cs = CollisionSphere(0, 0, 0, 1) cnodePath = circle.attachNewNode(CollisionNode('cnode')) cnodePath.node().addSolid(cs) island.bay.model = circle self.modelToSeaField[circle.getKey()] = island.bay degree = angle((0, 1), island.pos) * 180 / math.pi if island.pos[0] > 0: degree *= -1 if not suppressRot: island.model.setHpr(degree, 0, 0) def drawFigures(self): for player in self.game.players: for figure in player.figures: if hasattr(figure, 'model'): continue if type(figure) == Ship: field = figure.field figure.model = self.loader.loadModel('models/ship') figure.model.reparentTo(field.model) cs = CollisionSphere(1.5, 0, 1, 1.3) cnodePath = figure.model.attachNewNode( CollisionNode('cnode')) cnodePath.node().addSolid(cs) # cnodePath.show() cs = CollisionSphere(0, 0, 1.4, 1.3) cnodePath = figure.model.attachNewNode( CollisionNode('cnode')) cnodePath.node().addSolid(cs) # cnodePath.show() cs = CollisionSphere(-1.8, 0, 1, 1) cnodePath = figure.model.attachNewNode( CollisionNode('cnode')) cnodePath.node().addSolid(cs) # cnodePath.show() figure.model.setScale(1.4) figure.model.setHpr(90, 0, 0) # figure.model.setTag('highlightable', 'true') figure.model.setTag('clickable', 'true') self.modelToFigure[figure.model.getKey()] = figure else: field = figure.field figure.model = self.loader.loadModel('models/warrior100') figure.model.reparentTo(field.model) cs = CollisionSphere(0, -.35, 7, 1) cnodePath = figure.model.attachNewNode( CollisionNode('cnode')) cnodePath.node().addSolid(cs) figure.model.setScale(0.35) figure.model.setTag('highlightable', 'true') figure.model.setTag('clickable', 'true') self.modelToFigure[figure.model.getKey()] = figure col = 256 * int(player.color) # set figure title title = TextNode(str(figure.model.getKey()) + '_title') title.setText(type(figure).__name__) title.setCardColor(col, col, col, 1) title.setCardAsMargin(0.1, 0.1, 0.1, 0.1) title.setCardDecal(True) titleNode = self.render.attachNewNode(title) titleNode.reparentTo(figure.model) titleNode.setScale(3) titleNode.setPos(0, 3, 10) if type(figure) == Ship: titleNode.setScale(1.5) titleNode.setPos(-1.5, 0, 3) titleNode.setBillboardPointEye() def drawSeaways(self): for field in self.game.board.seawayFields: circle = self.loader.loadModel('models/circle') pos = (field.x, field.y, 0) circle.setPos(pos) circle.setScale(0.04) circle.setHpr(-90, 0, 0) circle.reparentTo(self.render) circle.setTag('clickable', 'true') cs = CollisionSphere(0, 0, 0, 1) cnodePath = circle.attachNewNode(CollisionNode('cnode')) cnodePath.node().addSolid(cs) field.model = circle self.modelToSeaField[circle.getKey()] = field def drawBuilding(self, building, field): model = self.loader.loadModel('models/house') # model.setScale(0.05) model.reparentTo(field.model) building.model = model self.modelToBuilding[model.getKey()] = building player = self.game.currentPlayer() model.setTag('clickable', 'true') cs = CollisionSphere(0, 0, 0, 2) cnodePath = model.attachNewNode(CollisionNode('cnode')) cnodePath.node().addSolid(cs) # cnodePath.show() col = 256 * int(player.color) # set building title title = TextNode(str(building.model.getKey()) + '_title') title.setText(building.building) title.setCardColor(col, col, col, 1) title.setCardAsMargin(0.1, 0.1, 0.1, 0.1) title.setCardDecal(True) titleNode = self.render.attachNewNode(title) titleNode.reparentTo(building.model) titleNode.setScale(1.5) titleNode.setPos(0, 0, 3) titleNode.setBillboardPointEye() def drawGame(self, game): if not self.gameReady: self.game = game # menu = OnscreenImage(image = 'textures/menu.png', pos = (1.53, 0, 0), scale=(0.35, 1, 1)) # menu.setTransparency(TransparencyAttrib.MAlpha) # setup the background of the board self.environ = self.loader.loadModel('models/plane') sea = self.loader.loadTexture('textures/sea.png') self.environ.setTexture(sea) self.environ.setPos(0, 1, 0) self.environ.setScale(1.1) sea.setWrapU(Texture.WM_repeat) sea.setWrapV(Texture.WM_repeat) self.environ.reparentTo(self.render) # setup camera self.camera.setPos(0, 0, 10) self.camera.setHpr(0, -70, 0) self.camLens.setNear(0.85) # setup lighting plight = PointLight('plight') plight.setColor(VBase4(1, 1, 1, 3)) plnp = self.render.attachNewNode(plight) plnp.setPos(10, 0, 10) self.render.setLight(plnp) ambientLight = AmbientLight('ambientLight') ambientLight.setColor(Vec4(0.25, 0.25, 0.25, .3)) ambientLightNP = self.render.attachNewNode(ambientLight) self.render.setLight(ambientLightNP) # place islands first = True for island in game.board.islands: island.drawable = True island.model = self.loader.loadModel('models/island2_104') self.drawIsland(island, first) first = False self.drawFigures() self.drawSeaways() self.turn = OnscreenText(text='Black\'s turn.', pos=(0.06, -0.1), align=TextNode.ALeft, parent=base.a2dTopLeft, scale=0.06) self.resources = OnscreenText(text='Resources: ', pos=(0.08, -0.2), align=TextNode.ALeft, parent=base.a2dTopLeft, scale=0.06) self.gameReady = True player = 'Black' if game.turn == 1: player = 'White' self.turn.setText(player + '\'s turn.') resourcesText = 'Resources: ' + \ str(self.game.currentPlayer().resources) self.resources.setText(resourcesText) if self.game.loosers != None: message = OnscreenText(text='End of the game', align=TextNode.ACenter, pos=(0, 0), scale=0.1) if self.game.loosers == 'black': message.setText('White wins!') elif self.game.loosers == 'white': message.setText('Black wins!') else: message.setText('Nobody wins!') def destroyGame(self): children = self.render.getChildren() for child in children: child.removeNode() def cameraSpeed(self, height, speedRange): # Figure out how 'wide' each range is leftSpan = self.camLimits[2][1] - self.camLimits[2][0] rightSpan = speedRange[1] - speedRange[0] # Convert the left range into a 0-1 range (float) valueScaled = float(height - self.camLimits[2][0]) / float(leftSpan) # Convert the 0-1 range into a value in the right range. return speedRange[0] + (valueScaled * rightSpan) def moveCamera(self): mousePos = self.getMouseCoords() if mousePos == None: return x, y = mousePos camX, camY, camZ = self.getCameraCoords() transformX, transformY = 0, 0 speed = self.cameraSpeed(camZ, (0.01, 0.2)) if x < -0.7 and y < -0.7: transformX -= speed transformY -= speed elif x > 0.7 and y < -0.7: transformX += speed transformY -= speed elif x < -0.7 and y > 0.7: transformX -= speed transformY += speed elif x > 0.7 and y > 0.7: transformX += speed transformY += speed else: if x < -0.7: transformX -= speed elif x > 0.7: transformX += speed if y < -0.7: transformY -= speed elif y > 0.7: transformY += speed newX = camX + transformX newY = camY + transformY if newX < self.camLimits[0][0] or newX > self.camLimits[0][1]: newX = camX if newY < self.camLimits[1][0] or newY > self.camLimits[1][1]: newY = camY self.setCameraCoords(newX, newY, camZ) def highlight(self): if self.mouseWatcherNode.hasMouse(): mPos = self.mouseWatcherNode.getMouse() # Set the position of the ray based on the mouse position self.pickerRay.setFromLens(self.camNode, mPos.getX(), mPos.getY()) self.picker.traverse(self.render) if self.pq.getNumEntries() > 0: # This is so we get the closest object. self.pq.sortEntries() pickedObj = self.pq.getEntry(0).getIntoNodePath() # pick the model and not the cnode pickedObj = pickedObj.findNetTag('clickable') if not pickedObj.isEmpty(): return pickedObj @staticmethod def boardingTransformations(figure, pos): figure.model.setScale(0.2) figure.model.setPos(1 + pos, 0, 1) @staticmethod def unboardingTransformations(figure): figure.model.setScale(0.35) figure.model.setPos(0, 0, 0) def drawSongsMenu(self, songs, field): if self.songMenu: return self.songMenu = [(OnscreenText(text='Choose song:', pos=(-0.7, -0.1), align=TextNode.ALeft, parent=base.a2dTopRight, scale=0.06), field)] i = 1 for song in songs: item = OnscreenText(text=str(i) + ') Song of ' + song, pos=(-0.7, -0.1 - i * 0.1), align=TextNode.ALeft, parent=base.a2dTopRight, scale=0.06) i += 1 self.songMenu.append((item, song)) def destroySongMenu(self): if self.songMenu: for item in self.songMenu: item[0].destroy() self.songMenu = None def drawBuildMenu(self, buildings, field): self.buildMenu = [(OnscreenText(text='Choose building:', pos=(-0.7, -0.1), align=TextNode.ALeft, parent=base.a2dTopRight, scale=0.06), field)] i = 1 for building in buildings: price = Building.buildingPrice(building) text = '{0}) {1} ({2})'.format(str(i), building, price) item = OnscreenText(text=text, pos=(-0.7, -0.1 - i * 0.1), align=TextNode.ALeft, parent=base.a2dTopRight, scale=0.06) i += 1 self.buildMenu.append((item, building)) def destroyBuildMenu(self): if self.buildMenu: for item in self.buildMenu: item[0].destroy() self.buildMenu = None def clickFigure(self, figure): print('figure') if type(figure) == Ship: ship = figure figure = self.clicked if isinstance(figure, Figure) and type(figure) != Ship: if figure.hasMoved: self.clicked = ship return if (figure.field.island == ship.field.island and figure.player == ship.player and None in ship.fields): figure.field.put(None) pos = 0 if ship.fields[0] == None: ship.fields[0] = figure else: ship.fields[1] = figure pos = 1 figure.field = ship figure.model.reparentTo(ship.model) self.boardingTransformations(figure, pos) figure.hasMoved = True if ship.player == self.game.currentPlayer(): self.clicked = ship else: if figure.player == self.game.currentPlayer(): self.clicked = figure def initiateBattle(self, blackTroops, whiteTroops): self.blackTroops = blackTroops self.whiteTroops = whiteTroops battle = self.game.newBattle() self.push(battle) self.gameEventHandler.ignoreAll() def clickField(self, field): print(self.clicked) if type(self.clicked) == Ship: return if self.clicked and isinstance(self.clicked, Figure): figure = self.clicked board = self.game.board if figure.hasMoved: return if type(figure.field) == Ship: if field in board.possibleMoves(figure.field): figure.field.removeFigure(figure) player = self.game.currentPlayer() battle = field.figure != None and field.figure.player != player whiteTroops = field.figure field.put(figure) figure.model.reparentTo(field.model) self.unboardingTransformations(figure) figure.hasMoved = True self.initiateBattle(figure, whiteTroops) if field in board.possibleMoves(self.clicked): initiateBattle = field.figure != None whiteTroops = field.figure figure.field.put(None) field.put(figure) figure.model.reparentTo(field.model) figure.hasMoved = True if initiateBattle: self.initiateBattle(figure, whiteTroops) if isinstance(self.clicked, Building): building = self.clicked player = self.game.currentPlayer() if not field.figure or field.figure.player != player: if field.island != building.field.island: return figure = None battle = field.figure != None and field.figure.player != player whiteTroops = field.figure if building.building == 'House': figure = self.game.giveBirthToPeasant(field) elif building.building == 'Barracks': figure = self.game.giveBirthToWarrior(field) if figure == None: return if figure: self.drawFigures() if battle: self.initiateBattle(figure, whiteTroops) else: print('Not enough resources!') def clickSeaField(self, field): if type(self.clicked) == Ship: figure = self.clicked if figure.hasMoved: return if field.figure != None: return if field in figure.field.linked: figure.field.put(None) field.put(figure) figure.model.reparentTo(field.model) figure.hasMoved = True if type(self.clicked) == Building: player = self.game.currentPlayer() building = self.clicked if building.building == 'Harbor': if building.field.island.bay != field: return player = self.game.currentPlayer() if not field.figure or field.figure.player != player: ship = self.game.buildShip(field) if ship: self.drawFigures() else: print('Not enough resources') def clickBuildingField(self, field): print("Gonna build, huh?") player = self.game.currentPlayer() print(self.game.possibleBuildings(field.island)) self.drawSongsMenu(self.game.possibleSongs(field.island), field) def handle(self, event, *args): print(event) if type(self.current()) != Game: return if event == 'wheel_up': x, y, z = self.getCameraCoords() if z > self.camLimits[2][0]: self.setCameraCoords(x, y, z - 1) elif event == 'wheel_down': x, y, z = self.getCameraCoords() if z < self.camLimits[2][1]: self.setCameraCoords(x, y, z + 1) elif event == 'enter': if self.game.loosers != None: self.pop() self.game.changeTurn() elif event == 'left_click': obj = self.highlight() if obj != None: key = obj.getKey() # if it's a figure if key in self.modelToFigure: figure = self.modelToFigure[key] self.clickFigure(figure) # if it's a figure field if key in self.modelToField: field = self.modelToField[key] self.clickField(field) # if it's a building field if key in self.modelToBuildingField: field = self.modelToBuildingField[key] self.clickBuildingField(field) # if it's a sea field if key in self.modelToSeaField: field = self.modelToSeaField[key] self.clickSeaField(field) # if it's a building if key in self.modelToBuilding: self.clicked = self.modelToBuilding[key] else: self.clicked = None if self.songMenu != None: if obj == None or obj.getKey() not in self.modelToBuildingField: self.destroySongMenu() elif event in [str(i) for i in range(1, 10)]: if self.songMenu: if self.songMenu[0][1] != self.game.board.islands[0]: song = self.songMenu[int(event)][1] buildings = self.game.buildings[song] self.drawBuildMenu(buildings, self.songMenu[0][1]) else: print('CHANGE OBJECTIVES!') self.destroySongMenu() return if self.buildMenu: building = self.buildMenu[int(event)][1] field = self.buildMenu[0][1] building = self.game.build(building, field) if building: self.drawBuilding(building, field) else: print('Not enough resources or field is taken!!>@') self.destroyBuildMenu() def hoverFigure(self, hovered): if self.hovered != None: reverseFactor = self.hovered.getScale()[0] reverseFactor *= REVERSE_HIGHLIGHT_SCALE self.hovered.setScale(reverseFactor) self.hovered = None if hovered != None: figure = self.modelToFigure[hovered.getKey()] if figure.player.color != str(self.current().turn): return self.hovered = hovered factor = HIGHLIGHT_SCALE * hovered.getScale()[0] hovered.setScale(factor)
class Picker(Viewer): """ View and click objects in a scene.""" def __init__(self): # Parent init. super(Picker, self).__init__() self.disableMouse() # Picker stuff. self.contact_margin = Vec3(0.01, 0.01, 0.01) self.parser = None self.marked = None self.attached_pairs = set() self.contacts = None self.contact_points = None self.contact_bottoms = None self.compound_components = [] self.compound_objects = [] self.joints = JointManager() self.wire_attrib = RenderModeAttrib.make(RenderModeAttrib.MWireframe, 4.) self.attachment_colors = (Vec4(0.1, 0.1, 1., 1.), Vec4(0.1, 0.8, 0.1, 1.), Vec4(1., 0.1, 1., 1.), Vec4(1., 0.5, 0.1, 1.), Vec4(1., 1., 1., 1.)) self.max_attach = 999 self.permanent_events += ["mouse1"] # Make cursor dot. self.cursor = self._build_cursor("cross") s = 0.08 self.cursor.setScale(s, s, s) self.cursor.setColor(1, 1, 1, 1) self.cursor.reparentTo(self.aspect2d) self.taskMgr.add(self.draw_cursor2d, "draw_cursor2d") self.permanent_tasks.append("draw_cursor2d") def init_ssos(self, *args, **kwargs): super(Picker, self).init_ssos(*args, **kwargs) def init_physics(self, *args, **kwargs): super(Picker, self).init_physics(*args, **kwargs) self.joints.bbase = self.bbase def init_picker(self): # Collision traverser self.traverser = CollisionTraverser("traverser") # Collision handler self.handler = CollisionHandlerQueue() # Initialize and set up picker ray node and NodePath self.picker = CollisionNode("mouse_ray") self.pickerNP = self.camera.attachNewNode(self.picker) self.picker.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.picker_ray = CollisionRay() self.picker.addSolid(self.picker_ray) self.traverser.addCollider(self.pickerNP, self.handler) mark_color = (1, 1, 1, 0.3) self.base_mark = self.create_mark(color=mark_color) connector_color = (1, 1, 1, 1) self.base_connector = self.create_connector(color=connector_color) def _build_cursor(self, shape="sphere"): if shape == "sphere": cursor = self._load("sphere.bam") elif shape == "cross": cursor = LineNodePath() lines = [[Point3(-0.5, 0, 0), Point3(0.5, 0, 0)], [Point3(0, 0, -0.5), Point3(0, 0, 0.5)]] cursor.drawLines(lines) cursor.setThickness(1) cursor.create() # cursor = NodePath("cross") # S = {"cylinderX.bam": ((0., 0., 0.), (1., 0.1, 0.1)), # "cylinderY.bam": ((0., 0., 0.), (0.1, 1., 0.1)), # "cylinderZ.bam": ((0., 0., 0.), (0.1, 0.1, 1.))} # for k, v in S.iteritems(): # m = self._load(k) # m.setName(k) # m.setPos(*v[0]) # m.setScale(*v[1]) # m.reparentTo(cursor) #BP() return cursor def create_mark(self, color): """ Makes a graphical mark object.""" # Make a graphical box. props = dict(name="mark", color=color, model="box-round.egg") obj = GSO(props=props) return obj def create_connector(self, color): """ Makes a graphical connector object.""" # Make a graphical box. props = dict(name="connector", color=color, model="connector.egg") obj = GSO(props=props) return obj def start_picker(self, pickables): # Set pickable objs. for i, obj in enumerate(pickables): obj.setTag("pickable", str(i)) # Add mouse events. self.accept("mouse1", self.clicked, extraArgs=[1]) # Start contact detector. detector = ContactDetector(self.bbase.world, self.scene, margin=self.contact_margin) self.contacts = detector.contacts self.contact_bodies = detector.bodies self.contact_points = detector.points parser = Parser(self.contacts, self.contact_bodies) self.contact_bottoms = parser.bottom_bodies self.connectors = {} def stop_picker(self): self.removeTask("mouse1") def goto_sso(self, *args, **kwargs): self.clear_attachments() self.stop_picker() super(Picker, self).goto_sso(*args, **kwargs) self.remove_physics() # Start picker. pickables = self.sso.descendants(type_=PSO) self.start_picker(pickables) self.attach_physics() def get_picked_obj(self): mpos = self.mouseWatcherNode.getMouse() self.picker_ray.setFromLens(self.cam.node(), mpos.getX(), mpos.getY()) self.traverser.traverse(self.render) if self.handler.getNumEntries() > 0: # This is so we get the closest object self.handler.sortEntries() entries = self.handler.getEntries() for entry in entries: picked_obj = entry.getIntoNodePath().findNetTag("pickable") if not picked_obj.isEmpty(): break if picked_obj.isEmpty(): picked_obj = None else: picked_obj = None return picked_obj def clicked(self, button): """ Mouse click handler.""" if self.mouseWatcherNode.hasMouse(): # Get picked object picked_obj = self.get_picked_obj() if picked_obj is not None: if self.marked is None: # New mark activated. self.marked = picked_obj self.show_marked(picked_obj, True) event = "mark" elif picked_obj == self.marked: # Existing mark deactivated. self.show_marked(picked_obj, False) self.marked = None event = "unmark" else: # New attachment or detachment. pair = tuple(sorted((self.marked, picked_obj))) ij = tuple( sorted((self.contact_bodies.index(pair[0]), self.contact_bodies.index(pair[1])))) if ij in self.contacts: f_add = (ij, pair) not in self.attached_pairs if (not f_add or len(self.attached_pairs) < self.max_attach): self.store_attachment(ij, pair, f_add) self.show_marked(self.marked, False) self.marked = None event = "attach" if f_add else "detach" else: print("Max attachments already reached.") event = "max-attach" else: event = "non-contact" else: event = "non-pick" return picked_obj, event def store_attachment(self, ij, pair, f_add): """ Stores the attached objects, and draws them.""" if f_add: self.attached_pairs.add((ij, pair)) self.show_attachment(ij, True) self.attach_pair(pair, True) else: try: self.attached_pairs.remove((ij, pair)) except KeyError: pass else: self.attach_pair(pair, False) self.show_attachment(ij, False) def clear_attachments(self): """ Clear all attachments.""" if self.marked: self.show_marked(self.marked, False) self.marked = None self.mark = None for ij, pair in self.attached_pairs: self.attach_pair(pair, False) self.show_attachment(ij, False) self.attached_pairs = set() # self.reset_compounds() self.contacts = None self.contact_bodies = None self.contact_points = None self.contact_bottoms = None def _make_mark(self, node, extent, name): """ Makes a mark GSO.""" mark = self.base_mark.copy() mat = node.getMat(self.scene) mark.apply_prop(dict(name=name), other=self.scene) mark.setMat(self.scene, mat) mark.setScale(self.scene, mark.getScale(self.scene) + extent) mark.wrtReparentTo(node) return mark def show_marked(self, node, f_on): """ Turns on/off marked graphic.""" if f_on: extent = Vec3(0.15, 0.15, 0.15) name = "mark" self.mark = self._make_mark(node, extent, name) self.mark.init_tree(tags=("model", )) # Exclude object from casting shadows self.mark.hide(self.shadow_mask) self.mark.setTransparency(TransparencyAttrib.MAlpha) self.mark.setDepthWrite(False) self.mark.setBin("fixed", 0, priority=5) else: self.mark.removeNode() def _make_connector(self, parent, points, extent, name): """ Makes connector object.""" connector = self.base_connector.copy() scale = Vec3(*(np.ptp(points, axis=0))) scale_extended = scale + extent pos = Point3(*(np.min(points, axis=0) + scale / 2.)) connector.apply_prop(dict(name=name, scale=scale_extended, pos=pos), other=self.scene) connector.wrtReparentTo(parent) return connector def show_attachment(self, ij, f_on): """ Turns on/off attachment graphic.""" if f_on: parent = self.contact_bottoms[ij] points = self.contact_points[ij] extent = Vec3(0.15, 0.15, 0.15) name = "connector_%d-%d" % ij self.connectors[ij] = self._make_connector(parent, points, extent, name) self.connectors[ij].init_tree(tags=("model", )) else: self.connectors.pop(ij).removeNode() # def attach_pair(self, pair, f_on): # """ Adds/removes physical attachment between a pair of nodes.""" # key = tuple(sorted(p.node() for p in pair)) # # key = frozenset(pair) # if f_on: # # Create the joint and add it. # self.joints[key] = self.joints.make_fixed(*pair) # else: # # Remove it. # del self.joints[key] def attach_physics(self): # Attach `self.scene` to the physics world. try: exclude = zip(*self.compound_components)[0] except IndexError: exclude = [] bnodes = [ bnode for bnode in self.scene.descendants(type_=PSO) if bnode not in exclude ] for bnode in bnodes: bnode.init_resources(tags=("shape", )) bnode.setCollideMask(BitMask32.allOn()) bnode.node().setDeactivationEnabled(False) self.bbase.attach(bnodes) def reset_compounds(self): for n, p in self.compound_components: n.wrtReparentTo(p) self.compound_components = [] for cnode in self.compound_objects: cnode.destroy_resources() cnode.removeNode() self.compound_objects = [] def make_attachment_graph(self): if not self.contact_bodies: return None n = len(self.contact_bodies) mtx = np.zeros((n, n), dtype="i") for (i, j), _ in self.attached_pairs: # i = self.contact_bodies.index(pair[0]) # j = self.contact_bodies.index(pair[1]) mtx[i, j] = 1 # mtx[j, i] = 1 graph = nx.from_numpy_matrix(mtx) return graph def attach_pair(self, pair, f_on): """ Adds/removes physical attachment between a pair of nodes.""" # Get the connected subgroups. graph = self.make_attachment_graph() sgs = [sg for sg in nx.connected_components(graph) if len(sg) > 1] self.reset_compounds() # Iterate over subgroups, creating compound shapes. for sg in sgs: nodes = [self.contact_bodies[i] for i in sg] parents = [c.getParent() for c in nodes] self.compound_components.extend(zip(nodes, parents)) cname = "+".join([str(i) for i in sorted(sg)]) cnode = CPSO(cname) cnode.reparentTo(self.scene) cnode.add(nodes) cnode.init_tree(tags=("shape", )) cnode.destroy_component_shapes() self.compound_objects.append(cnode)
class Physics: def __init__(self): self.rayCTrav = CollisionTraverser("collision traverser for ray tests") #self.pusher = PhysicsCollisionHandler() self.pusher = CollisionHandlerPusher() self.pusher.addInPattern('%fn-in-%in') self.pusher.addOutPattern('%fn-out-%in') self.pusher.addInPattern('%fn-in') self.pusher.addOutPattern('%fn-out') def startPhysics(self): #self.actorNode = ActorNode("playerPhysicsControler") #base.physicsMgr.attachPhysicalNode(self.actorNode) #self.actorNode.getPhysicsObject().setMass(self.player_mass) #self.mainNode = render.attachNewNode(self.actorNode) self.mainNode = render.attachNewNode("CharacterColliders") self.reparentTo(self.mainNode) charCollisions = self.mainNode.attachNewNode( CollisionNode(self.char_collision_name)) #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0, self.player_height/4.0)) #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0*3.05, self.player_height/4.0)) charCollisions.node().addSolid( CollisionSphere(0, 0, self.player_height / 2.0, self.player_height / 4.0)) charCollisions.node().setIntoCollideMask(BitMask32(0x80)) # 1000 0000 if self.show_collisions: charCollisions.show() self.pusher.addCollider(charCollisions, self.mainNode) base.cTrav.addCollider(charCollisions, self.pusher) charFFootCollisions = self.attachNewNode(CollisionNode("floor_ray")) charFFootCollisions.node().addSolid(CollisionRay(0, 0, 0.5, 0, 0, -1)) #charFFootCollisions.node().addSolid(CollisionSegment((0, 0, 0.2), (0, 0, -1))) charFFootCollisions.node().setIntoCollideMask(BitMask32.allOff()) charFFootCollisions.node().setFromCollideMask( BitMask32(0x7f)) # 0111 1111 if self.show_collisions: charFFootCollisions.show() self.floor_handler = CollisionHandlerFloor() self.floor_handler.addCollider(charFFootCollisions, self.mainNode) #self.floor_handler.setOffset(0) self.floor_handler.setMaxVelocity(5) base.cTrav.addCollider(charFFootCollisions, self.floor_handler) self.accept("{}-in".format(self.char_collision_name), self.checkCharCollisions) self.raytest_segment = CollisionSegment(0, 1) self.raytest_np = render.attachNewNode(CollisionNode("testRay")) self.raytest_np.node().addSolid(self.raytest_segment) self.raytest_np.node().setIntoCollideMask(BitMask32.allOff()) self.raytest_np.node().setFromCollideMask(BitMask32(0x7f)) # 0111 1111 if self.show_collisions: self.raytest_np.show() self.raytest_queue = CollisionHandlerQueue() self.rayCTrav.addCollider(self.raytest_np, self.raytest_queue) def stopPhysics(self): self.raytest_segment.removeNode() self.pusher.clearColliders() self.floor_handler.clearColliders() self.rayCTrav.clearColliders() def updatePlayerPos(self, speed, heading, dt): if heading is not None: self.mainNode.setH(camera, heading) self.mainNode.setP(0) self.mainNode.setR(0) self.mainNode.setFluidPos(self.mainNode, speed) self.doStep() def checkCharCollisions(self, args): self.doStep() def doStep(self): # do the step height check tmpNP = self.mainNode.attachNewNode("temporary") tmpNP.setPos(self.mainNode, 0, 0, -self.stepheight) pointA = self.mainNode.getPos(render) pointA.setZ(pointA.getZ() + self.player_height / 1.8) pointB = tmpNP.getPos(render) if pointA == pointB: return char_step_collision = self.getFirstCollisionInLine(pointA, pointB) tmpNP.removeNode() if char_step_collision is not None: self.mainNode.setFluidZ(char_step_collision.getZ()) return True return False def getFirstCollisionInLine(self, pointA, pointB): """A simple raycast check which will return the first collision point as seen from point A towards pointB""" self.raytest_segment.setPointA(pointA) self.raytest_segment.setPointB(pointB) self.rayCTrav.traverse(render) self.raytest_queue.sortEntries() pos = None if self.raytest_queue.getNumEntries() > 0: pos = self.raytest_queue.getEntry(0).getSurfacePoint(render) return pos
class Usuario(object): """ Usuario """ def __init__(self, dadosUsuario, principal=False): self.key = dadosUsuario["key"] self.nick = dadosUsuario["nick"] self.vida_real = float(dadosUsuario["vida_real"]) self.vida_total = float(dadosUsuario["vida_total"]) self.mana_real = float(dadosUsuario["mana_real"]) self.mana_total = float(dadosUsuario["mana_total"]) self.forca = float(dadosUsuario["forca"]) self.velocidade = float(dadosUsuario["velocidade"]) self.velocidade_atack = float(dadosUsuario["velocidade_atack"]) self.estaMovendo = False self.estaRodando = False self.__task_name = "Task Usuario - " + self.key self.keyMap = {TECLA_esquerda: EVENT_up, TECLA_direita: EVENT_up, TECLA_frente: EVENT_up, TECLA_traz: EVENT_up} pandaFileModelo = get_path_modelo("ralph") pandaFileAnimacaoRun = get_path_animacao("ralph-run") pandaFileAnimacaoWalk = get_path_animacao("ralph-walk") self.modelo = Actor(pandaFileModelo, {"run": pandaFileAnimacaoRun, "walk": pandaFileAnimacaoWalk}) self.modelo.reparentTo(render) self.modelo.setScale(SCALE_MODELOS) self.set_pos((float(dadosUsuario["x"]), float(dadosUsuario["y"]), float(dadosUsuario["z"]))) self.set_h(float(dadosUsuario["h"])) if not principal: self.text = Text( parent=self.modelo, pos=(0, 0, 5.5), scale=0.5, align="center", cor=COR_VERDE, text=self.nick ) self.text.billboardEffect() self.__setup_collision() taskMgr.add(self.__task_movimentacao, self.__task_name, sort=1) def get_x(self): return self.modelo.getX() def get_y(self): return self.modelo.getY() def get_z(self): return self.modelo.getZ() def get_h(self): return self.modelo.getH() def get_pos(self): return self.modelo.getPos() def set_x(self, x): self.modelo.setX(x) def set_y(self, y): self.modelo.setY(y) def set_z(self, z): self.modelo.setZ(z) def set_h(self, h): self.modelo.setH(h) def set_pos(self, pos): self.modelo.setPos(pos) def delete(self): taskMgr.remove(self.__task_name) self.modelo.delete() def __setup_collision(self): # Colisao self.cTrav = CollisionTraverser("usuarioTraverser") self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 5) 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.modelo.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) # self.ralphGroundColNp.show() # self.cTrav.showCollisions(render) # Colisao def __task_movimentacao(self, task): dt = globalClock.getDt() startpos = self.modelo.getPos() # movimentos usuario modelo if self.keyMap[TECLA_esquerda] == EVENT_down and self.keyMap[TECLA_direita] == EVENT_up: self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt)) if not self.estaRodando: self.estaRodando = True elif self.keyMap[TECLA_direita] == EVENT_down and self.keyMap[TECLA_esquerda] == EVENT_up: self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt) * -1) if not self.estaRodando: self.estaRodando = True elif self.estaRodando: self.estaRodando = False if self.keyMap[TECLA_frente] == EVENT_down and self.keyMap[TECLA_traz] == EVENT_up: self.modelo.setY(self.modelo, ((self.velocidade * 2) * dt) * -1) if self.estaMovendo is False: self.modelo.loop("run") self.estaMovendo = True elif self.keyMap[TECLA_traz] == EVENT_down and self.keyMap[TECLA_frente] == EVENT_up: self.modelo.setY(self.modelo, (self.velocidade * dt)) if self.estaMovendo is False: self.modelo.loop("walk") self.estaMovendo = True elif self.estaMovendo: self.modelo.stop() self.modelo.pose("walk", 5) self.estaMovendo = False # movimentos usuario modelo if self.estaMovendo: self.cTrav.traverse(render) if self.ralphGroundHandler.getNumEntries() == 1: entry = self.ralphGroundHandler.getEntry(0) if entry.getIntoNode().getName() == "terrain": self.modelo.setZ(entry.getSurfacePoint(render).getZ()) else: self.modelo.setPos(startpos) return task.cont
class World(DirectObject): def __init__(self): #Let's start the Music mySound = base.loader.loadSfx("music/music.mp3") mySound.setLoopCount(0) #And Keep it On Loop mySound.play() base.setFrameRateMeter(True) #Shows the FrameRate in The Top Corner self.walking = Vec3() self.isMoving = False self.dest = None base.win.setClearColor(Vec4(0,0,0,1)) self.keyMap = {"left":0, "right":0, "forward":0, "backward":0} base.win.setClearColor(Vec4(0,0,0,1)) #Here is the number of collectibles in the game self.rare = 1; self.vasenum = 10; self.coinnum = 30; self.silvernum = 5; self.chestnum = 2; #Here is the Obstacles in the game self.rocknum = 500; #Here is the Score self.score = 0; #Here is the total Number of Objects to collect self.numObjects = self.rare + self.vasenum + self.coinnum + self.silvernum + self.chestnum # print the number of objects printNumObj(self.score) # Post the instructions self.title = addTitle("Mighty Mountain") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[A]: Rotate Ralph Left") self.inst3 = addInstructions(0.85, "[D]: Rotate Ralph Right") self.inst4 = addInstructions(0.80, "[W]: Run Ralph Forward") self.inst5 = addInstructions(0.75, "[S]: Run Ralph Backward") self.inst6 = addInstructions(0.70, "[Space]: Run, Ralph, Run") # 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("models/world") self.environ.reparentTo(render) self.environ.setPos(0,0,0) # Timer to increment in the move task self.time = 0 # Get bounds of environment min, max = self.environ.getTightBounds() self.mapSize = max-min # Create the main character, Ralph self.ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(self.ralphStartPos) # ralph's stamina self.stamina = 200 # 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", self.endgame) # these don't work well in combination with the space bar 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("arrow_down", self.setKey, ["backward",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("arrow_down-up", self.setKey, ["backward",0]) self.accept("space", self.runRalph, [True]) self.accept("space-up", self.runRalph, [False]) 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]) # Game state variables self.isMoving = False self.isRunning = False # Set up the camera base.disableMouse() #base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,2) base.camera.setPos(0, 0, 0) base.camera.reparentTo(self.ralph) base.camera.setPos(0, 40, 2) base.camera.lookAt(self.ralph) # 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. base.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0,0,300) 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() base.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) # camera ground collision handler self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,300) 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() base.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Place the collectibles self.placeCollectibles() #Platinum self.placeVases() self.placeCoins() self.placeSilver() self.placeGold() self.placeChests() #Place the obstacles self.placeRocks() #Cactus # Uncomment this line to show a visual representation of the # collisions occuring #base.cTrav.showCollisions(render) # Create some lighting 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)) taskMgr.add(self.move,"moveTask") #Reinitialize all necessary parts of the game def restart(self): #self.numObjects = 10 self.score = 0 printNumObj(self.score) self.ralph.setPos(self.ralphStartPos) self.stamina = 200 self.time = 0 base.camera.setPos(0, 0, 0) base.camera.reparentTo(self.ralph) base.camera.setPos(0, 40, 2) base.camera.lookAt(self.ralph) # Place the collectibles self.placeCollectibles() #Platinum self.placeVases() self.placeCoins() self.placeSilver() self.placeGold() self.placeChests() #Place the obstacles self.placeRocks() #Total number of obstacles self.numObjects = self.rare + self.vasenum + self.coinnum + self.silvernum + self.chestnum taskMgr.add(self.move,"moveTask") # Display ralph's stamina def displayStamina(self): sprintBar['scale'] = (self.stamina*0.01*BAR_WIDTH,0.2,0.2) #Collects the item and modifies score def collectCollectibles(self, entry): #Platinum #Remove the collectible entry.getIntoNodePath().getParent().removeNode() # Update the number of objects self.score = self.score * self.numObjects + 500 self.numObjects = self.numObjects - 1 printNumObj(self.score) def collectVase(self, entry): # Remove the collectible entry.getIntoNodePath().getParent().removeNode() # Update the number of objects self.score = self.score + 10 self.numObjects = self.numObjects - 1 printNumObj(self.score) def collectCoins(self, entry): # Remove the collectible entry.getIntoNodePath().getParent().removeNode() # Update the number of objects self.score = self.score + 1 printNumObj(self.score) self.numObjects = self.numObjects - 1 def collectSilver(self, entry): # Remove the collectible entry.getIntoNodePath().getParent().removeNode() # Update the number of objects self.score = self.score + 20 printNumObj(self.score) self.numObjects = self.numObjects - 1 def collectGold(self, entry): # Remove the collectible entry.getIntoNodePath().getParent().removeNode() # Update the number of objects self.score = self.score + 30 printNumObj(self.score) self.numObjects = self.numObjects - 1 def collectChest(self, entry): # Remove the collectible entry.getIntoNodePath().getParent().removeNode() # Update the number of objects self.score = self.score + 100 printNumObj(self.score) self.numObjects = self.numObjects - 1 #Unique function which handles collisions with a deduction obstacles. def deductRocks(self, entry): # Remove the collectible entry.getIntoNodePath().getParent().removeNode() # Update the number of objects if self.score > 500: randomnum = random.randint(1,2) if randomnum == 1: self.score = self.score - 100 #Removes Score if randomnum == 2: self.score = self.score + 100 #Removes Score if self.score < 500: self.score = self.score - 100 randomnum = random.randint(1,2) if randomnum == 1: result =buttonbox(msg='A kind wizard wishes to help you on your quest? Trust him?', title='Alert!', choices=("Yes", "No")) if result == "Yes": othernum = random.randint(1,100) othernum = othernum * self.score + self.numObjects #Y = MX + B if othernum > 1000: msgbox("Good choice! Add 1,000 Points to your Score!") self.score = self.score + 1000 if othernum < 1000: msgbox("The wizard tricked you!He stole 100 Points!") self.score = self.score - 100 printNumObj(self.score) # Places an item randomly on the map def placeItem(self, item): # Add ground collision detector to the health item self.collectGroundRay = CollisionRay() self.collectGroundRay.setOrigin(0,0,300) self.collectGroundRay.setDirection(0,0,-1) self.collectGroundCol = CollisionNode('colRay') self.collectGroundCol.addSolid(self.collectGroundRay) self.collectGroundCol.setFromCollideMask(BitMask32.bit(0)) self.collectGroundCol.setIntoCollideMask(BitMask32.allOff()) self.collectGroundColNp = item.attachNewNode(self.collectGroundCol) self.collectGroundHandler = CollisionHandlerQueue() base.cTrav.addCollider(self.collectGroundColNp, self.collectGroundHandler) placed = False; while placed == False: # re-randomize position item.setPos(-random.randint(0,140),-random.randint(0,40),0) base.cTrav.traverse(render) # Get Z position from terrain collision entries = [] for j in range(self.collectGroundHandler.getNumEntries()): entry = self.collectGroundHandler.getEntry(j) 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"): item.setZ(entries[0].getSurfacePoint(render).getZ()+1) placed = True # remove placement collider self.collectGroundColNp.removeNode() #Places all obstacles on map. def placeCollectibles(self): self.placeCol = render.attachNewNode("Collectible-Placeholder") self.placeCol.setPos(0,0,0) # Add the health items to the placeCol node for i in range(self.rare): # Load in the health item model self.collect = loader.loadModel("models/moneyBag") self.collect.setPos(0,0,0) self.collect.reparentTo(self.placeCol) self.placeItem(self.collect) # Add spherical collision detection colSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('colSphere') sphereNode.addSolid(colSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.collect.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) def placeVases(self): self.placeV = render.attachNewNode("Collectible-Placeholder") self.placeV.setPos(0,0,0) # Add the health items to the placeCol node for i in range(self.vasenum): # Load in the health item model self.collect = loader.loadModel("models/jar.egg") self.collect.setPos(0,0,0) self.collect.reparentTo(self.placeV) self.placeItem(self.collect) # Add spherical collision detection vaseSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('vaseSphere') sphereNode.addSolid(vaseSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.collect.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) def placeCoins(self): self.placeC = render.attachNewNode("Collectible-Placeholder") self.placeC.setPos(0,0,0) # Add the health items to the placeCol node for i in range(self.coinnum): # Load in the health item model self.collect = loader.loadModel("models/Cookie.egg") self.collect.setPos(0,0,0) self.collect.reparentTo(self.placeC) self.placeItem(self.collect) # Add spherical collision detection coinSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('coinSphere') sphereNode.addSolid(coinSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.collect.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) def placeSilver(self): self.placeS = render.attachNewNode("Collectible-Placeholder") self.placeS.setPos(0,0,0) # Add the health items to the placeCol node for i in range(self.silvernum): # Load in the health item model self.collect = loader.loadModel("models/Anvil.egg") self.collect.setPos(0,0,0) self.collect.reparentTo(self.placeS) self.placeItem(self.collect) # Add spherical collision detection silverSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('silverSphere') sphereNode.addSolid(silverSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.collect.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) def placeGold(self): self.placeG = render.attachNewNode("Collectible-Placeholder") self.placeG.setPos(0,0,0) # Add the health items to the placeCol node for i in range(self.silvernum): # Load in the health item model self.collect = loader.loadModel("models/key.egg") self.collect.setPos(0,0,0) self.collect.reparentTo(self.placeS) self.placeItem(self.collect) # Add spherical collision detection goldSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('goldSphere') sphereNode.addSolid(goldSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.collect.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) def placeChests(self): self.placeCh = render.attachNewNode("Collectible-Placeholder") self.placeCh.setPos(0,0,0) # Add the health items to the placeCol node for i in range(self.chestnum): # Load in the health item model self.collect = loader.loadModel("models/Keg.a2c.cr.egg") self.collect.setPos(0,0,0) self.collect.reparentTo(self.placeCh) self.placeItem(self.collect) # Add spherical collision detection chestSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('chestSphere') sphereNode.addSolid(chestSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.collect.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) def placeRocks(self): self.placeR = render.attachNewNode("Collectible-Placeholder") self.placeR.setPos(0,0,0) # Add the health items to the placeCol node for i in range(self.rocknum): # Load in the health item model self.collect = loader.loadModel("models/smallcactus.egg") self.collect.setScale(0.2) self.collect.setPos(0,0,0) self.collect.reparentTo(self.placeR) self.placeItem(self.collect) # Add spherical collision detection rockSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('rockSphere') sphereNode.addSolid(rockSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.collect.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue() base.cTrav.addCollider(sphereNp, sphereColHandler) #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Makes ralph's health decrease over time # Make ralph's stamina regenerate def staminaReg(self, task): if (self.stamina >= 200): self.stamina = 200 return task.done else: self.stamina += 1 task.setDelay(1) return task.again # Make ralph run def runRalph(self, arg): self.isRunning = arg # 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.score < 0: self.die() if self.numObjects == 0: self.endgame() randomnum1 = random.randint(1,1000) randomnum2 = randomnum1 * self.numObjects + self.score if randomnum1 == 1000: result =buttonbox(msg='An odd villager wishes to help you on your quest? Trust him?', title='Alert!', choices=("Yes", "No")) if result == "Yes": if randomnum2 > 20000: msgbox("The villager grants you 4,000 Points!") self.score = self.score + 4000 if randomnum2 < 20000: msgbox("The villager betrays you! He steal 200 points!") self.score = self.score - 200 # 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() # calculate ralph's speed if (self.isRunning and self.stamina > 0): taskMgr.remove("staminaTask") ralphSpeed = 45 self.stamina -= 0.5 else: taskMgr.doMethodLater(5, self.staminaReg, "staminaTask") ralphSpeed = 25 # If a move-key is pressed, move ralph in the specified direction. # and rotate the camera to remain behind ralph if (self.keyMap["left"]!=0): self.ralph.setH(self.ralph.getH() + 100 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.ralph.setH(self.ralph.getH() - 100 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.ralph.setY(self.ralph, -ralphSpeed * globalClock.getDt()) if (self.keyMap["backward"]!=0): self.ralph.setY(self.ralph, ralphSpeed *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) or (self.keyMap["backward"]!=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 # so the following line is unnecessary base.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()) #base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+5) #Adds all the items to the map and handles if they get hit. elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "colSphere"): self.collectCollectibles(entries[0]) elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "vaseSphere"): self.collectVase(entries[0]) elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "coinSphere"): self.collectCoins(entries[0]) elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "silverSphere"): self.collectSilver(entries[0]) elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "goldSphere"): self.collectGold(entries[0]) elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "chestSphere"): self.collectChest(entries[0]) elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "rockSphere"): self.deductRocks(entries[0]) else: self.ralph.setPos(startpos) # Keep the camera above the terrain 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"): modZ = entries[0].getSurfacePoint(render).getZ() base.camera.setZ(20.0+modZ+(modZ-self.ralph.getZ())) self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ()+2.0) base.camera.lookAt(self.floater) self.displayStamina() return task.cont #If the user collects all items and/or ends the game through Escape. def endgame(self): # end all running tasks taskMgr.remove("moveTask") taskMgr.remove("healthTask") # Open database connection and inserts data. conn = MySQLdb.connect("sql5.freemysqlhosting.net","sql5106009","DFxbmhVkvG","sql5106009") cursor = conn.cursor() cursor.execute("INSERT INTO scores (score, username) VALUES (%s, %s)", (self.score, name)) conn.commit() time.sleep(5) #Error without this... #Some text self.label = DirectLabel(text="End Game!", scale=.05, pos=(0,0,0.2)) self.entry = DirectEntry(text="", scale=.05, initialText="", numLines=1, focus=1, pos=(-0.25,0,0)) #Display high score self.highscore = OkDialog(dialogName="highscoreDialog", text="Your High Score:\n\nName: " + name + "Score: " + str(self.score), command=sys.exit()) # Restart or End? def die(self): # end all running tasks taskMgr.remove("moveTask") taskMgr.remove("healthTask") # Open database connection conn = MySQLdb.connect("sql5.freemysqlhosting.net","sql5106009","DFxbmhVkvG","sql5106009") cursor = conn.cursor() cursor.execute("INSERT INTO scores (score, username) VALUES (%s, %s)", (self.score, name)) conn.commit() time.sleep(5) self.label = DirectLabel(text="Game over!", scale=.05, pos=(0,0,0.2)) self.entry = DirectEntry(text="", scale=.05, initialText="", numLines=1, focus=1, pos=(-0.25,0,0)) #Display high score self.highscore = OkDialog(dialogName="highscoreDialog", text="Your High Score:\n\nName: " + name + " " + "Score: " + str(self.score), command=self.showDialog) def showDialog(self, arg): # cleanup highscore dialog self.highscore.cleanup() # display restart or exit dialog self.dialog = YesNoDialog(dialogName="endDialog", text="Would you like to continue?", command=self.endResult) # Handle the dialog result def endResult(self, arg): if (arg): # cleanup the dialog box self.dialog.cleanup() # restart the game self.restart() else: sys.exit()
class World(DirectObject): def skyBoxLoad(self): self.spaceSkyBox = load_model('skybox1.egg') self.spaceSkyBox.setScale(150) self.spaceSkyBox.setLightOff() self.spaceSkyBox.reparentTo(render) self.spaceSkyBox.setPos(0,0,-200) self.spaceSkyBox.setHpr(0,0,0) def loadEnviron(self): self.environ = load_model("secondWorld.egg") self.environ.reparentTo(render) self.environ.setPos(0,0,0) def loadPokemon(self): self.pikachu = load_model("pikachu.egg") self.pikachu.reparentTo(render) self.pikachu.setScale(1) # self.pikachu.setPos(0,0,1) # self.pikachu.place() self.Groudon = load_model("Groudon.egg") self.Groudon.reparentTo(render) self.Groudon.setPos(-50,0,0) # self.Groudon.place() def loadRalph(self): # Create the main character, Ralph basePath = r"../google_drive/ball/data/models/" ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor(basePath+"ralph",{"run":basePath+"ralph-run", "walk":basePath+"ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos) self.ralph.hide() def loadMusic(self, name="palette.mp3"): bgmusic = load_bgmusic(name) bgmusic.play() def keyControl(self): 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("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("w",self.setKey,["upward",1]) self.accept("w-up",self.setKey,["upward",0]) self.accept("s",self.setKey,["downward",1]) self.accept("s-up",self.setKey,["downward",0]) def displayInformation(self): self.title = addTitle("My Pokemon - Roam Mode") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[Arrow Keys]: Move") self.inst4 = addInstructions(0.85, "[w]: look up") self.inst4 = addInstructions(0.80, "[s]: look down") def __init__(self): self.keyMap = {"left":0, "right":0, "forward":0,"backward":0, "upward":0, "downward":0, "leftward":0,"rightward":0, "cam-left":0, "cam-right":0} # base.win.setClearColor(Vec4(0,0,0,1)) self.above = 3.0 # load sky box self.skyBoxLoad() # load environment self.loadEnviron() # load pokemon self.loadPokemon() # load ralph self.loadRalph() # load music self.loadMusic() self.displayInformation() self.keyControl() # 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) taskMgr.add(self.move,"moveTask") taskMgr.add(self.setAbove,"setAbove") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(),self.ralph.getY(),2) 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) # Create some lighting 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)) def setAbove(self,task): if self.keyMap["upward"] == 1: self.above += 0.1 if self.keyMap["downward"] == 1: self.above -= 0.1 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): # 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() + 113 * globalClock.getDt()) base.camera.setX(base.camera, +20 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.ralph.setH(self.ralph.getH() - 113 * globalClock.getDt()) base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.ralph.setY(self.ralph, -75 * globalClock.getDt()) if (self.keyMap["backward"] != 0): pass #self.ralph.setY(self.ralph, 75 * 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):# or (self.keyMap["backward"]!=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 # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. 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 # 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) # Keep the camera at one foot above the terrain, # or two feet above ralph, 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.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.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. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + self.above)#self.above) base.camera.lookAt(self.floater) return task.cont
class World(DirectObject): def __init__(self): #create Queue to hold the incoming chat #request the heartbeat so that the caht interface is being refreshed in order to get the message from other player self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0, "charge":0} base.win.setClearColor(Vec4(0,0,0,1)) self.cManager = ConnectionManager() self.cManager.startConnection() #------------------------------ #Chat Chat(self.cManager) #send dummy login info of the particular client #send first chat info #--------------------------------------- self.userName = username dummy_login ={'user_id' : self.userName, 'factionId': faction, 'password': '******'} self.cManager.sendRequest(Constants.RAND_STRING, dummy_login) chat = { 'userName' : self.userName, #username 'message' : '-------Login------' } self.cManager.sendRequest(Constants.CMSG_CHAT, chat) #-------------------------------------- #self.minimap = OnscreenImage(image="images/minimap.png", scale=(0.2,1,0.2), pos=(-1.1,0,0.8)) #frame = DirectFrame(text="Resource Bar", scale=0.001) resource_bar = DirectWaitBar(text="", value=35, range=100, pos=(0,0,0.9), barColor=(255,255,0,1), frameSize=(-0.3,0.3,0,0.03)) cp_bar = DirectWaitBar(text="", value=70, range=100, pos=(1.0,0,0.9), barColor=(0,0,255,1), frameSize=(-0.3,0.3,0,0.03), frameColor=(255,0,0,1)) # 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("models/world") self.environ.reparentTo(render) self.environ.setPos(0,0,0) # Create the main character, Ralph ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos) nameplate = TextNode('textNode username_' + str(self.userName)) nameplate.setText(self.userName) npNodePath = self.ralph.attachNewNode(nameplate) npNodePath.setScale(0.8) npNodePath.setBillboardPointEye() #npNodePath.setPos(1.0,0,6.0) npNodePath.setZ(6.5) bar = DirectWaitBar(value=100, scale=1.0) bar.setColor(255,0,0) #bar.setBarRelief() bar.setZ(6.0) bar.setBillboardPointEye() bar.reparentTo(self.ralph) # 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("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]) self.accept("c", self.setKey, ["charge",1]) self.accept("c-up", self.setKey, ["charge",0]) taskMgr.add(self.move,"moveTask") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(),self.ralph.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 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) # Create some lighting 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)) #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 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 (self.keyMap["charge"]!=0): self.ralph.setY(self.ralph, -250 * globalClock.getDt()) #ribbon = Ribbon(self.ralph, Vec4(1,1,1,1), 3, 10, 0.3) #ribbon.getRoot().setZ(2.0) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"]!=0) or (self.keyMap["charge"]!=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 # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. 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 # 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) # Keep the camera at one foot above the terrain, # or two feet above ralph, 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.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.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. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + 2.0) base.camera.lookAt(self.floater) return task.cont
class Main(ShowBase): def __init__(self): ShowBase.__init__(self) global picture_names picture_names = [f for f in listdir('images') if isfile(join('images', f))] self.handScale = 1 self.handV=ZERO self.scale = 20 / self.handScale self.ex = Vec3(1,0,0) self.ez = Vec3(0,0,-1) self.leap = Leap.Controller() self.title = OnscreenText(text="Wen-Jye's Panda3D Leap Motion", style=1, fg=(1,1,0,1), pos=(0.7,-0.95), scale = .07) self.score = OnscreenText(text="", pos = (-1.3, .75), fg=(1,1,0,1), align = TextNode.ALeft, scale = .1) self.timer = OnscreenText(text="", pos = (-1.3, .85), fg=(1,1,0,1), align = TextNode.ALeft, scale = .1) self.cTrav = CollisionTraverser() self.cHandler = CollisionHandlerQueue() self.handLoader() self.tracks = self.loader.loadModel("models/tracks") self.tracks.setScale(1,1.5,1) self.tracks.setPosHpr(-3, STAGE_HEIGHT, 12, 90, 90, 90) self.train = self.loader.loadModel("models/train") self.train.setScale(1,0.5,0.5) self.train.setPosHpr(16, STAGE_HEIGHT+0.3, 12, 90, 180, 90) self.stage = self.loader.loadModel("models/stage") self.stage.setScale(0.55,0.50,0.25) self.stage.setPosHpr(0, STAGE_HEIGHT-0.5, 2, 90, 180, 90) self.mesh = self.stage.find("**/mesh_stage") self.floor = self.stage.find("**/floor") self.floor.node().setIntoCollideMask(BitMask32.bit(0)) self.wall_B = self.stage.find("**/wall_B") self.wall_B.node().setIntoCollideMask(BitMask32.bit(0)) self.wall_F = self.stage.find("**/wall_F") self.wall_F.node().setIntoCollideMask(BitMask32.bit(0)) self.wall_R = self.stage.find("**/wall_R") self.wall_R.node().setIntoCollideMask(BitMask32.bit(0)) self.wall_L = self.stage.find("**/wall_L") self.wall_L.node().setIntoCollideMask(BitMask32.bit(0)) self.buttonList = [render.attachNewNode("button_%i" % (i+1)) for i in range(3)] # @UndefinedVariable for i in range(len(self.buttonList)): self.buttonCreator(i) self.buttonList[i].detachNode() self.setLight() self.errorMsg = OnscreenText(text="", pos = (0,0), fg=(1,1,0,1), align = TextNode.ACenter, scale = .1) self.taskMgr.add(self.spinCameraTask, "SpinCameraTask") self.menuBG = self.loadImageAsPlane("tex/startScreen.jpg" ) self.menuBG.setScale(12.5,9,8.5) self.menuBG.reparentTo(self.render) self.menuBG.setPosHpr(0,STAGE_HEIGHT+1.5,-2, 0, -105, 0) self.menuBG.setTransparency(TransparencyAttrib.MAlpha) self.menuBG.setAlphaScale(1) self.taskMgr.add(self.deviceChecker, "deviceChecker") def spinCameraTask(self, task): self.camera.setPos(0,STAGE_HEIGHT+10,30) self.camera.setHpr(0,255,0) self.camLens.setFov(65) return Task.cont def loadImageAsPlane(self, filepath, yresolution = 600): tex = loader.loadTexture(filepath) # @UndefinedVariable tex.setBorderColor(Vec4(0,0,0,0)) tex.setWrapU(Texture.WMBorderColor) tex.setWrapV(Texture.WMBorderColor) cm = CardMaker(filepath + ' card') cm.setFrame(-tex.getOrigFileXSize(), tex.getOrigFileXSize(), -tex.getOrigFileYSize(), tex.getOrigFileYSize()) card = NodePath(cm.generate()) card.setTexture(tex) card.setScale(card.getScale()/ yresolution) card.flattenLight() # apply scale return card def handLoader(self): self.palm_R = self.loader.loadModel("%s/palm_R" % LOAD_HAND_FROM) # @UndefinedVariable self.palm_R_collider = self.palm_R.find("**/palm_R_collider") self.palm_R_collider.node().setIntoCollideMask(BitMask32.bit(0)) self.fing_R = [self.loader.loadModel("%s/fing%i_R" % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable self.midd_R = [self.loader.loadModel("%s/m%i_R" % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable self.base_R = [self.loader.loadModel("%s/b%i_R" % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable self.fing_R_collider = [self.fing_R[i].find("**/fing%i_R_collider" % (i+1)) for i in range(5)] # @UndefinedVariable self.midd_R_collider = [self.midd_R[i].find("**/m%i_R_collider" % (i+1)) for i in range(5)] # @UndefinedVariable self.base_R_collider = [self.base_R[i].find("**/b%i_R_collider" % (i+1)) for i in range(5)] # @UndefinedVariable self.palm_L = self.loader.loadModel("%s/palm_L" % LOAD_HAND_FROM) # @UndefinedVariable self.palm_R_collider = self.palm_L.find("**/palm_L_collider") self.palm_R_collider.node().setIntoCollideMask(BitMask32.bit(0)) self.fing_L = [self.loader.loadModel("%s/fing%i_L" % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable self.midd_L = [self.loader.loadModel("%s/m%i_L" % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable self.base_L = [self.loader.loadModel("%s/b%i_L" % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable self.fing_L_collider = [self.fing_L[i].find("**/fing%i_L_collider" % (i+1)) for i in range(5)] # @UndefinedVariable self.midd_L_collider = [self.midd_L[i].find("**/m%i_L_collider" % (i+1)) for i in range(5)] # @UndefinedVariable self.base_L_collider = [self.base_L[i].find("**/b%i_L_collider" % (i+1)) for i in range(5)] # @UndefinedVariable self.palm_R.setScale(self.handScale, self.handScale, self.handScale*1.5) self.palm_L.setScale(self.handScale, self.handScale, self.handScale*1.5) for f in self.fing_R: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5) for f in self.midd_R: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5) for f in self.base_R: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5) for f in self.fing_L: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5) for f in self.midd_L: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5) for f in self.base_L: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5) for f in self.fing_R_collider: f.node().setIntoCollideMask(BitMask32.bit(0)) for f in self.midd_R_collider: f.node().setIntoCollideMask(BitMask32.bit(0)) for f in self.base_R_collider: f.node().setIntoCollideMask(BitMask32.bit(0)) for f in self.fing_L_collider: f.node().setIntoCollideMask(BitMask32.bit(0)) for f in self.midd_L_collider: f.node().setIntoCollideMask(BitMask32.bit(0)) for f in self.base_L_collider: f.node().setIntoCollideMask(BitMask32.bit(0)) def deviceChecker(self, task): if self.leap.is_connected: if len(self.leap.frame().hands) is 0: self.errorMsg.setText("please place the hand above the device to start") return Task.cont else: base.cTrav = self.cTrav # @UndefinedVariable self.errorMsg.setText("") self.menuBG.detachNode() taskMgr.remove("handUpdater") # @UndefinedVariable self.handLoop = taskMgr.add(self.handUpdater, "handUpdater") # @UndefinedVariable self.handLoop.last = 0 self.homeInitial() return Task.done else: self.errorMsg.setText("please connect device") return Task.cont def buttonCreator(self, buttonRoot): button = loader.loadModel("models/button") # @UndefinedVariable button.setScale(0.3,0.4,0.25) button.reparentTo(self.buttonList[buttonRoot]) # @UndefinedVariable buttonMesh = button.find("**/mesh_button") myTexture = self.loader.loadTexture('tex/start_%i.png' %(buttonRoot+1)) buttonMesh.setTexture(myTexture,1) buttonCollider = button.find("**/collider_button") buttonCollider.node().setFromCollideMask(BitMask32.bit(0)) self.cTrav.addCollider(buttonCollider, self.cHandler) def cubeCreator(self, i, cubeRoot): global tempCubeList cube = loader.loadModel("models/cube") # @UndefinedVariable print(i) cube.reparentTo(tempCubeList[i][0]) # @UndefinedVariable cubeMesh = cube.find("**/mesh_cube") myTexture = self.loader.loadTexture('cubes/tex_%i.jpg' %(cubeRoot)) cubeMesh.setTexture(myTexture,1) cubeSphere = cube.find("**/collider_cube") cubeSphere.node().setFromCollideMask(BitMask32.bit(0)) self.cTrav.addCollider(cubeSphere, self.cHandler) def clamp(self, i, mn=0, mx=1): return min(max(i, mn), mx) def setLight(self): #self.ambientText = self.makeStatusLabel(0) self.ambientLight = self.render.attachNewNode(AmbientLight("ambientLight")) # Set the color of the ambient light self.ambientLight.node().setColor((1, 1, 1, 1)) self.render.setLight(self.ambientLight) self.directionalLight = self.render.attachNewNode( DirectionalLight("directionalLight")) self.directionalLight.node().setColor((.35, .35, .35, 1)) # The direction of a directional light is set as a 3D vector self.directionalLight.node().setDirection(Vec3(1, 1, -2)) # These settings are necessary for shadows to work correctly self.directionalLight.setY(6) dlens = self.directionalLight.node().getLens() dlens.setFilmSize(41, 21) dlens.setNearFar(50, 75) self.render.setLight(self.directionalLight) self.color = self.directionalLight.node().getColor() h, s, b = colorsys.rgb_to_hsv(self.color[0], self.color[1], self.color[2]) brightness = self.clamp(b + 0) r, g, b = colorsys.hsv_to_rgb(h, s, brightness) self.directionalLight.node().setColor((r, g, b, 1)) self.lightSourceSphere = self.loader.loadModel('models/sphere') self.lightSourceSphere.setColor((1, 1, 1, 1)) self.lightSourceSphere.setPos(0,STAGE_HEIGHT+4,3) self.lightSourceSphere.setScale(.25) self.lightSource = self.lightSourceSphere.attachNewNode(PointLight("lightSource")) self.lightSource.node().setAttenuation(Vec3(1, 0.04, 0.1)) self.lightSource.node().setColor((1, 1, 1, 1)) self.lightSource.node().setSpecularColor((1, 1, 1, 1)) self.render.setLight(self.lightSource) def homeInitial(self): global gameStart global returnHome global tryAgain gameStart = False tryAgain = False returnHome = False self.menuBG.reparentTo(self.render) myTexture = self.loader.loadTexture('tex/home.jpg') self.menuBG.setTexture(myTexture,1) self.buttonList[0].reparentTo(self.render) self.buttonList[0].setPosHpr(-6, STAGE_HEIGHT-1, 0, -90, 0, -105) taskMgr.remove("homeTask") # @UndefinedVariable self.menu = taskMgr.add(self.homeTask, "homeTask") # @UndefinedVariable self.menu.last = 0 def homeTask(self, task): global gameStart if pointable_finger is None: return Task.cont for i in range(len(self.buttonList)): buttonPressed = Vec3(1,1,1) for f in range(self.cHandler.getNumEntries()): entry = self.cHandler.getEntry(f) tipName = entry.getIntoNode().getName() name = entry.getFromNode().getName() if name == "collider_button" and tipName == fingerTip[pointable_finger.type]: if self.buttonPress(entry, i): buttonPressed= (Vec3(1.1,1.1,1.1)) self.buttonList[i].setScale(buttonPressed) if gameStart: self.stage.reparentTo(self.render) self.buttonList[0].detachNode() self.menuBG.detachNode() self.gameInitial(len(picture_names), True) taskMgr.remove("inGameTask") # @UndefinedVariable self.inGameTaskLoop = taskMgr.add(self.inGameTask, "inGameTask") # @UndefinedVariable self.inGameTaskLoop.last = 0 gameStart = False return Task.done else: return Task.cont def scoreInitial(self): global gameStart global returnHome global tryAgain global answer global renderedCube global score global question_list question_list.clear() gameStart = False tryAgain = False returnHome = False scoreCubes = [] for i in range(len(renderedCube)): taskMgr.remove("physicsTask_%i" % (i)) # @UndefinedVariable if len(answer)>i: self.cargos[i][0].removeNode() tempCubeList[i][0].removeNode() self.image.removeNode() self.cargos.clear() renderedCube.clear() tempCubeList.clear() answer.clear() self.train.setPosHpr(16, STAGE_HEIGHT+0.3, 12, 90, 180, 90) self.train.detachNode() self.stage.detachNode() self.tracks.detachNode() self.timer.setText("") self.score.setText("") self.menuBG.reparentTo(self.render) myTexture = self.loader.loadTexture('tex/score.jpg') self.menuBG.setTexture(myTexture,1) for i in range(len(str(score))): temp = cubeList.index(str(score)[i]) scoreCubes.append(loader.loadModel("models/cube"))# @UndefinedVariable scoreCubes[i].reparentTo(self.render) # @UndefinedVariable scoreCubes[i].setPos(3.5+(int(i)*2.4),STAGE_HEIGHT+2.5-(i*0.1),-1) scoreCubes[i].setHpr(0,-2,-15) cubeMesh = scoreCubes[i].find("**/mesh_cube") myTexture = self.loader.loadTexture('cubes/tex_%i.jpg' %(temp)) cubeMesh.setTexture(myTexture,1) self.buttonList[1].reparentTo(self.render) self.buttonList[1].setPosHpr(-7, STAGE_HEIGHT-5, 0, -90, 0, -105) self.buttonList[2].reparentTo(self.render) self.buttonList[2].setPosHpr(8.5, STAGE_HEIGHT-5, 0, -90, 0, -105) taskMgr.remove("scoreTask") # @UndefinedVariable self.scoreLoop = taskMgr.add(self.scoreTask, "scoreTask", extraArgs = [scoreCubes], appendTask=True) # @UndefinedVariable self.scoreLoop.last = 0 score = 0 def scoreTask(self, scoreCubes, task): global tryAgain global returnHome for i in range(len(self.buttonList)): buttonPressed = Vec3(1,1,1) for f in range(self.cHandler.getNumEntries()): entry = self.cHandler.getEntry(f) tipName = entry.getIntoNode().getName() name = entry.getFromNode().getName() if name == "collider_button" and tipName == fingerTip[pointable_finger.type]: if self.buttonPress(entry, i): buttonPressed= (Vec3(1.1,1.1,1.1)) self.buttonList[i].setScale(buttonPressed) if tryAgain: self.stage.reparentTo(self.render) for f in scoreCubes: f.removeNode() scoreCubes.clear() self.buttonList[1].detachNode() self.buttonList[2].detachNode() self.menuBG.detachNode() self.gameInitial(len(picture_names),True) taskMgr.remove("inGameTask") # @UndefinedVariable self.inGameTaskLoop = taskMgr.add(self.inGameTask, "inGameTask") # @UndefinedVariable self.inGameTaskLoop.last = 0 return task.done elif returnHome: for f in scoreCubes: f.removeNode() scoreCubes.clear() self.menuBG.detachNode() self.buttonList[1].detachNode() self.buttonList[2].detachNode() self.homeInitial() return task.done else: return task.cont def gameInitial(self, question, englishGame): global answer global gameStart global returnHome global tryAgain global score global question_list gameStart = False tryAgain = False returnHome = False tempQuestion= "" self.score.setText("Score: %i" % (score)) self.ballAccelV = GRAVITY self.tracks.reparentTo(self.render) self.trainV = Vec3(0,0,0) self.train.reparentTo(self.render) self.trainV = Vec3(-5,0,0) if(englishGame): temp = randint(0, question-1) while temp in question_list: temp = randint(0, question-1) tempQuestion = picture_names[temp][:picture_names[temp].index('.')] print(tempQuestion) question_list.append(temp) self.image = self.loadImageAsPlane("images/%s" % (picture_names[temp])) self.image.reparentTo(self.render) self.image.setScale(self.image.getScale()*1.2) self.image.setPosHpr(0,STAGE_HEIGHT+3.5,-11, 90, 270, 90) self.image.setTransparency(TransparencyAttrib.MAlpha) self.image.setAlphaScale(1) self.cargos = [[self.loader.loadModel("models/cargo"), -1] for i in range(len(tempQuestion))] # @UndefinedVariable for i in range(len(self.cargos)): self.cargos[i][0].reparentTo(self.render) self.cargos[i][0].setScale(1,0.3,0.3) self.cargos[i][0].setScale(1,0.32,0.32) if i == 0:self.cargos[i][0].setPosHpr(self.train.getX()+2.5, STAGE_HEIGHT+0.3, 12, 90, 180, 90) else: self.cargos[i][0].setPosHpr(self.cargos[i-1][0].getX()+2, STAGE_HEIGHT+0.3, 12, 90, 180, 90) taskMgr.remove("trainMovingTask") # @UndefinedVariable self.trainEnter = taskMgr.add(self.trainMovingTask, "trainMovingTask", extraArgs = [True], appendTask=True ) # @UndefinedVariable self.trainEnter.last = 0 usedPos = random.sample(range(0, 10), 10) for i in range(10): if i<len(tempQuestion): temp = cubeList.index(tempQuestion[i]) answer.append(temp) self.assignCube(temp, i, usedPos) else: temp = randint(10,35) while temp in answer: temp = randint(10,35) self.assignCube(temp, i, usedPos) else: temp = randint(0, question-1) while temp in question_list: temp = randint(0, question-1) tempQuestion = picture_names[temp][:picture_names[temp].index('.')] question_list.append(temp) self.image = self.loadImageAsPlane("images/%s" % (picture_names[temp])) self.image.reparentTo(self.render) self.image.setScale(self.image.getScale()*1.2) self.image.setPosHpr(0,STAGE_HEIGHT+3.5,-11, 90, 270, 90) self.image.setTransparency(TransparencyAttrib.MAlpha) self.image.setAlphaScale(1) self.cargos = [[self.loader.loadModel("models/cargo"), -1] for i in range(len(tempQuestion))] # @UndefinedVariable for i in range(len(self.cargos)): self.cargos[i][0].reparentTo(self.render) self.cargos[i][0].setScale(1,0.3,0.3) self.cargos[i][0].setScale(1,0.32,0.32) if i == 0:self.cargos[i][0].setPosHpr(self.train.getX()+2.5, STAGE_HEIGHT+0.3, 12, 90, 180, 90) else: self.cargos[i][0].setPosHpr(self.cargos[i-1][0].getX()+2, STAGE_HEIGHT+0.3, 12, 90, 180, 90) taskMgr.remove("trainMovingTask") # @UndefinedVariable self.trainEnter = taskMgr.add(self.trainMovingTask, "trainMovingTask", extraArgs = [True], appendTask=True ) # @UndefinedVariable self.trainEnter.last = 0 usedPos = random.sample(range(0, 10), 10) for i in range(10): if i<len(tempQuestion): temp = cubeList.index(tempQuestion[i]) answer.append(temp) self.assignCube(temp, i, usedPos) else: temp = randint(10,35) while temp in answer: temp = randint(10,35) self.assignCube(temp, i, usedPos) def assignCube(self, temp, i, usedPos): global renderedCube global tempCubeList pos = len(tempCubeList) renderedCube.append(temp) tempCubeList.append([render.attachNewNode("cubeRoot_%i" % (temp)), Vec3(randint(-3, 3),7,randint(-3, 3))]) # @UndefinedVariable self.cubeCreator(pos,temp) tempCubeList[pos][0].reparentTo(self.render) tempCubeList[pos][0].setPos(cubesPosList[usedPos[i]]) tempCubeList[pos][0].setHpr(0,0,0) taskMgr.remove("physicsTask_%i" % (i)) # @UndefinedVariable self.physicsTaskLoop = taskMgr.add(self.physicsTask, "physicsTask_%i" % (i),extraArgs = [pos], appendTask=True) # @UndefinedVariable self.physicsTaskLoop.last = 0 def inGameTask(self, task): global gameSuccess global score global gameInter global timer secs = timer - int(task.time) mins = int(secs/60) self.timer.setText('{:02d}:{:02d}'.format(mins, secs%60)) if secs <= -1: #score= score+22 gameInter= False self.errorMsg.setText("") taskMgr.remove("trainMovingTask") # @UndefinedVariable self.scoreInitial() return Task.done if gameInter: return Task.cont fail = True gameSuccess = True for i in range(len(answer)): if self.cargos[i][1] == -1: fail = False if answer[i] != renderedCube[self.cargos[i][1]]: gameSuccess = False if gameSuccess: self.errorMsg.setText("Success") score = score +1 self.score.setText("Score: %i" % (score)) gameInter = True taskMgr.remove("trainMovingTask") # @UndefinedVariable self.trainLeaving = taskMgr.add(self.trainMovingTask, "trainMovingTask", extraArgs = [False], appendTask=True ) # @UndefinedVariable self.trainLeaving.last = 0 elif fail: self.errorMsg.setText("FAIL") else: self.errorMsg.setText("") return Task.cont def buttonPress(self, colEntry, button): global gameStart global returnHome global tryAgain if colEntry.getFromNodePath().getPos(self.buttonList[button]).length() == 0: norm = colEntry.getSurfaceNormal(render) * -1 # The normal of the hand # @UndefinedVariable handCurSpeed = self.handV.length() # The current hand speed hitDir = colEntry.getSurfacePoint(render) - self.buttonList[button].getPos() # @UndefinedVariable hitDir.normalize() hitAngle = self.dotProduct(norm, hitDir) if hitAngle > 0 and handCurSpeed>100 and self.handV[2]<-1: if button == 0: gameStart = True elif button == 1: returnHome = True elif button == 2: tryAgain = True return True else: return False def trainMovingTask(self, arriving, task): global tempCubeList global answer global renderedCube global gameInter dt = task.time - task.last task.last = task.time if dt > .1: return Task.cont if arriving: if self.train.getX()<0: self.trainV += Vec3(1,0,0)* dt * trainAccel[len(answer)] self.train.setPos(self.train.getPos() + (self.trainV * dt)) for f in self.cargos: f[0].setPos(f[0].getPos() + (self.trainV * dt)) if self.trainV[0]>0: self.trainV = Vec3(0,0,0) return Task.done else: self.trainV += Vec3(-1,0,0)* dt * trainAccel[len(answer)] self.train.setPos(self.train.getPos() + (self.trainV * dt)) for i in range(len(answer)): newPos = self.cargos[i][0].getPos() + (self.trainV * dt) self.cargos[i][0].setPos(newPos) tempCubeList[self.cargos[i][1]][0].setPos(newPos+Vec3(0,1.4,0)) if self.cargos[len(answer)-1][0].getX()<-16: for i in range(len(renderedCube)): if len(answer)>i: self.cargos[i][0].remove_node() tempCubeList[i][0].removeNode() self.image.removeNode() tempCubeList.clear() renderedCube.clear() self.cargos.clear() answer.clear() gameInter = False self.train.setPosHpr(16, STAGE_HEIGHT+0.3, 12, 90, 180, 90) self.gameInitial(len(picture_names),True) return task.done return Task.cont def physicsTask(self, cube, task): global trigger_pinch global trigger_pinch_threshold global lastPinchFrame global pinch_cube if gameInter: return task.done isLoaded = False dt = task.time - task.last task.last = task.time if dt > .1: return Task.cont df = 0 if trigger_pinch and cube == pinch_cube: lastPinchFrame = task.time trigger_pinch_threshold = True else: df = task.time - lastPinchFrame if cube == pinch_cube: if df < 0.1 and trigger_pinch_threshold is True and trigger_pinch is False: cubeP = tempCubeList[pinch_cube][0].getPos() for f in self.cargos: cargoP = f[0].getPos() if cubeP[0]>cargoP[0]-1 and cubeP[0]<cargoP[0]+1 and cubeP[1] > cargoP[1] and cubeP[1] < cargoP[1]+4 and cubeP[2]>cargoP[2]-3 and cubeP[2]<cargoP[2]+3: tempCubeList[pinch_cube][0].setPos(cargoP+Vec3(0,1.4,0)) lastPinchFrame = 0 trigger_pinch_threshold = False f[1] = pinch_cube pinch_cube = -1 if trigger_pinch_threshold: currentPos = self.thowingTask(False) if currentPos.length() >0: tempCubeList[cube][0].setPos(currentPos) else: lastPinchFrame = 0 trigger_pinch_threshold = False elif df >= 0.1 and trigger_pinch_threshold is True: lastPinchFrame = 0 trigger_pinch_threshold = False pinch_cube = -1 tempCubeList[cube][1] = self.thowingTask(True) for f in self.cargos: if f[1] == cube: isLoaded=True if isLoaded : return Task.cont elif cube == pinch_cube and trigger_pinch_threshold: return Task.cont #if trigger_pinch_threshold is False: for i in range(self.cHandler.getNumEntries()): entry = self.cHandler.getEntry(i) name = entry.getIntoNode().getName() if name == "palm_L_collider": self.handCollideHandler(entry, cube) elif name == "palm_R_collider": self.handCollideHandler(entry, cube) elif name == "floor": self.wallCollideHandler(entry, cube) elif name == "wall_B": self.wallCollideHandler(entry, cube) elif name == "wall_F": self.wallCollideHandler(entry, cube) elif name == "wall_R": self.wallCollideHandler(entry, cube) elif name == "wall_L": self.wallCollideHandler(entry, cube) elif name == "collider_cube": self.cubeCollideHandler(entry, cube) elif trigger_pinch_threshold is False: self.handCollideHandler(entry, cube) tempCubeList[cube][1] += self.ballAccelV * dt * ACCEL if tempCubeList[cube][1].lengthSquared() > MAX_SPEED_SQ: tempCubeList[cube][1].normalize() tempCubeList[cube][1] *= MAX_SPEED tempCubeList[cube][0].setPos(tempCubeList[cube][0].getPos() + (tempCubeList[cube][1] * dt)) return Task.cont def thowingTask(self, thowing): global pinch_position global pinch_finger self.frame = self.leap.frame() temp = self.frame.hands[pinch_finger[0]].palm_velocity releaseHandV = Vec3((temp[0], temp[1], temp[2]))/self.scale thumb_tip = self.frame.hands[pinch_finger[0]].fingers[0].bone(3).next_joint joint_position = self.frame.hands[pinch_finger[0]].fingers[pinch_finger[1]].bone(3).next_joint distance = thumb_tip - joint_position release_position = joint_position + Vector(distance[0]/2, distance[1]/2, distance[2]/2) release_position = Vec3((release_position[0], release_position[1], release_position[2]))/self.scale if thowing is True: thowingV = release_position-pinch_position pinch_finger = [-1,-1] return releaseHandV else: return release_position def dotProduct(self, pos1, pos2): v1 = (round(pos1[0], 8),round(pos1[1], 8),round(pos1[2], 8)) v2 = (round(pos2[0], 8),round(pos2[1], 8),round(pos2[2], 8)) v1_u = v1 / numpy.linalg.norm(v1) v2_u = v2 / numpy.linalg.norm(v2) return numpy.dot(v1_u, v2_u) def cubeCollideHandler(self, colEntry, cube): if colEntry.getFromNodePath().getPos(tempCubeList[cube][0]).length() == 0: ballV=Vec3(0,0,0) tempCubeList[cube][1] = ballV disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) # @UndefinedVariable newPos = tempCubeList[cube][0].getPos() + disp tempCubeList[cube][0].setPos(newPos) def handCollideHandler(self, colEntry, cube): if colEntry.getFromNodePath().getPos(tempCubeList[cube][0]).length() == 0: norm = colEntry.getSurfaceNormal(render) * -1 # The normal of the hand # @UndefinedVariable curSpeed = tempCubeList[cube][1].length() # The current ball speed inVec = tempCubeList[cube][1] / curSpeed # The direction of ball travel velAngle = self.dotProduct(norm, inVec) totalV = Vec3(tempCubeList[cube][1][0]+self.handV[0],tempCubeList[cube][1][1]+self.handV[1],tempCubeList[cube][1][2]+self.handV[2]) ballV=Vec3(totalV[0]/10,totalV[1]/10,totalV[2]/10) if velAngle > 0: tempCubeList[cube][1] = ballV disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) # @UndefinedVariable newPos = tempCubeList[cube][0].getPos() + disp tempCubeList[cube][0].setPos(newPos) def wallCollideHandler(self, colEntry, cube): if colEntry.getFromNodePath().getPos(tempCubeList[cube][0]).length() == 0: ballV=Vec3(-tempCubeList[cube][1][0],tempCubeList[cube][1][1],tempCubeList[cube][1][2]) if colEntry.getIntoNode().getName() == "wall_F" or colEntry.getIntoNode().getName() == "wall_B": ballV=Vec3(tempCubeList[cube][1][0],tempCubeList[cube][1][1],-tempCubeList[cube][1][2]) elif colEntry.getIntoNode().getName() == "floor": ballV=Vec3(tempCubeList[cube][1][0]/2,-tempCubeList[cube][1][1]/2,tempCubeList[cube][1][2]/2) if ballV[2]<0.01: ballV[2] =0 tempCubeList[cube][1] = ballV disp = (colEntry.getSurfacePoint(render)- colEntry.getInteriorPoint(render)) # @UndefinedVariable newPos = tempCubeList[cube][0].getPos() + disp tempCubeList[cube][0].setPos(newPos) def handUpdater(self, task): self.frame = self.leap.frame() global trigger_pinch pointables = self.frame.pointables trigger_pinch = False rightHand=None if len(self.frame.hands)>0: front_pointable = pointables.frontmost for hand in self.frame.hands: if(hand.is_left and rightHand==None): self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, self.frame.hands[0], 0, front_pointable) rightHand=False elif(hand.is_right and rightHand==None): self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, self.frame.hands[0], 0, front_pointable) rightHand=True if(len(self.frame.hands)>1): if(rightHand): self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, self.frame.hands[1], 0, front_pointable) else: self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, self.frame.hands[1], 0, front_pointable) else: if(rightHand): self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, None, None, front_pointable) else: self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, None, None, front_pointable) else: self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, None, None, None) self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, None, None, None) rightHand=None return Task.cont def plotHand(self, palm, fingerTips, fingerMiddles, fingerbases, leapHand, pinchHand, front_pointable): global pinch_finger global pointable_position global pointable_finger usedFingers = 0 palmValid = False if(leapHand and leapHand.is_valid): palmValid = True palm_position, palm_quat = self.calcTrafo(leapHand.palm_position, -leapHand.palm_normal, self.ez, self.scale) palm.setPos(palm_position) #print(palm_position[2]) palm.setQuat(palm_quat) thumb_tip = leapHand.fingers[0].bone(3).next_joint self.handV=Vec3(leapHand.palm_velocity[0], leapHand.palm_velocity[1], leapHand.palm_velocity[2]) for i in range(len(leapHand.fingers)): lf = leapHand.fingers[i] if lf.is_valid: if i>0 and len(answer) >0: self.updatePinch(leapHand, thumb_tip, lf) if trigger_pinch is True: pinch_finger[0] = pinchHand pinch_finger[1] = i bf = fingerTips[usedFingers] bm = fingerMiddles[usedFingers] bb = fingerbases [usedFingers] usedFingers += 1 bf.reparentTo(self.render) tip_position, tip_quat = self.calcTrafo(lf.bone(3).next_joint, -lf.bone(3).direction, self.ex, self.scale) bf.setPos(tip_position) bf.setQuat(tip_quat) if str(front_pointable) == str(lf): pointable_position = tip_position pointable_finger = lf bm.reparentTo(self.render) m1 = lf.bone(3).next_joint+lf.bone(3).direction*30 m2 = lf.bone(2).next_joint-m1 mid_position, mid_quat = self.calcTrafo(m1, lf.bone(2).direction, self.ex, self.scale) #mid_position, mid_quat = self.calcTrafo(m1, m2, self.ex, self.scale) bm.setPos(mid_position) bm.setQuat(mid_quat) bb.reparentTo(self.render) b1 = lf.bone(2).next_joint+lf.bone(2).direction*30 b2 = leapHand.palm_position-b1 #base_position, base_quat = self.calcTrafo(b1, lf.bone(1).direction, self.ex, self.scale) base_position, base_quat = self.calcTrafo(b1, b2, self.ex, self.scale) bb.setPos(base_position) bb.setQuat(base_quat) if palmValid: palm.reparentTo(self.render) else: palm.detachNode() for i in range(usedFingers,5): fingerTips[i].detachNode() fingerMiddles[i].detachNode() fingerbases[i].detachNode() def updatePinch(self, hand, tip, finger): global tempCubeList global trigger_pinch global pinch_position global pinch_cube joint_position = finger.bone(3).next_joint distance = tip - joint_position if distance.magnitude < 35: trigger_pinch = True pinch_position = joint_position + Vector(distance[0]/2, distance[1]/2, distance[2]/2) pinch_position = Vec3((pinch_position[0], pinch_position[1], pinch_position[2]))/self.scale if trigger_pinch is True: temp = 1.5 for i in range(len(tempCubeList)): distance = pinch_position - tempCubeList[i][0].getPos() distance = Vector(distance[0], distance[1], distance[2]) if distance.magnitude<temp: temp = distance.magnitude self.unLoadedCube(i) pinch_cube = i if temp < 1.5: tempCubeList[pinch_cube][0].setPos(pinch_position) trigger_pinch = True else: trigger_pinch = False def unLoadedCube(self, cube): for f in self.cargos: if f[1] == cube: f[1]=-1 def calcTrafo(self, leapPosition, leapDirection, e_i, scale): position = Vec3((leapPosition[0], leapPosition[1], leapPosition[2]))/scale direction = Vec3((leapDirection[0], leapDirection[1], leapDirection[2])).normalized() ang = e_i.angleDeg(direction) axis = e_i.cross(direction).normalized() return position, LRotationf(axis, ang)
class Usuario(object): ''' Usuario ''' def __init__(self): self.habilitado = False self.estaMovendo = False self.estaRodando = False self.timeIniMover = 0 self.timeIniRodar = 0 self.keyMap = { TECLA_esquerda: EVENT_up, TECLA_direita: EVENT_up, TECLA_frente: EVENT_up, TECLA_traz: EVENT_up } self.login = None self.senha = None self.nick = None self.vida_real = None self.vida_total = None self.mana_real = None self.mana_total = None self.forca = None self.velocidade = None self.velocidade_atack = None self.key = None self.addr = None self.login = None pandaFileModelo = get_path_modelo("ralph") self.__modelo = Actor(pandaFileModelo) self.__modelo.reparentTo(render) self.__modelo.setScale(SCALE_MODELOS) modeloStartPos = vinerWorld.mapa.modelo.find("**/start_point").getPos() self.set_pos(modeloStartPos) self.__setup_collision() def get_x(self): return self.__modelo.getX() def get_y(self): return self.__modelo.getY() def get_z(self): return self.__modelo.getZ() def get_h(self): return self.__modelo.getH() def get_pos(self): return self.__modelo.getPos() def set_x(self, x): self.__modelo.setX(x) def set_y(self, y): self.__modelo.setY(y) def set_z(self, z): self.__modelo.setZ(z) def set_h(self, h): self.__modelo.setH(h) def set_pos(self, pos): self.__modelo.setPos(pos) def get_dados(self): return [ self.key, self.nick, self.vida_real, self.vida_total, self.mana_real, self.mana_total, self.forca, self.velocidade, self.velocidade_atack, self.get_x(), self.get_y(), self.get_z(), self.get_h(), ] def stop_task_movimentacao(self): taskMgr.remove(self.key) def inicia_task_movimentacao(self): if self.key != "": taskMgr.add(self.__task_movimentacao, self.key, sort=1) def __setup_collision(self): #Colisao self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 5) 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.__modelo.attachNewNode( self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() base.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) #Colisao def __task_movimentacao(self, task): dt = globalClock.getDt() startpos = self.__modelo.getPos() #rodar usuario if self.keyMap[TECLA_esquerda] == EVENT_down and self.keyMap[ TECLA_direita] == EVENT_up: if time.time() < self.timeIniRodar + 4: self.estaRodando = True self.__modelo.setH(self.__modelo, ((self.velocidade * 5) * dt)) else: h = self.get_h() vinerOnline.envia_pacote_todos( 1, ACAO_CLIENT_rodar, [self.key, TECLA_esquerda, EVENT_up, h]) self.estaRodando = False self.keyMap[TECLA_esquerda] = EVENT_up elif self.keyMap[TECLA_direita] == EVENT_down and self.keyMap[ TECLA_esquerda] == EVENT_up: if time.time() < self.timeIniRodar + 4: self.estaRodando = True self.__modelo.setH(self.__modelo, ((self.velocidade * 5) * dt) * -1) else: h = self.get_h() vinerOnline.envia_pacote_todos( 1, ACAO_CLIENT_rodar, [self.key, TECLA_direita, EVENT_up, h]) self.estaRodando = False self.keyMap[TECLA_direita] = EVENT_up elif self.estaRodando: self.estaRodando = False #rodar usuario #mover usuario if self.keyMap[TECLA_frente] == EVENT_down and self.keyMap[ TECLA_traz] == EVENT_up: if time.time() < self.timeIniMover + 4: self.estaMovendo = True self.__modelo.setY(self.__modelo, ((self.velocidade * 2) * dt) * -1) else: x = self.get_x() y = self.get_y() z = self.get_z() vinerOnline.envia_pacote_todos( 1, ACAO_CLIENT_mover, [self.key, TECLA_frente, EVENT_up, x, y, z]) self.estaMovendo = False self.keyMap[TECLA_frente] = EVENT_up elif self.keyMap[TECLA_traz] == EVENT_down and self.keyMap[ TECLA_frente] == EVENT_up: if time.time() < self.timeIniMover + 4: self.estaMovendo = True self.__modelo.setY(self.__modelo, (self.velocidade * dt)) else: x = self.get_x() y = self.get_y() z = self.get_z() vinerOnline.envia_pacote_todos( 1, ACAO_CLIENT_mover, [self.key, TECLA_traz, EVENT_up, x, y, z]) self.estaMovendo = False self.keyMap[TECLA_traz] = EVENT_up elif self.estaMovendo: self.estaMovendo = False #mover usuario #se esta moventdo trata colisao if self.estaMovendo: base.cTrav.traverse(render) if self.ralphGroundHandler.getNumEntries() == 1: entry = self.ralphGroundHandler.getEntry(0) if entry.getIntoNode().getName() == "terrain": self.__modelo.setZ(entry.getSurfacePoint(render).getZ()) else: self.__modelo.setPos(startpos) #se esta moventdo trata colisao return task.cont
class World(DirectObject): def __init__(self): self.itemID = 0 self.switchState = True self.iAktion = "E" self.altIPos = [0,0] self.switchCam = False self.kampf = Battle.Kampf() self.itemDa = False self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0} base.win.setClearColor(Vec4(0,0,0,1)) self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) self.environ.setPos(0,0,0) self.spieler = Players.Player(Actor("models/box.x")) self.spieler.actor.reparentTo(render) spielerStartPos = (-107.575, 26.6066, -0.490075) self.spieler.actor.setPos(spielerStartPos) self.textObjectSpieler = OnscreenText(text = self.spieler.name+": "+str(self.spieler.energie)+"/"+str(self.spieler.maxenergie)+" HP", pos = (-0.90, -0.98), scale = 0.07, fg = (1,0,0,1)) # Erstellt Gegner self.gegnerStartPos = ([(-39.1143569946,25.1781406403,-0.136657714844), (-102.375793457,-30.6321983337,0.0), (-56.927986145, -34.6329650879, -0.16748046875), (-79.6673126221,30.8231620789,2.89721679688), (-4.37648868561,30.5158863068,2.18450927734), (22.6527004242,4.99837779999,3.11364746094), (-23.8257598877,-7.87773084641,1.36920166016), (-80.6140823364,19.5769443512,4.70764160156), (-75.0773696899,-15.2991075516,6.24676513672) ]) gegnerPos = random.choice(self.gegnerStartPos) self.gegnerErstellen(gegnerPos) self.textObjectGegner = OnscreenText(text = str(self.gegner.name)+": "+str(self.gegner.energie)+"/"+str(self.gegner.maxenergie)+" HP", pos = (0.90, -0.98), scale = 0.07, fg = (1,0,0,1)) self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) self.item = None # Handling der Usereingaben für Bewegung 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("i", self.setKey, ["inventar",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]) self.accept("e", self.iAktionsHandler,["e"]) self.accept("v", self.iAktionsHandler,["v"]) self.accept("w", self.iAktionsHandler,["w"]) taskMgr.add(self.move,"moveTask") taskMgr.add(self.erkenneKampf,"Kampferkennung") taskMgr.add(self.screentexts,"Screentexte") # Menü erstellen self.createMenu() # Kameraeinstellungen base.disableMouse() base.camera.setPos(self.spieler.actor.getX(),self.spieler.actor.getY()+10,2) self.collisionInit(); self.setAI() # Licht 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)) # Hintergrund (Himmel) self.setupSkySphere() def iAktionsHandler(self,key): if key == "e": self.iAktion = "E" elif key == "w": self.iAktion = "W" elif key == "v": self.iAktion = "V" def collisionInit(self): # Kollisionserkennung, um auf dem Boden zu laufen. Der Collisionray # erkennt die Hoehe des Gelaendes und wenn ein Objekt da ist, wird # die Bewegung als illegal gewertet. self.cTrav = CollisionTraverser() self.spielerGroundRay = CollisionRay() self.spielerGroundRay.setOrigin(0,0,1000) self.spielerGroundRay.setDirection(0,0,-1) self.spielerGroundCol = CollisionNode('spielerRay') self.spielerGroundCol.addSolid(self.spielerGroundRay) self.spielerGroundCol.setFromCollideMask(BitMask32.bit(0)) self.spielerGroundCol.setIntoCollideMask(BitMask32.allOff()) self.spielerGroundColNp = self.spieler.actor.attachNewNode(self.spielerGroundCol) self.spielerGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.spielerGroundColNp, self.spielerGroundHandler) 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) self.gegnerGroundRay = CollisionRay() self.gegnerGroundRay.setOrigin(0,0,1000) self.gegnerGroundRay.setDirection(0,0,-1) self.gegnerGroundCol = CollisionNode('gegnerRay') self.gegnerGroundCol.addSolid(self.gegnerGroundRay) self.gegnerGroundCol.setFromCollideMask(BitMask32.bit(0)) self.gegnerGroundCol.setIntoCollideMask(BitMask32.allOff()) self.gegnerGroundColNp = self.gegner.actor.attachNewNode(self.gegnerGroundCol) self.gegnerGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.gegnerGroundColNp, self.gegnerGroundHandler) def setupSkySphere(self): self.skysphere = loader.loadModel("models/LinearPinkSkySphere.bam") # Textur für den Himmel laden self.sky_tex = loader.loadTexture("Images/Sterne.jpg") # Himmel Textur konfigurieren self.skysphere.setTexture(self.sky_tex, 1) self.skysphere.setBin('background', 1) self.skysphere.setDepthWrite(0) self.skysphere.reparentTo(render) self.skysphere.setScale(40) taskMgr.add(self.skysphereTask, "SkySphere Task") def skysphereTask(self, task): self.skysphere.setPos(base.camera, 0, 0, 0) return task.cont def createMenu(self): self.createFrame() itemListe = self.spieler.inventar.anzeigen(1) standardpos = [0.18, 0.98, 0.83] self.buttonListe = [] beutelLabel = DirectLabel(text = itemListe[0][0], pos = (0.18, 0.98, 0.95), scale = 0.07, text_fg = (1,0,0,1), text_bg = (0, 50, 50, 1), textMayChange = 1) del itemListe [0][0] for zeile in range(4): for i in range(0,5): Button = DirectButton(text = itemListe [zeile] [i], pos = standardpos, scale = 0.07, text_fg = (1,0,0,1), text_bg = (0, 50, 50, 1), textMayChange = 1, extraArgs = [zeile,i], command = self.inventarAktion) self.buttonListe.append (Button) standardpos[0] += 0.25 standardpos[0] = 0.18 standardpos[2] -= 0.15 def createFrame(self): self.myFrame = DirectFrame(frameColor=(0, 50, 50, 0.5), frameSize=(-1, 1, -.7, 1), pos=(1, -1, 1)) def inventarAktion(self,zeile,spalte): if self.iAktion == "E": self.spieler.inventar.entfernen(1,[zeile,spalte]) self.myFrame.destroy() i = 0 for item in self.buttonListe: self.buttonListe [i].destroy() i += 1 del self.buttonListe[:] self.createMenu() elif self.iAktion == "W": self.altIPos = [zeile,spalte] elif self.iAktion == "V": self.spieler.inventar.verschieben(1,1,self.altIPos,[zeile,spalte]) self.myFrame.destroy() i = 0 for item in self.buttonListe: self.buttonListe [i].destroy() i += 1 del self.buttonListe[:] self.createMenu() # Erkennt den Status der Eingabe def setKey(self, key, value): self.keyMap[key] = value def screentexts(self,task): self.textObjectSpieler.destroy() self.textObjectSpieler = OnscreenText(text = self.spieler.name+": "+str(self.spieler.energie)+"/"+str(self.spieler.maxenergie)+" HP", pos = (-0.90, -0.98), scale = 0.07, fg = (1,0,0,1)) self.textObjectGegner.destroy() if self.kampf.active == True: self.textObjectGegner = OnscreenText(text = str(self.gegner.name)+": "+str(self.gegner.energie)+"/"+str(self.gegner.maxenergie)+" HP", pos = (0.90, -0.98), scale = 0.07, fg = (1,0,0,1)) else: self.textObjectGegner = OnscreenText(text = "Kein Gegner vorhanden", pos = (0.90, -0.98), scale = 0.07, fg = (1,0,0,1)) return Task.cont def camera(self): # cam-left Key: Kamera nach links # cam-right Key: Kamera nach rechts base.camera.lookAt(self.spieler.actor) 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()) # Wenn die Kamera zu weit weg ist, zoom heran. # Wenn die Kamera zu nah dran ist, zoom weg. camvec = self.spieler.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 # Haelt die Kamera einen Schritt über dem Boden # oder zwei Schritte ueber dem Spieler, je nachdem, was groesser ist. 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.spieler.actor.getZ() + 2.0): base.camera.setZ(self.spieler.actor.getZ() + 2.0) # Die Kamera soll in die Richtung des Spielers gucken, aber auch # immer horizontal bleiben. self.floater.setPos(self.spieler.actor.getPos()) self.floater.setZ(self.spieler.actor.getZ() + 2.0) base.camera.lookAt(self.floater) def collisions(self,startpos): # Überprüfen auf Itemkollision if self.item <> None: if (self.item.actor.getX() - self.spieler.actor.getX() < 1 and self.item.actor.getY() - self.spieler.actor.getY() < 1 and self.item.actor.getZ() - self.spieler.actor.getZ() <1 and self.itemDa == True): self.itemDa = False self.item.actor.detachNode() self.spieler.inventar.einfuegen(self.item) self.myFrame.destroy() del self.buttonListe[:] self.createMenu() # Start der Kollisionserkennung self.cTrav.traverse(render) # Aendert die Z Koordinate des Spielers. Wenn er etwas trifft, bewegt # ihn entsprechend, wenn er nichts trifft, setzt die Koordinate # auf den Stand des letzten Frames self.dummyMethode(self.spielerGroundHandler, self.spieler.actor,startpos) def move(self,task): self.camera(); # Speichert die Startposition, damit der Spieler zurueckgesetzt # werden kann, sollte er irgendwo runterfallen startpos = self.spieler.actor.getPos() # Wenn einer der Move Keys gedrueckt wird, wird der Spieler # in die ensprechende Richtung bewegt if (self.keyMap["left"]!=0): self.spieler.actor.setH(self.spieler.actor.getH() + 150 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.spieler.actor.setH(self.spieler.actor.getH() - 150 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.spieler.actor.setY(self.spieler.actor, -12 * globalClock.getDt()) self.collisions(startpos); return Task.cont def gegnermove(self): # Zeit seit dem letzten Frame. Benötigt fuer # framerateunabhaengige Bewegung. elapsed = globalClock.getDt() startpos = self.gegner.actor.getPos() # Aendert die Z Koordinate des Gegners. Wenn er etwas trifft, bewegt # ihn entsprechend, wenn er nichts trifft, setzt die Koordinate # auf den Stand des letzten Frames self.cTrav.traverse(render) self.dummyMethode(self.gegnerGroundHandler, self.gegner.actor,startpos) self.gegner.actor.setP(0) if self.gegner.energie == 0: return Task.done else: return Task.cont def dummyMethode(self, handler, actor,startpos): entries = [] for i in range(handler.getNumEntries()): entry = handler.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"): actor.setZ(entries[0].getSurfacePoint(render).getZ()) else: actor.setPos(startpos) def setAI(self): # Erstellt die AI World self.AIworld = AIWorld(render) self.AIchar = AICharacter("gegner",self.gegner.actor, 100, 0.02, 1) self.AIworld.addAiChar(self.AIchar) self.AIbehaviors = self.AIchar.getAiBehaviors() self.AIbehaviors.wander(360, 0, 15, 1.0) #AI World update zum Tasknamager hinzufügen taskMgr.add(self.AIUpdate,"AIUpdate") # Update der AI World def AIUpdate(self,task): if self.kampf.active == False: self.AIworld.update() self.gegnermove() return Task.cont # Startet bei einem Abstand von 4 zwischen Spieler und Gegner einen Kampf def erkenneKampf(self,task): if (self.spieler.actor.getX() - self.gegner.actor.getX() < 4 and self.spieler.actor.getX() - self.gegner.actor.getX() > -4 and self.kampf.active == False): self.kampf.active = True self.startzeit = globalClock.getLongTime() if self.kampf.active == True: self.Kampf(self) if self.gegner.energie == 0: return Task.done else: return Task.cont def gegnerErstellen(self,pos): self.gegner = Monster.Goblin(Actor("models/box.x")) self.gegner.actor.reparentTo(render) self.gegner.actor.setPos(pos) self.gegnerAltPos = pos self.setAI() def gegnerTod(self): self.kampf.active = False itemPos = self.gegner.actor.getPos() self.gegner.actor.detachNode() self.item = Items.Axt() self.item.ID = self.itemID self.itemID += 1 self.itemDa = True self.item.actor.setScale(0.3) self.item.actor.reparentTo(render) self.item.actor.setPos(itemPos) gegnerNeuPos = random.choice(self.gegnerStartPos) while gegnerNeuPos == self.gegnerAltPos: gegnerNeuPos = random.choice(self.gegnerStartPos) self.gegnerErstellen(gegnerNeuPos) # Lässt Spieler und Gegner nach bestimmter Zeit Aktionen ausführen. Bei Tod des # Gegners wird ein neuer Gegner sowie ein Item generiert def Kampf(self,task): if ((int(globalClock.getLongTime()) - int(self.startzeit)) % 5 == 0 and self.kampf.active == True): erg = self.kampf.Kampf(self.spieler,self.gegner) self.spieler = erg[0] self.gegner = erg[1] self.startzeit -= 1 if self.spieler.energie == 0: sys.exit elif self.gegner.energie == 0: self.gegnerTod(); if self.startzeit <= 0: self.startzeit = globalClock.getLongTime()
class Grabber(object): def __init__( self, levitNP): """ A widget to position, rotate, and scale Panda 3D Models and Actors * handleM1 decides what to do with a mouse1 click -- object selection by calling handleSelection when the grabModel is inactive (hidden) -- object manipulation by calling handleManipulationSetup (sets the stage for and launches the dragTask) isHidden() when nothing is selected isDragging means not running collision checks for selection setup and LMB is pressed call handleM1 from another class to push control up in the program hierarchy (remove inner class calls) """ # TODO remove selection functionality from grabber and put it in a selector class self.levitorNP = levitNP # TODO remove this and use barebonesNP self.selected = None self.initialize() def initialize(self): """Reset everything except LevitorNP and selected, also called inside __init__""" self.notify = DirectNotify().newCategory('grabberErr') self.currPlaneColNorm = Vec3(0.0) self.isCameraControlOn = False self.isDragging = False self.isMultiselect = False self.grabScaleFactor = .075 self.currTransformDir = Point3(0.0) self.interFrameMousePosition = Point3(0.0) self.init3DemVal = Point3(0.0) # initCommVal holds the value before a command operation has taken place self.initialCommandTrgVal = None # To load the grabber model, this climbs up the absolute path to /barebones/ to gain access to the model folder self.grabModelNP = loader.loadModel(Filename.fromOsSpecific( ntpath.split( ntpath.split(inspect.stack()[0][1])[0] )[0]) + '/EditorModels/widget') self.grabModelNP.setPos(0.0, 0.0, 0.0) self.grabModelNP.setBin("fixed", 40) self.grabModelNP.setDepthTest(False) self.grabModelNP.setDepthWrite(False) self.transformOpEnum = Enum('rot, scale, trans') self.currTransformOperation = None # TODO For readability, use this enum in the nested if/else as was the original intent. self.grabInd = Enum('xRot, yRot, zRot, xScaler, yScaler, zScaler, xTrans, yTrans, zTrans, xyTrans, xzTrans, zyTrans, grabCore') grbrNodLst = [self.grabModelNP.find("**/XRotator;+h-s-i"), # 0 self.grabModelNP.find("**/YRotator;+h-s-i"), # 1 self.grabModelNP.find("**/ZRotator;+h-s-i"), # 2 end rotate self.grabModelNP.find("**/XScaler;+h-s-i"), # 3 self.grabModelNP.find("**/YScaler;+h-s-i"), # 4 self.grabModelNP.find("**/ZScaler;+h-s-i"), # 5 end scale self.grabModelNP.find("**/XTranslator;+h-s-i"), # 6 self.grabModelNP.find("**/YTranslator;+h-s-i"), # 7 self.grabModelNP.find("**/ZTranslator;+h-s-i"), # 8 end translate / end single dir operations self.grabModelNP.find("**/XYTranslator;+h-s-i"), # 9 self.grabModelNP.find("**/XZTranslator;+h-s-i"), # 10 self.grabModelNP.find("**/ZYTranslator;+h-s-i"), # 11 end bi-directional operations self.grabModelNP.find("**/WidgetCore;+h-s-i")] # 12 #Mat4.yToZUpMat() # change coordinate to z up grbrNodLst[12].getParent().setHprScale(0, 0, 0, 1, 1, -1) self.grabModelNP.setPythonTag('grabberRoot', grbrNodLst) self.grabModelNP.reparentTo(BBGlobalVars.bareBonesObj.levitorNP) self.grabModelNP.hide() #self.grabIntoBitMask = COLLISIONMASKS self.grabModelNP.setCollideMask(COLLISIONMASKS['default']) self.grabModelNP.setPythonTag('grabber', self) ############################################################################## # This whole section is the basics for setting up mouse selection # --The mouse events are added in the events section (next) # Create the collision node for the picker ray to add traverser as a 'from' collider self.grabberColNode = CollisionNode('grabberMouseRay') # Set the collision bitmask # TODO: define collision bitmask (let user define thiers? likely not) self.defaultBitMask = GeomNode.getDefaultCollideMask() self.grabberColNode.setFromCollideMask(self.defaultBitMask) self.grabberRayColNP = camera.attachNewNode(self.grabberColNode) # Create the grabberRay and add it to the picker CollisionNode self.grabberRay = CollisionRay(0.0, 0.0, 0.0, 0.0, 1.0, 0.0) self.grabberRayNP = self.grabberColNode.addSolid(self.grabberRay) # create a collision queue for the traverser self.colHandlerQueue = CollisionHandlerQueue() # Create collision traverser self.colTraverser = CollisionTraverser('grabberTraverser') # Set the collision traverser's 'fromObj' and handler # e.g. trav.addCollider( fromObj, handler ) self.colTraverser.addCollider(self.grabberRayColNP, self.colHandlerQueue) ############################################################ # setup event handling with the messenger # URGENT remove all of this messenger code throughout Grabber, especially the camera control # disable the mouse when the ~ is pressed (w/o shift) self.disableCamera() # disable camera control by the mouse messenger.accept('`', self, self.enableCamera) # enable camera control when the ~ key is pressed w/o shift messenger.accept('`-up', self, self.disableCamera) # disable camera control when the ~ key is released # handle mouse selection/deselection & manipulating the scene messenger.accept('mouse1', self, self.handleM1, persistent=1) # deselect in event handler taskMgr.add(self.scaleGrabber, 'scaleGrabber') # //////////////////////////////////////////////////////////////////// # comment out: good for debug info #taskMgr.add(self.watchMouseColl, name='grabberDebug') #this is only good for seeing types and hierarchy #self.grabModelNP.ls() #render.ls() # self.frames = 0 #remove # self.axis = loader.loadModel("zup-axis") # self.axis.reparentTo(self.grabModelNP) # self.axis.setScale(.15) # self.axis.setPos(0.0) # self.grabModelNP.append( 'newAttrib', self) # setattr( self.grabModelNP, 'newAttrib', self) def prepareForPickle(self): self.colTraverser = None # Traversers are not picklable self.defaultBitMask = None # BitMasks "..." # self.grabIntoBitMask = None # "..." self.colHandlerQueue = None # CollisonHandlerQueue "..." self.grabModelNP.removeNode() self.grabModelNP = None taskMgr.remove('scaleGrabber') def recoverFromPickle(self): self.initialize() if self.selected is not None: self.grabModelNP.setPos(render, self.selected.getPos(render)) self.grabModelNP.show() print "grabber sel ", self.selected, " isHidden() ", self.grabModelNP.isHidden(), '\n' taskMgr.add(self.scaleGrabber, 'scaleGrabber') #### May use to gain control over pickling. # def __repr__(self): # for pickling purposes # if self.colTraverser: # self.colTraverser = None # # dictrepr = dict.__repr__(self.__dict__) # dictrepr = '%r(%r)' % (type(self).__name__, dictrepr) # print dictrepr # REMOVE # return dictrepr def watchMouseColl(self, task): """ This exists for debugging purposes to perpetually watch mouse collisions. """ # TODO make this highlight objects under the mouse for predictable object selection/grabber operations self.colTraverser.showCollisions(render) if base.mouseWatcherNode.hasMouse() and False == self.isCameraControlOn: # This gives the screen coordinates of the mouse. 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.grabberRay.setFromLens(base.camNode, mPos.getX(), mPos.getY()) # traverses the graph for collisions self.colTraverser.traverse(render) return task.cont def scaleGrabber(self, task): if self.grabModelNP.isHidden(): return task.cont coreLst = self.grabModelNP.getPythonTag('grabberRoot') camPos = self.grabModelNP.getRelativePoint(self.grabModelNP, camera.getPos()) if camPos.z >= 0: # 1-4 if camPos.x > 0.0 <= camPos.y: # quad 1 coreLst[12].getParent().setScale( 1, 1, -1) elif camPos.x < 0.0 <= camPos.y: # quad 2 coreLst[12].getParent().setScale( -1, 1, -1) elif camPos.x < 0.0 >= camPos.y: # quad 3 coreLst[12].getParent().setScale( -1, -1, -1) elif camPos.x > 0.0 >= camPos.y: # quad 4 coreLst[12].getParent().setScale( 1, -1, -1) else: self.notify.warning("if-else default, scaleGrabber cam.z > 0") else: # 5-8 if camPos.x > 0.0 <= camPos.y: # quad 5 coreLst[12].getParent().setScale( 1, 1, 1) elif camPos.x < 0.0 <= camPos.y: # quad 6 coreLst[12].getParent().setScale( -1, 1, 1) elif camPos.x < 0.0 >= camPos.y: # quad 7 coreLst[12].getParent().setScale( -1, -1, 1) elif camPos.x > 0.0 >= camPos.y: # quad 8 coreLst[12].getParent().setScale( 1, -1, 1) else: self.notify.warning("if-else default, scaleGrabber cam.z z < 0") distToCam = (camera.getPos() - render.getRelativePoint(BBGlobalVars.currCoordSysNP, self.grabModelNP.getPos())).length() self.grabModelNP.setScale(self.grabScaleFactor * distToCam, self.grabScaleFactor * distToCam, self.grabScaleFactor * distToCam) # keep the position identical to the selection # for when outside objects like undo/redo move selected self.grabModelNP.setPos(render, self.selected.getPos(render)) return task.cont # TODO find a way to move camera control to a proper camera handler, perhaps move these to a global def enableCamera(self): self.isCameraControlOn = True PanditorEnableMouseFunc() def disableCamera(self): self.isCameraControlOn = False PanditorDisableMouseFunc() def handleM3(self): """Deselect the selected object.""" if not self.grabModelNP.isHidden() and not self.isCameraControlOn: # if the grab model is in the scene and the camera is not in control if base.mouseWatcherNode.hasMouse() and not self.isDragging: # we're ignoring accidental mouse3 clicks while dragging here with not isDragging self.selected = None # empty the selected, will be turned back on once something's selected messenger.ignore('mouse3', self) # turn the deselect event off self.grabModelNP.hide() # hide the grab model and set it back to render's pos self.grabModelNP.setPos(0.0) def handleM1Up(self): """Stop dragging the selected object.""" taskMgr.remove('mouse1Dragging') self.isDragging = False self.currTransformOperation = None # NOTE other references have been added, but no other object references them # record the mouse1 operation BBGlobalVars.undoHandler.record(self.selected, CommandUndo([self.initialCommandTrgVal], self.selected.setMat, self.selected.getMat(render))) messenger.ignore('mouse1-up', self) def handleM1(self): """Decides how to handle a mouse1 click.""" if self.isCameraControlOn: return if base.mouseWatcherNode.hasMouse(): # give the grabber first chance if self.grabModelNP.isHidden(): # no collisions w/ grabber or nothing selected # handle selection with scene objects self.handleSelection() elif not self.isDragging: # The grabber is in place but not dragging. Get ready to drag. self.handleManipulationSetup() # it'll call self.handleSelection() if no collision w/ grabber # TODO (if warranted) make self.handleManipulationSetup() return false if no col w/ grabber, call selection here instead def handleManipulationSetup(self): """Sets up all the attributes needed for the mouse dragging task.""" # This makes the ray's origin the camera and makes the ray point # to the screen coordinates of the mouse. if self.isDragging: return camVec = self.grabModelNP.getRelativeVector(self.grabModelNP, camera.getPos()) mPos = base.mouseWatcherNode.getMouse() self.grabberRay.setFromLens(base.camNode, mPos.getX(), mPos.getY()) self.colTraverser.traverse(self.grabModelNP) # look for collisions on the grabber if not self.isCameraControlOn and self.colHandlerQueue.getNumEntries() > 0 and not self.grabModelNP.isHidden(): # see if collided with the grabber if not handle re or multi selection self.colHandlerQueue.sortEntries() grabberObj = self.colHandlerQueue.getEntry(0).getIntoNodePath() grabberLst = self.grabModelNP.getPythonTag('grabberRoot') # see __init__ # the index gives the operations rot < 3 scale < 6 trans < 9 trans2D < 12 # mod index gives axis 0 == x, 1 == y, 2 == z ind = -1 for i in range(0, 13): if grabberObj == grabberLst[i]: ind = i grabberObj = grabberLst[i] # ensure we are not picking ourselves, ahem, the grabber assert(not self.grabModelNP.isAncestorOf(self.selected)) mPos3D = Point3(0.0) xVec = Vec3(1, 0, 0) yVec = Vec3(0, 1, 0) zVec = Vec3(0, 0, 1) # TODO: ??? break this up into translate rotate and scale function to make it readable if -1 < ind < 3: # rotate if ind % 3 == 0: # x self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.rot, Point3(mPos.getX(), mPos.getY(), 0.0)) elif ind % 3 == 1: # y self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.rot, Point3(mPos.getX(), mPos.getY(), 0.0)) else: # z self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.rot, Point3(mPos.getX(), mPos.getY(), 0.0)) elif ind < 6: # scale if ind % 3 == 0: # x self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.scale, Point3(mPos.getX(), mPos.getY(), 0.0)) elif ind % 3 == 1: # y # self.currTransformDir = Point3( 0.0, 1.0, 0.0) self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.scale, Point3(mPos.getX(), mPos.getY(), 0.0)) else: # z # self.currTransformDir = Point3( 0.0, 0.0, 1.0) self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.scale, Point3(mPos.getX(), mPos.getY(), 0.0)) elif ind < 9: # translate if ind % 3 == 0: # x # if the camera's too flat to the collision plane bad things happen if camVec.angleDeg( zVec) < 89.0 and self.getMousePlaneIntersect(mPos3D, zVec): self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.trans, mPos3D, zVec) elif self.getMousePlaneIntersect(mPos3D, yVec): self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.trans, mPos3D, yVec) elif ind % 3 == 1: # y if camVec.angleDeg( zVec) < 89.0 and self.getMousePlaneIntersect(mPos3D, zVec): self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.trans, mPos3D, zVec) elif self.getMousePlaneIntersect(mPos3D, xVec): self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.trans, mPos3D, xVec) else: # z if camVec.angleDeg( yVec) < 89.0 and self.getMousePlaneIntersect(mPos3D, yVec): self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.trans, mPos3D, yVec) elif self.getMousePlaneIntersect(mPos3D, xVec): self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.trans, mPos3D, xVec) elif ind < 12: # translate 2D if ind % 3 == 0: # xy if self.getMousePlaneIntersect(mPos3D, zVec): self.initializeManipVars(Point3(1.0, 1.0, 0.0), self.transformOpEnum.trans, mPos3D, zVec) elif ind % 3 == 1: # xz if self.getMousePlaneIntersect(mPos3D, yVec): self.initializeManipVars(Point3(1.0, 0.0, 1.0), self.transformOpEnum.trans, mPos3D, yVec) else: # zy if self.getMousePlaneIntersect(mPos3D, xVec): self.initializeManipVars(Point3(0.0, 1.0, 1.0), self.transformOpEnum.trans, mPos3D, xVec) elif ind == 12: # scale in three directions self.initializeManipVars(Point3(1.0, 1.0, 1.0), self.transformOpEnum.scale, Point3(mPos.getX(), mPos.getY(), 0.0)) else: self.notify.warning("Grabber Err: no grabber collision when col entries > 0 AND grabber not hidden") # Save initial value for save/undo. # The end result of the operation is sent to the undo handler on mouse up event. if self.selected: self.initialCommandTrgVal = self.selected.getMat(render) else: # no collisions w/ grabber or nothing selected # handle reselection or multi-selection (not yet implemented) with other scene obj self.handleSelection() def handleSelection(self): if self.isDragging: return # First check that the mouse is not outside the screen. if base.mouseWatcherNode.hasMouse() and False == self.isCameraControlOn: self.grabberColNode.setFromCollideMask(self.defaultBitMask) # This gives the screen coordinates of the mouse. 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.colHandlerQueue.clearEntries() self.grabberRay.setFromLens(base.camNode, mPos.getX(), mPos.getY()) self.colTraverser.traverse(render) # look for collisions if self.colHandlerQueue.getNumEntries() > 0: self.colHandlerQueue.sortEntries() grabbedObj = self.colHandlerQueue.getEntry(0).getIntoNodePath() if not grabbedObj.findNetTag('pickable').isEmpty(): grabbedObj = grabbedObj.findNetTag('pickable') self.selected = grabbedObj self.grabModelNP.setPos(render, grabbedObj.getPos(render).x, grabbedObj.getPos(render).y, grabbedObj.getPos(render).z) self.grabModelNP.show() messenger.accept('mouse3', self, self.handleM3) def handleDragging(self, task): """ Does the actual work of manipulating objects, once the needed attributes have been setup by handleManipulationSetup(). """ if not self.isDragging: return task.done mPos3D = Point3(0.0) # # This section handles the actual translating rotating or scale after it's been set up in mouse1SetupManip...() # ONLY one operation is preformed per frame if self.currTransformOperation == self.transformOpEnum.trans: # 1st translation, rotation's section is at next elif if self.getMousePlaneIntersect(mPos3D, self.currPlaneColNorm): # get the difference between the last mouse and this frames mouse selectedNewPos = mPos3D - self.interFrameMousePosition # store this frames mouse self.interFrameMousePosition = mPos3D # add the difference to the selected object's pos self.selected.setPos(render, self.selected.getPos(render).x + self.currTransformDir.x * selectedNewPos.x, self.selected.getPos(render).y + self.currTransformDir.y * selectedNewPos.y, self.selected.getPos(render).z + self.currTransformDir.z * selectedNewPos.z) self.grabModelNP.setPos(render, self.selected.getPos(render)) elif self.currTransformOperation == self.transformOpEnum.rot: # 2nd rotation, followed finally by scaling # if operating on the z-axis, use the y (vertical screen coordinates otherwise use x (horizontal) mPos = base.mouseWatcherNode.getMouse() #rotMag = 0.0 if self.currTransformDir == Vec3( 0.0, 0.0, 1.0): rotMag = (mPos.x - self.interFrameMousePosition.x) * 1000 else: rotMag = (self.interFrameMousePosition.y - mPos.y) * 1000 initPos = self.selected.getPos() initPar = self.selected.getParent() self.selected.wrtReparentTo(render) self.selected.setMat(self.selected.getMat() * Mat4.rotateMat(rotMag, self.currTransformDir)) self.selected.wrtReparentTo(initPar) self.selected.setPos(initPos) self.interFrameMousePosition = Point3(mPos.x, mPos.y, 0.0) elif self.currTransformOperation == self.transformOpEnum.scale: # 3rd and final is scaling mPos = base.mouseWatcherNode.getMouse() # TODO: make dragging away from the object larger and to the object smaller (not simply left right up down) # td The problem with this MAY come if negative, mirrored, scaling is implemented. # if operating on the z-axis, use the y (vertical screen coordinates otherwise use x (horizontal) if self.currTransformDir == Point3( 0.0, 0.0, 1.0): sclMag = (mPos.y - self.interFrameMousePosition.y) * 5.5 elif self.currTransformDir == Point3( 0.0, 1.0, 0.0): sclMag = (mPos.x - self.interFrameMousePosition.x) * 5.5 else: sclMag = (self.interFrameMousePosition.x - mPos.x) * 5.5 # This is the line that prevents scaling past the origin. Flipping the faces doesn't seem to work. if -0.0001 < sclMag < 0.0001: sclMag = 0.000001 # create a dummy node to parent to and position such that applying scale to it will scale selected properly dummy = self.levitorNP.attachNewNode('dummy') initScl = dummy.getScale() # Don't forget the parent. Selected needs put back in place initPar = self.selected.getParent() initPos = self.selected.getPos() self.selected.wrtReparentTo(dummy) dummy.setScale(initScl.x + sclMag * self.currTransformDir.x, initScl.y + sclMag * self.currTransformDir.y, initScl.z + sclMag * self.currTransformDir.z) # reset selected's parent then destroy dummy self.selected.wrtReparentTo(initPar) self.selected.setPos(initPos) dummy.removeNode() dummy = None self.interFrameMousePosition = Point3( mPos.x, mPos.y, 0.0) else: self.notify.error("Err: Dragging with invalid curTransformOperation enum in handleDragging") return task.cont # ended by handleM1Up(), the mouse1-up event handler def initializeManipVars(self, transformDir, transformOp, mPos3D, planeNormVec=None): self.currTransformDir = transformDir self.currPlaneColNorm = planeNormVec # set the norm for the collision plane to be used in mouse1Dragging self.interFrameMousePosition = mPos3D self.currTransformOperation = transformOp self.isDragging = True taskMgr.add(self.handleDragging, 'mouse1Dragging') messenger.accept('mouse1-up', self, self.handleM1Up) def getMousePlaneIntersect(self, mPos3Dref, normVec): mPos = base.mouseWatcherNode.getMouse() plane = Plane(normVec, self.grabModelNP.getPos()) nearPoint = Point3() farPoint = Point3() base.camLens.extrude(mPos, nearPoint, farPoint) if plane.intersectsLine(mPos3Dref, render.getRelativePoint(camera, nearPoint), render.getRelativePoint(camera, farPoint)): return True return False def destroy(self): raise NotImplementedError('Make sure messenger etc are cleared of refs and the model node is deleted') self.grabModelNP.clearPythonTag('grabberRoot') self.grabModelNP.clearPythonTag('grabber') self.grabModelNP = None messenger.ignoreAll(self)
class MousePicker(object): def __init__(self, pickTag='MyPickingTag', nodeName='pickRay', showCollisions=False): self.pickTag = pickTag self.nodeName = nodeName self.showCollisions = showCollisions def create(self): self.mPickerTraverser = CollisionTraverser() self.mCollisionQue = CollisionHandlerQueue() self.mPickRay = CollisionRay() self.mPickRay.setOrigin(base.camera.getPos(base.render)) self.mPickRay.setDirection( base.render.getRelativeVector(base.camera, Vec3(0, 1, 0))) #create our collison Node to hold the ray self.mPickNode = CollisionNode(self.nodeName) self.mPickNode.addSolid(self.mPickRay) #Attach that node to the camera since the ray will need to be positioned #relative to it, returns a new nodepath #well use the default geometry mask #this is inefficent but its for mouse picking only self.mPickNP = base.camera.attachNewNode(self.mPickNode) #we'll use what panda calls the "from" node. This is reall a silly convention #but from nodes are nodes that are active, while into nodes are usually passive environments #this isnt a hard rule, but following it usually reduces processing #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it, we use bitmasks to determine what we check other objects against #if they dont have a bitmask for bit 1 well skip them! self.mPickNode.setFromCollideMask(BitMask32(1)) #Register the ray as something that can cause collisions self.mPickerTraverser.addCollider(self.mPickNP, self.mCollisionQue) #Setup 2D picker self.mPickerTraverser2D = CollisionTraverser() self.mCollisionQue2D = CollisionHandlerQueue() self.mPickNode2D = CollisionNode('2D PickNode') self.mPickNode2D.setFromCollideMask(BitMask32(1)) self.mPickNode2D.setIntoCollideMask(BitMask32.allOff()) self.mPick2DNP = base.camera2d.attachNewNode(self.mPickNode2D) self.mPickRay2D = CollisionRay() self.mPickNode2D.addSolid(self.mPickRay2D) self.mPickerTraverser2D.addCollider(self.mPick2DNP, self.mCollisionQue2D) if self.showCollisions: self.mPickerTraverser.showCollisions(base.render) self.mPickerTraverser2D.showCollisions(base.aspect2d) def mousePick(self, traverse=None, tag=None): #do we have a mouse if (base.mouseWatcherNode.hasMouse() == False): return None, None traverse = traverse or base.render tag = tag or self.pickTag mpos = base.mouseWatcherNode.getMouse() #Set the position of the ray based on the mouse position self.mPickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.mPickerTraverser.traverse(traverse) if (self.mCollisionQue.getNumEntries() > 0): self.mCollisionQue.sortEntries() for entry in self.mCollisionQue.getEntries(): pickedObj = entry.getIntoNodePath() pickedObj = pickedObj.findNetTag(tag) if not pickedObj.isEmpty(): pos = entry.getSurfacePoint(base.render) return pickedObj, pos return None, None def mousePick2D(self, traverse=None, tag=None, all=False): #do we have a mouse if (base.mouseWatcherNode.hasMouse() == False): return None, None traverse = traverse or base.render tag = tag or self.pickTag mpos = base.mouseWatcherNode.getMouse() self.mPickRay2D.setFromLens(base.cam2d.node(), mpos.getX(), mpos.getY()) self.mPickerTraverser2D.traverse(base.aspect2d) if self.mCollisionQue2D.getNumEntries() > 0: self.mCollisionQue2D.sortEntries() if all: return [(entry.getIntoNodePath().findNetTag(tag), entry.getSurfacePoint(base.aspect2d)) for entry in self.mCollisionQue2D.getEntries()], None else: entry = self.mCollisionQue2D.getEntry(0) pickedObj = entry.getIntoNodePath() pickedObj = pickedObj.findNetTag(tag) if not pickedObj.isEmpty(): pos = entry.getSurfacePoint(base.aspect2d) return pickedObj, pos return None, None
class World(DirectObject): def __init__(self): self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0} base.win.setClearColor(Vec4(0,0,0,1)) # Post the instructions self.title = addTitle("Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left") self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right") self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward") self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left") self.inst7 = addInstructions(0.65, "[S]: Rotate Camera Right") # 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("models/world") self.environ.reparentTo(render) self.environ.setPos(0,0,0) # Create the main character, Ralph ralphStartPos = self.environ.find("**/start_point").getPos() #self.addRalph(ralphStartPos) # 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("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") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() # 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. # 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) # Create some lighting 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)) # Add some text ''' bk_text = "This is a test" textObject = OnscreenText(text = bk_text, pos = (0.95,-0.35), scale = 0.07,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=1) ''' #MS: Adds a Roaming Ralph def addRalph(self, pos): ralphStartPos = pos self.ralph = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos) 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) #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 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 # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. 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 # 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) # Keep the camera at one foot above the terrain, # or two feet above ralph, 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.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.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. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + 2.0) base.camera.lookAt(self.floater) return task.cont
class Labryn(ShowBase): def setCamera(self, spin): # set camera spin state self.spin = spin def displayInformation(self): self.title = addTitle("Single Player") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[wasd]: Move") self.inst3 = addInstructions(0.85, "[q/e]: spin camera") self.inst4 = addInstructions(0.80, "[z/c]: zoom in/out") self.inst5 = addInstructions(0.75, "[shift]: hold and pan") self.inst6 = addInstructions(0.70, "[1/2/3]: use moves") self.inst7 = addInstructions(0.65, "[h]: hide instructions") self.insts = [self.title, self.inst1, self.inst2, self.inst3, self.inst4, self.inst5, self.inst6, self.inst7] def hideInstructions(self): if self.instStatus == "show": self.instStatus = "hide" groupHide(self.insts) else: # instructions are hidden self.instStatus = "show" groupShow(self.insts) def loadNextMusic(self, task): # random load background music if (self.music.status()!=self.music.PLAYING): # not playing self.musicCounter += 1 index = self.musicCounter % len(_BGMUSIC) self.music = load_bgmusic(_BGMUSIC[index]) self.music.play() return task.cont def spinCamera(self, task): # deal with spinning the camera # _FOCUS: focus point, changed by panning the camera # CAM_R: radius, changed by zooming # cameraSpinCount: amount of spinning, changed by spinning if self.spin == 1: # spin counter-clockwise self.cameraSpinCount += 1 angleDegrees = self.cameraSpinCount angleRadians = angleDegrees * (pi/ 180) self.CAM_RAD = angleRadians camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD), _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD), (25.0/12)*self.CAM_R) camera.setHpr(angleDegrees,-65,0) elif self.spin == 2: # spin clockwise self.cameraSpinCount -= 1 angleDegrees = self.cameraSpinCount angleRadians = angleDegrees * (pi/ 180) self.CAM_RAD = angleRadians camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD), _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD), (25.0/12)*self.CAM_R) camera.setHpr(angleDegrees,-65,0) elif self.spin == 3: # ZOOM IN not spin self.cameraZoomCount += 1 deltaR = self.cameraZoomCount * 0.1 new_R = 12-deltaR self.CAM_R = new_R camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD), _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD), (25.0/12)*new_R) elif self.spin == 4: # ZOOM OUT self.cameraZoomCount -= 1 deltaR = self.cameraZoomCount * 0.1 new_R = 12-deltaR self.CAM_R = new_R camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD), _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD), (25.0/12)*self.CAM_R) return Task.cont def takeRecord(self): def myCMP(aString, bString): a = float(aString.split(',')[0]) b = float(bString.split(',')[0]) return int(10*(a - b)) msg = "%.2f,%s\n" %(self.clock/100.0, time.ctime()) with open('record.txt') as f: data = f.readlines() # if has no previous data if len(data) == 0: data.append(msg) with open('record.txt','w') as f: f.writelines(data) else: data.append(msg) processedData = sorted(data, myCMP) with open('record.txt', 'w') as f: f.writelines(processedData) def printResults(self): addEndMessage(self.clock) with open('record.txt') as f: data = f.readlines() for i in xrange(0, len(data)): if i < 5: # only print the top 5 string = data[i] printRank(i, string) def checkForWin(self, task): if (checkWin(self.pikachu.getX(), self.pikachu.getY(), self.ballRoot.getX(), self.ballRoot.getY()) and self.gameOver == False): self.takeRecord() self.printResults() self.gameOver = True # if top 10, if top 1, print "WIN" # print previous best 10 results return Task.cont def pikachuBark(self, task): if self.distance < 3: if random.randint(1,200) == 1: # randomly bark dangerous sound if self.dangerous.status() != self.dangerous.PLAYING: self.dangerous.play() elif self.distance > 10: if random.randint(1,430) == 1: if self.safe.status() != self.safe.PLAYING: self.safe.play() return Task.cont def checkMouse(self, task): # get mouse position if base.mouseWatcherNode.hasMouse(): self.mouseX=base.mouseWatcherNode.getMouseX() self.mouseY=base.mouseWatcherNode.getMouseY() return Task.cont def dropRock(self): # when the user clicks, rock is dropped if self.pokeMoveChoice == 1: # selected Geodude result = MAZE.canDropRock(self.rockX, self.rockY) if result != False: # can place rock here MAZE.dropRock(result[0],result[1]) self.rock.setPos(self.rockX, self.rockY, 1) self.rockOnMaze = True self.pokeMoveChoice = None self.myPokeName.hide() self.myPokeName = None self.updateTwoD() self.playerCandyCount -= 1 def restart(self): sys.exit() def useFlame(self): # use flame to Pikachu -> cannot move self.onFire = True # on fire self.playerCandyCount -= 1 self.pokeStatus = 1 self.flame = ParticleEffect() self.flame.loadConfig("fireish.ptf") self.flame.setPos(self.pikachu.getPos()) self.flame.start(parent=render, renderParent=render) self.updateTwoD() def useStringShot(self): # use string shot -> speed goes down self.pokeStatus = 2 self.updateTwoD() def useThunder(self): self.onThunder = True self.pokeCandyCount -= 1 self.thunder = ParticleEffect() self.thunder.loadConfig("thunder.ptf") self.thunder.start(parent=render, renderParent=render) self.use.play() def placeRock(self, task): # rock moves with mouse cursor if self.pokeMoveChoice == 1: # selected Geodude dX,dY = ((self.mouseX-self.rockRefX), (self.mouseY-self.rockRefY)) self.rockX, self.rockY = MAZE.translateRockPosition(self.rockRefX, self.rockRefY, dX, dY) self.rock.show() self.rock.setPos(self.rockX, self.rockY, 1) self.updateTwoD() return Task.cont def placeRareCandy(self, task): # place rare candy with interval # needs to be improved if int(task.time) % 4 == 9 and self.candyOnBoard: self.candy.hide() self.candyOnBoard = False MAZE.clearCandy() if int(task.time) % 10 == 0 and (self.candyOnBoard == False): # every 10 seconds self.candy.setPos(MAZE.generateCandyPos()) self.candy.show() self.candyOnBoard = True return Task.cont def updateTwoD(self): # update player candy count self.playerCandyStatus.destroy() self.playerCandyStatus = candyStatus(0, self.playerCandyCount) self.pokeCandyStatus.destroy() self.pokeCandyStatus = candyStatus(1, self.pokeCandyCount) # update my pokes color if self.playerCandyCount == 0 : groupHide(self.myPokesBright) groupShow(self.myPokesDark) # update name if self.myPokeName != None: self.myPokeName.destroy() def clearRock(self): # clear rock self.rock.hide() self.rockOnMaze = False MAZE.clearRock() # clear it in 2D def clearFlame(self): # clear flame self.onFire = False self.flame.cleanup() self.pokeStatus = 0 self.pokeMoveChoice = None try: self.myPokeName.destroy() except: pass self.myPokeName = None def clearString(self): # clear string shot self.pokeStatus = 0 self.pokeMoveChoice = None try: self.myPokeName.destroy() except: pass self.myPokeName = None def clearThunder(self): self.onThunder = False try: self.thunder.cleanup() except: pass def timer(self, task): # deals with moves' lasting effects ############################################################## self.clock += 1 if self.rockOnMaze: # rock on maze self.rockCounter += 1 elif self.rockCounter != 1: # rock not on maze, counter not cleared self.rockCounter = 0 if self.onFire: self.fireCounter += 1 elif self.fireCounter != 1: self.fireCounter = 0 if self.pokeStatus == 2: # string shot self.stringCounter += 1 elif self.stringCounter != 1: self.stringCounter = 0 if self.onThunder: # thunderbolt self.thunderCounter += 1 elif self.thunderCounter != 1: self.thunderCounter = 0 if self.gameOver == True: # game is over self.gameOverCounter += 1 ################################################################## if self.rockCounter >= 100: self.clearRock() if self.fireCounter >= 80: self.clearFlame() if self.thunderCounter >= 150: self.clearThunder() if self.stringCounter >= 120: self.clearString() if self.gameOverCounter >= 800: # quit the game sys.exit() return Task.cont def usePokeMove(self, number): # use pokemon move if self.playerCandyCount > 0: # have more than one candy if number == 1 and self.rockOnMaze == False: if self.pokeMoveChoice == None: # no choice # set to center position centerx = base.win.getProperties().getXSize()/2 centery = base.win.getProperties().getYSize()/2 base.win.movePointer(0,centerx,centery) self.pokeMoveChoice = 1 # placeRock called here self.rockRefX, self.rockRefY = 0,0 self.rock.show() self.rock.setPos(0,0,1) elif self.pokeMoveChoice != 1: pass else: # self.pokeMoveChoice is already 1, cancel the choice self.pokeMoveChoice = None self.clearRock() # clear rock elif number == 2: if self.pokeMoveChoice == None: self.pokeMoveChoice = 2 self.useFlame() elif self.pokeMoveChoice != 2: pass else: self.pokeMoveChoice = None elif number == 3: if self.pokeMoveChoice == None: self.pokeMoveChoice = 3 self.useStringShot() elif self.pokeMoveChoice != 3: pass else: # already 3 self.pokeMoveChoice = None if self.pokeMoveChoice == None: # no choice if self.myPokeName != None: # there is a name on board self.myPokeName.destroy() # kill it else: # no name pass else: # there is a choice if self.myPokeName != None: self.myPokeName.destroy() self.myPokeName = writePokeName(self.pokeMoveChoice) def loadRareCandy(self): # load rare candy (a box) # needs to be improved self.candy = Model_Load.loadRareCandy() self.candy.reparentTo(render) self.candy.setScale(0.1) self.candy.hide() def eatRareCandy(self, task): # check who eats candy if self.candyOnBoard: # candy on board if checkEat(self.ballRoot.getX(), self.ballRoot.getY(), self.candy.getX(), self.candy.getY()): # ball eats self.candy.hide() # eaten self.candyOnBoard = False if self.playerCandyCount < 3: self.playerCandyCount += 1 groupShow(self.myPokesBright) MAZE.clearCandy() elif checkEatPika(self.pikachu.getX(), self.pikachu.getY(), self.candy.getX(), self.candy.getY()): self.candy.hide() self.candyOnBoard = False if self.pokeCandyCount < 3: self.pokeCandyCount += 1 MAZE.clearCandy() return Task.cont def setFocus(self, changing): # set focus of the camera while panning self.changingFocus = changing if changing == True: # Just Pressed self.referenceX, self.referenceY = self.mouseX, self.mouseY else: # cursor moves up self.referenceX, self.referenceY = None, None def resetView(self): # reset the view to default self.CAM_R, self.CAM_RAD = 12, 0 self.cameraSpinCount, self.cameraZoomCount = 0, 0 # _FOCUS = [0,0,0] does not work WHY??? _FOCUS[0], _FOCUS[1], _FOCUS[2] = 0,0,0 self.changingFocus = False self.referenceX, self.referenceY = None, None camera.setPos(_FOCUS[0], _FOCUS[1]-self.CAM_R, 25) camera.setHpr(0, -65, 0) def changeFocus(self, task): # change focus with displacement of mouse cursor if (self.changingFocus == True and self.mouseX != None and self.mouseY != None ): dX, dY = ((self.mouseX - self.referenceX)*0.1, (self.mouseY - self.referenceY)*0.1) _FOCUS[0] += dX _FOCUS[1] += dY camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD), _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD), (25.0/12)*self.CAM_R) return Task.cont def thunderbolt(self, task): if self.onThunder == True: self.thunder.setPos(self.ballRoot.getPos()) return Task.cont def displayClock(self, task): msg = "Time: %.2f" %(self.clock/100.0) if self.clockMSG == None: self.clockMSG = OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(1.3, .95), align=TextNode.ALeft, scale = .05) else: self.clockMSG.destroy() self.clockMSG = OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(1.3, .95), align=TextNode.ALeft, scale = .05) return task.cont def initialize(self): taskMgr.stop() self.musicCounter, self.clock = 0, 0 self.gameOverCounter = 0 self.clockMSG = None self.music = load_bgmusic(_BGMUSIC[0]) self.background = loadBackground() base.cam2dp.node().getDisplayRegion(0).setSort(-20) self.candyOnBoard = False self.playerCandyCount, self.pokeCandyCount = 0, 0 self.gameOver = False self.displayInformation() self.instStatus = "show" ######################Rare Candy############################### pokes=['caterpie', 'charmander', 'geodude'] self.myPokesDark = loadMyPokemon_Dark(pokes) # my pokemons self.myPokesBright = loadMyPokemon_Bright() groupHide(self.myPokesBright) self.loadRareCandy() # load rare candy ######################Camera Initialization#################### self.CAM_R, self.CAM_RAD = 12, 0 camera.setPos(_FOCUS[0],_FOCUS[1]-12,_FOCUS[2]+25) camera.setHpr(0, -65, 0) self.cameraSpinCount, self.cameraZoomCount = 0, 0 self.changingFocus = False self.spin = 0 #######################ICONS################################### self.myIcon = loadMyIcon() self.pokeIcon = loadPokeIcon() self.playerCandyStatus = candyStatus(0, self.playerCandyCount) self.pokeCandyStatus = candyStatus(1, self.pokeCandyCount) self.rareCandyImage = loadRareCandyImage() self.pokeRareCandyImage = loadRareCandyImage(pos=(-.3,0,-.75)) #######################FLAMES################################## base.enableParticles() self.fireCounter = 0 self.onFire = False #######################STRINGSHOT############################# self.stringCounter = 0 #######################THUNDER################################ self.thunderCounter = 0 #######################SOUND################################## self.dangerous = load_sound("pikachu_d.wav") self.safe = load_sound("pikachu_s1.wav") self.use = load_sound("pikachu_u.wav") #######################"GLOBALS"############################## self.speedCounter = 0 self.onThunder = False self.direction = 's' self.myDirection = ['zx', 'zy'] self.rockCounter = 0 self.rockX, self.rockY = None, None self.rockOnMaze = False self.pokeMoveChoice = None self.myPokeName = None self.arrowKeyPressed = False self.pokemonDirection = 'd' self.mouseX, self.mouseY = None, None # direction the ball is going self.jerkDirection = None base.disableMouse() self.jerk = Vec3(0,0,0) self.MAZE = Model_Load.loadLabyrinth() Control.keyControl(self) self.loadPokemonLevel1() self.light() self.loadBall() self.pokeStatus = 0 # 0 is normal, 1 is burned, 2 is slow-speed ########################################ROCK################### self.rock = Model_Load.loadRock() self.rock.reparentTo(render) self.rock.hide() # Do not show, but load beforehand for performance def loadPokemonLevel1(self): self.pikachu = load_model("pikachu.egg") self.pikachu.reparentTo(render) self.pikachu.setScale(0.3) endPos = self.MAZE.find("**/end").getPos() self.pikachu.setPos(endPos) def light(self): 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)) def loadBall(self): self.ballRoot = render.attachNewNode("ballRoot") self.ball = load_model("ball") self.ball.reparentTo(self.ballRoot) self.ball_tex = load_tex("pokeball.png") self.ball.setTexture(self.ball_tex,1) self.ball.setScale(0.8) # Find the collision sphere for the ball in egg. self.ballSphere = self.ball.find("**/ball") self.ballSphere.node().setFromCollideMask(BitMask32.bit(0)) self.ballSphere.node().setIntoCollideMask(BitMask32.allOff()) #self.ballSphere.show() # Now we create a ray to cast down at the ball. self.ballGroundRay = CollisionRay() self.ballGroundRay.setOrigin(0,0,10) self.ballGroundRay.setDirection(0,0,-1) # Collision solids go in CollisionNode self.ballGroundCol = CollisionNode('groundRay') self.ballGroundCol.addSolid(self.ballGroundRay) self.ballGroundCol.setFromCollideMask(BitMask32.bit(1)) self.ballGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol) # light ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.55, .55, .55, 1)) 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)) self.ballRoot.setLight(render.attachNewNode(ambientLight)) self.ballRoot.setLight(render.attachNewNode(directionalLight)) # material to the ball m = Material() m.setSpecular(Vec4(1,1,1,1)) m.setShininess(96) self.ball.setMaterial(m,1) def __init__(self): self.initialize() self.WALLS = self.MAZE.find("**/Wall.004") self.WALLS.node().setIntoCollideMask(BitMask32.bit(0)) # collision with the ground. different bit mask #self.mazeGround = self.maze.find("**/ground_collide") #self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1)) self.MAZEGROUND = self.MAZE.find("**/Cube.004") self.MAZEGROUND.node().setIntoCollideMask(BitMask32.bit(1)) # add collision to the rock cs = CollisionSphere(0, 0, 0, 0.5) self.cnodePath = self.rock.attachNewNode(CollisionNode('cnode')) self.cnodePath.node().addSolid(cs) self.cnodePath.node().setIntoCollideMask(BitMask32.bit(0)) # CollisionTraversers calculate collisions self.cTrav = CollisionTraverser() #self.cTrav.showCollisions(render) #self.cTrav.showCollisions(render) # A list collision handler queue self.cHandler = CollisionHandlerQueue() # add collision nodes to the traverse. # maximum nodes per traverser: 32 self.cTrav.addCollider(self.ballSphere,self.cHandler) self.cTrav.addCollider(self.ballGroundColNp,self.cHandler) self.cTrav.addCollider(self.cnodePath, self.cHandler) # collision traversers have a built-in tool to visualize collisons #self.cTrav.showCollisions(render) self.start() def pokemonTurn(self, pokemon, direction): if direction == 'l' and self.pokemonDirection != 'l': self.pokemonDirection = 'l' pokemon.setH(-90) if direction == 'r' and self.pokemonDirection != 'r': self.pokemonDirection = 'r' pokemon.setH(90) if direction == 'd' and self.pokemonDirection != 'd': self.pokemonDirection = 'd' pokemon.setH(0) if direction == 'u' and self.pokemonDirection != 'u': self.pokemonDirection = 'u' pokemon.setH(180) def pokemonMove(self, pokemon, direction): self.pokemonTurn(pokemon, direction) if self.pokeStatus == 0: speed = _SPEED elif self.pokeStatus == 1: speed = 0 else: # self.pokeStatus == 2 speed = _SPEED/2.0 if direction == 'l': newX = pokemon.getX() - speed pokemon.setX(newX) elif direction == 'r': newX = pokemon.getX() + speed pokemon.setX(newX) elif direction == 'u': newY = pokemon.getY() + speed pokemon.setY(newY) elif direction == 'd': newY = pokemon.getY() - speed pokemon.setY(newY) elif direction == "s": # stop pass def whereToGo(self, task): # this returns the direction pokemon should go # tell MAZE pokemon and ball's board position self.pokemonMove(self.pikachu, self.direction) MAZE.setPokeCoord(self.pikachu.getX(), self.pikachu.getY(), self.pokemonDirection) MAZE.setBallCoord(self.ballRoot.getX(), self.ballRoot.getY()) MAZE.sendInformation(self.myDirection, self.rockOnMaze, self.onThunder, self.playerCandyCount, self.pokeCandyCount, self.distance) # find out which direction to go self.direction = MAZE.getDecision() self.pokemonMove(self.pikachu,self.direction) return Task.cont def whatToDo(self, task): # determines when to use thunder if self.pokeCandyCount > 0: # Pikachu has candies decision = MAZE.useThunderDecision() if decision == True: self.useThunder() return Task.cont def getInformation(self, task): # get information on the board self.speedCounter += 1 # sample every other call to avoid if self.speedCounter % 2 == 0: dX = self.ballRoot.getX() - self.oldPos[0] dY = self.ballRoot.getY() - self.oldPos[1] if dX < 0 : # print "going left" self.myDirection[0] = 'l' elif abs(dX) < _EPSILON: # print "not moving horiz" self.myDirection[0] = 'zx' else: # print "going right" self.myDirection[0] = 'r' if dY < 0 : # print "going down" self.myDirection[1] = 'd' elif abs(dY) < _EPSILON: # print "not moving verti" self.myDirection[1] = 'zy' else: # print "going up" self.myDirection[1] = 'u' self.oldPos = self.ballRoot.getPos() # calculate distance self.distance = MAZE.getDistance() return Task.cont def start(self): # maze model has a locator in it # self.ballRoot.show() self.startPos = self.MAZE.find("**/start").getPos() self.oldPos = self.MAZE.find("**/start").getPos() self.ballRoot.setPos(self.startPos) # set the ball in the pos self.ballV = Vec3(0,0,0) # initial velocity self.accelV = Vec3(0,0,0) # initial acceleration # for a traverser to work, need to call traverser.traverse() # base has a task that does this once a frame base.cTrav = self.cTrav # create the movement task, make sure its not already running taskMgr.remove("rollTask") taskMgr.add(self.placeRock, "placeRock") taskMgr.add(self.displayClock, "displayClock") taskMgr.add(self.timer, "timer") taskMgr.add(self.loadNextMusic, "loadNextMusic") taskMgr.add(self.getInformation, "getInformation") taskMgr.add(self.eatRareCandy, "eatRareCandy") taskMgr.add(self.placeRareCandy, "placeRareCandy") taskMgr.add(self.checkMouse, "checkMouse") taskMgr.add(self.spinCamera, "spinCamera") taskMgr.add(self.changeFocus, "changeFocus") taskMgr.add(self.whereToGo, "whereToGo") taskMgr.add(self.whatToDo, "whatToDo") taskMgr.add(self.moveBall, "moveBall") taskMgr.add(self.thunderbolt, "thunderbolt") taskMgr.add(self.checkForWin, "checkForWin") taskMgr.add(self.pikachuBark, "pikachuBark") self.mainLoop = taskMgr.add(self.rollTask, "rollTask") self.mainLoop.last = 0 def moveBallWrapper(self, direction): # wrapper for moving the ball # needs to be improved if direction == False: self.arrowKeyPressed = False else: self.arrowKeyPressed = True self.jerkDirection = direction def moveBall(self, task): # move the ball # a key press changes the jerk direction = self.jerkDirection if self.arrowKeyPressed == True and self.onThunder == False: if direction == "u": self.jerk = Vec3(0,_JERK,0) elif direction == "d": self.jerk = Vec3(0,-_JERK,0) elif direction == "l": self.jerk = Vec3(-_JERK,0,0) elif direction == "r": self.jerk = Vec3(_JERK,0,0) elif self.onThunder == True: self.jerk = self.jerk return Task.cont # collision between ray and ground # info about the interaction is passed in colEntry def groundCollideHandler(self,colEntry): # set the ball to the appropriate Z for it to be on the ground newZ = colEntry.getSurfacePoint(render).getZ() self.ballRoot.setZ(newZ+.4) # up vector X normal vector norm = colEntry.getSurfaceNormal(render) accelSide = norm.cross(UP) self.accelV = norm.cross(accelSide) # collision between the ball and a wall def wallCollideHandler(self,colEntry): # some vectors needed to do the calculation norm = colEntry.getSurfaceNormal(render) * -1 norm.normalize() curSpeed = self.ballV.length() inVec = self.ballV/curSpeed velAngle = norm.dot(inVec) # angle of incidance hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos() hitDir.normalize() hitAngle = norm.dot(hitDir) # deal with collision cases if velAngle > 0 and hitAngle >.995: # standard reflection equation reflectVec = (norm * norm.dot(inVec*-1)*2) + inVec # makes velocity half of hitting dead-on self.ballV = reflectVec * (curSpeed * (((1-velAngle)*.5)+.5)) # a collision means the ball is already a little bit buried in # move it so exactly touching the wall disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) newPos = self.ballRoot.getPos() + disp self.ballRoot.setPos(newPos) def rollTask(self,task): # standard technique for finding the amount of time # since the last frame dt = task.time - task.last task.last = task.time # If dt is large, then there is a HICCUP # ignore the frame if dt > .2: return Task.cont # dispatch which function to handle the collision based on name for i in range(self.cHandler.getNumEntries()): entry = self.cHandler.getEntry(i) name = entry.getIntoNode().getName() if name == "Wall.004": self.wallCollideHandler(entry) elif name=="Cube.004": self.groundCollideHandler(entry) else: if self.rockOnMaze == True: self.wallCollideHandler(entry) self.accelV += self.jerk # move the ball, update the velocity based on accel self.ballV += self.accelV * dt * ACCELERATION # clamp the velocity to the max speed if self.ballV.lengthSquared() > MAX_SPEED_SQ: self.ballV.normalize() self.ballV *= MAX_SPEED # update the position self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV*dt)) # uses quaternion to rotate the ball prevRot = LRotationf(self.ball.getQuat()) axis = UP.cross(self.ballV) newRot = LRotationf(axis, 45.5 * dt * self.ballV.length()) self.ball.setQuat(prevRot * newRot) return Task.cont # continue the task
class World(DirectObject): def __init__(self): #create Queue to hold the incoming chat #request the heartbeat so that the caht interface is being refreshed in order to get the message from other player self.keyMap = { "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0, "charge": 0 } base.win.setClearColor(Vec4(0, 0, 0, 1)) self.cManager = ConnectionManager() self.cManager.startConnection() #------------------------------ #Chat Chat(self.cManager) #send dummy login info of the particular client #send first chat info #--------------------------------------- self.userName = username dummy_login = { 'user_id': self.userName, 'factionId': faction, 'password': '******' } self.cManager.sendRequest(Constants.RAND_STRING, dummy_login) chat = { 'userName': self.userName, #username 'message': '-------Login------' } self.cManager.sendRequest(Constants.CMSG_CHAT, chat) #-------------------------------------- #self.minimap = OnscreenImage(image="images/minimap.png", scale=(0.2,1,0.2), pos=(-1.1,0,0.8)) #frame = DirectFrame(text="Resource Bar", scale=0.001) resource_bar = DirectWaitBar(text="", value=35, range=100, pos=(0, 0, 0.9), barColor=(255, 255, 0, 1), frameSize=(-0.3, 0.3, 0, 0.03)) cp_bar = DirectWaitBar(text="", value=70, range=100, pos=(1.0, 0, 0.9), barColor=(0, 0, 255, 1), frameSize=(-0.3, 0.3, 0, 0.03), frameColor=(255, 0, 0, 1)) # 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("models/world") self.environ.reparentTo(render) self.environ.setPos(0, 0, 0) # Create the main character, Ralph ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor("models/ralph", { "run": "models/ralph-run", "walk": "models/ralph-walk" }) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos) nameplate = TextNode('textNode username_' + str(self.userName)) nameplate.setText(self.userName) npNodePath = self.ralph.attachNewNode(nameplate) npNodePath.setScale(0.8) npNodePath.setBillboardPointEye() #npNodePath.setPos(1.0,0,6.0) npNodePath.setZ(6.5) bar = DirectWaitBar(value=100, scale=1.0) bar.setColor(255, 0, 0) #bar.setBarRelief() bar.setZ(6.0) bar.setBillboardPointEye() bar.reparentTo(self.ralph) # 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("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]) self.accept("c", self.setKey, ["charge", 1]) self.accept("c-up", self.setKey, ["charge", 0]) taskMgr.add(self.move, "moveTask") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(), self.ralph.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 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) # Create some lighting 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)) #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 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 (self.keyMap["charge"] != 0): self.ralph.setY(self.ralph, -250 * globalClock.getDt()) #ribbon = Ribbon(self.ralph, Vec4(1,1,1,1), 3, 10, 0.3) #ribbon.getRoot().setZ(2.0) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"] != 0) or (self.keyMap["charge"] != 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 # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. 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 # 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) # Keep the camera at one foot above the terrain, # or two feet above ralph, 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.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.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. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + 2.0) base.camera.lookAt(self.floater) return task.cont
class PlayerInput(DirectObject): """ PlayerInput Class: Handels all inputs. """ def __init__(self): # Should make a method to get active players. self.activePlayer = ACTIVE_ACTORS['Player'].playerActor self.activePlayerSpeed = ACTIVE_ACTORS['Player'].playerSpeed # Set the control maps. self.controlMap = {"left": 0, "right": 0, "forward": 0, "backward": 0, "jump": 0, "wheel-in": 0, "wheel-out": 0} self.mousebtn = [0, 0, 0] # 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) ### SETUP KEYBOARD ### # Setup the control [KEYS] for movement w,a,s,d. self.accept("escape", sys.exit) self.accept("w", self.setControl, ["forward", 1]) self.accept("a", self.setControl, ["left", 1]) self.accept("s", self.setControl, ["backward", 1]) self.accept("d", self.setControl, ["right", 1]) self.accept("space", self.setControl, ["jump", 1]) self.accept("w-up", self.setControl, ["forward", 0]) self.accept("a-up", self.setControl, ["left", 0]) self.accept("s-up", self.setControl, ["backward", 0]) self.accept("d-up", self.setControl, ["right", 0]) self.accept("space-up", self.setControl, ["jump", 0]) # Setup mouse [ZOOM]. self.accept("wheel_up", self.setControl, ["wheel-in", 1]) self.accept("wheel_down", self.setControl, ["wheel-out", 1]) # Add the "moveTask" taskMgr.add(self.move, "moveTask") # Game State Variable. self.isMoving = False ###> ### SETUP CAMERA ### # Reparent the -main- Camera to playerActor. base.camera.reparentTo(self.activePlayer) self.cameraTargetHeight = 6.0 self.cameraDistance = 30 self.cameraPitch = 10 base.disableMouse() # This should be used together with a right click function, for the camera rotate. Like in wow. WinProps = WindowProperties() # Hide the cursor. | This will change with the rightClick function. # Giving us the cursor when not rotating. If the player wants to rotate basic [KEYS] left/right can turn while cursor is active. WinProps.setCursorHidden(True) base.win.requestProperties(WinProps) #base.camera.setPos(self.activePlayer.getX(),self.activePlayer.getY()+10,2) # FROM THE ROAMING RALPH TUT> # 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.actorGroundRay = CollisionRay() self.actorGroundRay.setOrigin(0,0,1000) self.actorGroundRay.setDirection(0,0,-1) self.actorGroundCol = CollisionNode('actorRay') self.actorGroundCol.addSolid(self.actorGroundRay) self.actorGroundCol.setFromCollideMask(BitMask32.bit(0)) self.actorGroundCol.setIntoCollideMask(BitMask32.allOff()) self.actorGroundColNp = self.activePlayer.attachNewNode(self.actorGroundCol) self.actorGroundHandler = CollisionHandlerQueue() cTrav.addCollider(self.actorGroundColNp, self.actorGroundHandler) # We will detect anything obstructing the camera's view of the player self.cameraRay = CollisionSegment((0,0,self.cameraTargetHeight),(0,5,5)) self.cameraCol = CollisionNode('cameraRay') self.cameraCol.addSolid(self.cameraRay) self.cameraCol.setFromCollideMask(BitMask32.bit(0)) self.cameraCol.setIntoCollideMask(BitMask32.allOff()) self.cameraColNp = self.activePlayer.attachNewNode(self.cameraCol) self.cameraColHandler = CollisionHandlerQueue() cTrav.addCollider(self.cameraColNp, self.cameraColHandler) # Uncomment this line to see the collision rays self.actorGroundColNp.show() self.cameraColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring cTrav.showCollisions(render) ###> # Check the state of the KB. def setControl(self, key, value): self.controlMap[key] = value def move(self, task): self.actorPos = self.activePlayer.getPos() # Check if a-move key is pressed, if so move. # Forward. if (self.controlMap["forward"] != 0): self.activePlayer.setY(self.activePlayer, -self.activePlayerSpeed * globalClock.getDt()) # Backward. if (self.controlMap["backward"] != 0): self.activePlayer.setY(self.activePlayer, self.activePlayerSpeed * globalClock.getDt()) # Left. if (self.controlMap["left"] != 0): self.activePlayer.setX(self.activePlayer, self.activePlayerSpeed * globalClock.getDt()) # Right. if (self.controlMap["right"] != 0): self.activePlayer.setX(self.activePlayer, -self.activePlayerSpeed * globalClock.getDt()) if (self.controlMap["jump"] != 0): print "Jump now...!?" # Check for zooming and Do. if (self.controlMap["wheel-in"] != 0): self.cameraDistance -= 0.1 * self.cameraDistance if (self.cameraDistance < 5): self.cameraDistance = 5 self.controlMap["wheel-in"] = 0 elif (self.controlMap["wheel-out"] != 0): self.cameraDistance += 0.1 * self.cameraDistance if (self.cameraDistance > 250): self.cameraDistance = 250 self.controlMap["wheel-out"] = 0 # Make use of mouse, to turn. if base.mouseWatcherNode.hasMouse(): # get changes in mouse position md = base.win.getPointer(0) x = md.getX() y = md.getY() deltaX = md.getX() - 200 deltaY = md.getY() - 200 # reset mouse cursor position base.win.movePointer(0, 200, 200) # Mouse speed setting mouseSpeed = 0.3 # alter the actor yaw by an amount proportionate to deltaX self.activePlayer.setH(self.activePlayer.getH() - mouseSpeed* deltaX) # find the new camera pitch and clamp it to a reasonable range self.cameraPitch = self.cameraPitch + 0.1 * deltaY if (self.cameraPitch < -60): self.cameraPitch = -60 if (self.cameraPitch > 80): self.cameraPitch = 80 base.camera.setHpr(0,self.cameraPitch,0) # set the camera at around middle of the ship # We should pivot around here instead of the view target which is noticebly higher base.camera.setPos(0,0,self.cameraTargetHeight/2) # back the camera out to its proper distance base.camera.setY(base.camera,self.cameraDistance) # point the camera at the view target viewTarget = Point3(0,0,self.cameraTargetHeight) base.camera.lookAt(viewTarget) # reposition the end of the camera's obstruction ray trace self.cameraRay.setPointB(base.camera.getPos()) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.controlMap["forward"]!=0) or (self.controlMap["left"]!=0) or (self.controlMap["right"]!=0): if self.isMoving is False: self.activePlayer.loop("run") self.isMoving = True else: if self.isMoving: self.activePlayer.stop() self.activePlayer.pose("walk",5) self.isMoving = False # Now check for collisions. 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.actorGroundHandler.getNumEntries()): entry = self.actorGroundHandler.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() == "ground"): self.activePlayer.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.activePlayer.setPos(self.actorPos) # Go through the BALL_DICT which is not a list and needs a new name :P # And find the ball being colided with. and then del. it for ball in BALL_LIST: if (len(entries)>0) and (entries[0].getIntoNode().getName() == str(ball)): print "Collide with ", entries[0].getIntoNode().getName() del BALL_LIST[ball] BALL_LIST[ball] = None # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. entries = [] for i in range(self.cameraColHandler.getNumEntries()): entry = self.cameraColHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(-y.getSurfacePoint(self.activePlayer).getY(), -x.getSurfacePoint(self.activePlayer).getY())) if (len(entries)>0): collisionPoint = entries[0].getSurfacePoint(self.activePlayer) collisionVec = ( viewTarget - collisionPoint) if ( collisionVec.lengthSquared() < self.cameraDistance * self.cameraDistance ): base.camera.setPos(collisionPoint) if (entries[0].getIntoNode().getName() == "ground"): base.camera.setZ(base.camera, 0.2) base.camera.setY(base.camera, 0.3) return task.cont