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
class ColTime(DirectObject.DirectObject): def __init__(self): self.colahand = CollisionHandlerEvent() #self.que=CollisionHandlerQueue() self.loc = CollisionTraverser() self.anim = loader.loadModel("BO1.egg") self.simco = CollisionNode("sim") self.simco.addSolid( CollisionSphere(self.anim.node().getBounds().getCenter(), self.anim.node().getBounds().getRadius() * 1.2)) self.colahand.addAgainPattern("modelintoacube-%in") self.simco = self.anim.attachNewNode(self.simco) self.accept("modelintoacube-sim", self.sim) self.loc.addCollider(self.simco, self.colahand) self.loc.addCollider(hifi.modcollision, self.colahand) taskMgr.add(self.startingcol, "StartingCol") #messenger.send("sim",[self.simco]) self.anim.reparentTo(render) def sim(self, colEntry): colEntry.getIntoNodePath().removeNode() def startingcol(self, task): self.loc.traverse(render) return task.cont
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
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 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 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
class MouseCollision: def __init__(self, game): self.game = game self.c_trav = CollisionTraverser() self.mouse_groundHandler = CollisionHandlerQueue() self.mouse_ground_ray = CollisionRay() self.mouse_ground_col = CollisionNode('mouseRay') self.mouse_ground_ray.setOrigin(0, 0, 0) self.mouse_ground_ray.setDirection(0, -1, 0) self.mouse_ground_col.addSolid(self.mouse_ground_ray) self.mouse_ground_col.setFromCollideMask(CollideMask.bit(0)) self.mouse_ground_col.setIntoCollideMask(CollideMask.allOff()) self.mouse_ground_col_np = self.game.camera.attachNewNode( self.mouse_ground_col) self.c_trav.addCollider(self.mouse_ground_col_np, self.mouse_groundHandler) self.game.taskMgr.add(self.update, 'updateMouse') def update(self, task): if self.game.mouseWatcherNode.hasMouse(): if self.game.ship.model: mouse_pos = self.game.mouseWatcherNode.getMouse() self.mouse_ground_ray.setFromLens(self.game.camNode, mouse_pos.getX(), mouse_pos.getY()) near_point = render.getRelativePoint( self.game.camera, self.mouse_ground_ray.getOrigin()) near_vec = render.getRelativeVector( self.game.camera, self.mouse_ground_ray.getDirection()) self.game.ship.shipPoint.setPos( self.PointAtY(self.game.ship.model.getY(), near_point, near_vec)) return task.cont def PointAtY(self, y, point, vec): return point + vec * ((y - point.getY()) / vec.getY())
class 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
class SmartCar(ShowBase): def __init__(self): ShowBase.__init__(self) # Override defaults self.disableMouse() self.setBackgroundColor(VBase3(160, 200, 150) / 255.0) self.setFrameRateMeter(True) # Lights dlight = DirectionalLight("dlight") dlnp = self.render.attachNewNode(dlight) dlnp.setHpr(180.0, -70.0, 0) self.render.setLight(dlnp) alight = AmbientLight("alight") alnp = self.render.attachNewNode(alight) alight.setColor(VBase4(0.4, 0.4, 0.4, 1)) self.render.setLight(alnp) # Collision traverser self.cTrav = CollisionTraverser("collisionTraverser") # Collision handlers self.carCollisionHandler = CollisionHandlerEvent() self.carCollisionHandler.addInPattern("%fn-into-%in") # Camera controls self.cameraController = CameraController(self, 400, math.pi / 4.0, math.pi / 4.0) # Load the track self.track = self.loader.loadModel("models/trackValencia") checkpointsCollision = self.track.find("checkpoints").node() checkpointsCollision.setIntoCollideMask(BitMask32(0xF0)) self.numCheckpoints = checkpointsCollision.getNumSolids() self.track.reparentTo(self.render) # Load the car self.car = NeuralNetworkCar(self) self.cameraController.follow(self.car.getNodePath()) # Reposition the car # self.car.getNodePath().setH(180.0) # Register car collisions with track self.cTrav.addCollider(self.car.carCollider, self.carCollisionHandler) self.accept("carCollider-into-trackCollision", self.car.onCrash) self.accept("carCollider-into-checkpoints", self.car.onCheckpoint)
class PlayerObject(): def __init__(self, render, player): self.username = player.getUsername() self.isMoving = False self.render = render self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0} self.actor = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.actor.reparentTo(render) self.actor.setScale(0.2) self.actor.setPos(player.getX(), player.getY(), player.getZ()) self.actor.setH(player.getH()) self.cTrav = CollisionTraverser() self.GroundRay = CollisionRay() self.GroundRay.setOrigin(0,0,1000) self.GroundRay.setDirection(0,0,-1) self.GroundCol = CollisionNode('actorRay') self.GroundCol.addSolid(self.GroundRay) self.GroundCol.setFromCollideMask(BitMask32.bit(0)) self.GroundCol.setIntoCollideMask(BitMask32.allOff()) self.GroundColNp = self.actor.attachNewNode(self.GroundCol) self.GroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.GroundColNp, self.GroundHandler) # def getUsername(self): # return self.username def getActor(self): return self.actor def setPos(self, x, y, z): self.actor.setPos(x, y, z) def setH(self, h): self.actor.setH(h) def move(self, isActorMove): if isActorMove == "True": if self.isMoving is False: self.actor.loop("run") self.isMoving = True else: if self.isMoving: self.actor.stop() self.actor.pose("walk",5) self.isMoving = False
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 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 MouseCollision: def __init__(self, game): self.game = game self.c_trav = CollisionTraverser() self.mouse_groundHandler = CollisionHandlerQueue() self.mouse_ground_ray = CollisionRay() self.mouse_ground_col = CollisionNode('mouseRay') self.mouse_ground_ray.setOrigin(0, 0, 0) self.mouse_ground_ray.setDirection(0, -1, 0) self.mouse_ground_col.addSolid(self.mouse_ground_ray) self.mouse_ground_col.setFromCollideMask(CollideMask.bit(0)) self.mouse_ground_col.setIntoCollideMask(CollideMask.allOff()) self.mouse_ground_col_np = self.game.camera.attachNewNode(self.mouse_ground_col) self.c_trav.addCollider(self.mouse_ground_col_np, self.mouse_groundHandler) self.game.taskMgr.add(self.update, 'updateMouse') def update(self, task): if self.game.mouseWatcherNode.hasMouse(): if self.game.ship.model: mouse_pos = self.game.mouseWatcherNode.getMouse() self.mouse_ground_ray.setFromLens(self.game.camNode, mouse_pos.getX(), mouse_pos.getY()) near_point = render.getRelativePoint(self.game.camera, self.mouse_ground_ray.getOrigin()) near_vec = render.getRelativeVector(self.game.camera, self.mouse_ground_ray.getDirection()) self.game.ship.shipPoint.setPos(self.PointAtY(self.game.ship.model.getY(), near_point, near_vec)) return task.cont def PointAtY(self, y, point, vec): return point + vec * ((y - point.getY()) / vec.getY())
class 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 MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) # Create player node and attach camera and collision node/solid self.Player = render.attachNewNode('Player') self.camera.reparentTo(self.Player) self.PlayerCN = CollisionNode('Player') self.PlayerCNP = self.Player.attachNewNode(self.PlayerCN) self.PlayerCSph = CollisionSphere(0, 0, 0, 1) self.PlayerCN.addSolid(self.PlayerCSph) # Player collision sphere playerCS = CollisionSphere(0, 0, 0, 2) playerCNP = self.Player.attachNewNode(CollisionNode('cnode')) playerCNP.node().addSolid(playerCS) #PlayerCNP.reparentTo(self.camera) playerCNP.show() # This won't show since we are inside # Create generic sphere in the world in front of us to see self.Sphere = self.loader.loadModel("models/misc/sphere") self.Sphere.reparentTo(self.render) self.Sphere.setPos(0, 20, -0.2) # Collision sphere for visible sphere, slightly larger cs = CollisionSphere(0, 0, 0, 1) cnodePath = self.Sphere.attachNewNode(CollisionNode('cSpherenode')) cnodePath.node().addSolid(cs) cnodePath.show() # Create global collision traverser self.cTrav = CollisionTraverser() # Collision handler pusher - visible sphere will push back self.pusher = CollisionHandlerPusher() # Tell player sphere to act as pusher - or world object? self.cTrav.addCollider(cnodePath, self.pusher) self.pusher.addCollider(cnodePath, self.Sphere, base.drive.node()) seq = self.Player.posInterval(5, Point3(0, 40, 0), startPos=Point3(0, 0, 0), fluid=1).loop()
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 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 TunnelPinchTask(ShowBase, GripStateMachine): DATA_DIR = 'data' def __init__(self, id, session, hand, block, mode, wrist): ShowBase.__init__(self) GripStateMachine.__init__(self) base.disableMouse() wp = WindowProperties() wp.setSize(1920,1080) wp.setFullscreen(True) wp.setUndecorated(True) base.win.requestProperties(wp) self.sub_id = str(id) self.sess_id = str(session) self.hand = str(hand) self.block = str(block) self.mode = str(mode) self.wrist = str(wrist) self.prev_blk = os.path.join(self.DATA_DIR,'exp_2',self.sub_id,self.sess_id,self.wrist,self.hand,"B0") self.exp_blk0 = os.path.join(self.DATA_DIR,'exp_1',self.sub_id,self.sess_id,self.wrist,self.hand,"B0") self.table = np.loadtxt('src/tunnel_pinch_task/trialtable_flex.csv',dtype='str',delimiter=',',skiprows=1) indices = {} try: self.prev_table = np.loadtxt(os.path.join(self.prev_blk, 'final_targets.csv'),dtype='str',delimiter=',',skiprows=1) except: try: self.prev_table = np.loadtxt(os.path.join(self.exp_blk0, 'final_targets.csv'),dtype='str',delimiter=',',skiprows=1) except: print('Previous target file not found, results may be suboptimal') try: for i in range(self.prev_table.shape[0]): indices[self.prev_table[i,1]] = int(self.prev_table[i,0])-1 for i in range(self.table.shape[0]): self.table[i,11] = self.prev_table[indices[self.table[i,1].strip()],11] self.table[i,12] = self.prev_table[indices[self.table[i,1].strip()],12] self.table[i,13] = self.prev_table[indices[self.table[i,1].strip()],13] except: print('Invalid target file') self.table = np.array([[item.strip() for item in s] for s in self.table]) ################################################### #only use rows relevant to this block #HARDCODED! NOTE IN LOG SHEET spec_table = [] for i in range(self.table.shape[0]): if int(self.block)%5 == 0: #block 0 to adjust positions if "(p)" in self.table[i,2]: spec_table.append(self.table[i]) elif int(self.block)%5 == 1: if "(L)" in self.table[i,2]: spec_table.append(self.table[i]) elif int(self.block)%5 == 2: if "(L+t)" in self.table[i,2]: spec_table.append(self.table[i]) elif int(self.block)%5 == 3: if "(S)" in self.table[i,2]: spec_table.append(self.table[i]) elif int(self.block)%5 == 4: if "(S+t)" in self.table[i,2]: spec_table.append(self.table[i]) ################################################### self.table = np.array(spec_table) self.session_dir = os.path.join(self.DATA_DIR,'exp_2',self.sub_id,self.sess_id,self.wrist,self.hand) self.subjinfo = self.sub_id + '_' + self.sess_id + '_' + self.hand + '_log.yml' self.p_x,self.p_y,self.p_a = GET_POS(self.session_dir,self.subjinfo,self.hand,self.wrist) self.rotmat = ROT_MAT(self.p_a,self.hand) self.setup_text() self.setup_lights() self.setup_camera() self.trial_counter = 0 self.load_models() self.load_audio() self.update_trial_command() self.countdown_timer = CountdownTimer() self.hold_timer = CountdownTimer() self.cTrav = CollisionTraverser() self.chandler = CollisionHandlerEvent() self.chandler.addInPattern('%fn-into-%in') self.chandler.addOutPattern('%fn-outof-%in') self.chandler.addAgainPattern('%fn-again-%in') self.attachcollnodes() taskMgr.add(self.read_data, 'read') for i in range(5): taskMgr.add(self.move_player, 'move%d' % i, extraArgs = [i], appendTask=True) taskMgr.add(self.log_data, 'log_data') taskMgr.add(self.update_state, 'update_state', sort=1) self.accept('space', self.space_on) self.accept('escape', self.clean_up) self.space = False self.statenum = list() self.max_time = 20 self.med_data = None self.grip_dir = os.path.join(self.DATA_DIR,'exp_2',self.sub_id,self.sess_id,self.wrist,self.hand,"B"+self.block) if not os.path.exists(self.grip_dir): print('Making new folders: ' + self.grip_dir) os.makedirs(self.grip_dir) self.dev = MpDevice(RightHand(calibration_files=['calibs/cal_mat_70_v2.mat', 'calibs/cal_mat_73_v2.mat', 'calibs/cal_mat_56.mat', 'calibs/cal_mat_58_v2.mat', 'calibs/cal_mat_50.mat'], clock=mono_clock.get_time)) ############ #SET UP HUD# ############ def setup_text(self): self.bgtext = OnscreenText(text='Not recording.', pos=(-0.8, 0.8), scale=0.08, fg=(0, 0, 0, 1), bg=(1, 1, 1, 1), frame=(0.2, 0.2, 0.8, 1), align=TextNode.ACenter) self.bgtext.reparentTo(self.aspect2d) self.dirtext = OnscreenText( pos=(-0.6, 0.65), scale=0.08, fg=(0, 0, 0, 1), bg=(1, 1, 1, 1), frame=(0.2, 0.2, 0.8, 1), align=TextNode.ACenter) self.dirtext.reparentTo(self.aspect2d) ########################## #SET UP SCENE AND PLAYERS# ########################## def setup_lights(self): pl = PointLight('pl') pl.setColor((1, 1, 1, 1)) plNP = self.render.attachNewNode(pl) plNP.setPos(-10, -10, 10) self.render.setLight(plNP) pos = [[[0, 0, 50], [0, 0, -10]], [[0, -50, 0], [0, 10, 0]], [[-50, 0, 0], [10, 0, 0]]] for i in pos: dl = Spotlight('dl') dl.setColor((1, 1, 1, 1)) dlNP = self.render.attachNewNode(dl) dlNP.setPos(*i[0]) dlNP.lookAt(*i[1]) dlNP.node().setShadowCaster(False) self.render.setLight(dlNP) def setup_camera(self): self.cam.setPos(0, 0, 12) self.cam.lookAt(0, 2, 0) self.camLens.setFov(90) def load_models(self): self.back_model = self.loader.loadModel('models/back') self.back_model.setScale(10, 10, 10) if self.hand == "Left": self.back_model.setH(90) self.back_model.reparentTo(self.render) self.player_offsets = [[self.p_x[0]-5, self.p_y[0]+3, 0], [self.p_x[1]-2.5, self.p_y[1]+4.5, 0], [self.p_x[2], self.p_y[2]+5, 0], [self.p_x[3]+2.5, self.p_y[3]+4.5, 0], [self.p_x[4]+5, self.p_y[4]+3, 0]] self.p_col =[[0,0,250],[50,0,200],[125,0,125],[200,0,50],[250,0,0]] if self.hand == 'Left': self.p_col = self.p_col[::-1] self.players = list() self.contacts = list() for counter, value in enumerate(self.player_offsets): self.players.append(self.loader.loadModel('models/target')) self.contacts.append(False) self.players[counter].setPos(*value) self.players[counter].setScale(0.2, 0.2, 0.2) self.players[counter].setColorScale( self.p_col[counter][0]/255, self.p_col[counter][1]/255, self.p_col[counter][2]/255, 1) self.players[counter].reparentTo(self.render) self.players[counter].show() self.target_select() def load_audio(self): self.pop = self.loader.loadSfx('audio/Blop.wav') self.buzz = self.loader.loadSfx('audio/Buzzer.wav') ############################ #SET UP COLLISION MECHANICS# ############################ def attachcollnodes(self): self.inside = [False]*5 for i in range(5): self.fromObject = self.players[i].attachNewNode(CollisionNode('colfromNode'+str(i))) self.fromObject.node().addSolid(CollisionSphere(0,0,0,1)) self.cTrav.addCollider(self.fromObject, self.chandler) for i in range(5): self.accept('colfromNode%d-into-colintoNode' % i, self.collide1,[i]) self.accept('colfromNode%d-again-colintoNode' % i, self.collide2,[i]) self.accept('colfromNode%d-outof-colintoNode' % i, self.collide3,[i]) def collide1(self,f,collEntry): if f in self.highlighted_indices: self.players[f].setColorScale(0,1,0,1) self.tar.setColorScale(0.2,0.2,0.2,1) self.tar.setAlphaScale(0.7) self.contacts[f] = True taskMgr.doMethodLater(self.delay,self.too_long,'too_long%d' % f,extraArgs = [f]) def collide2(self,f,collEntry): for i in self.highlighted_indices: if self.contacts[i] == False: return taskMgr.remove('too_long%d' % f) def collide3(self,f,collEntry): taskMgr.remove('too_long%d' % f) self.reset_fing(f) self.tar.setColorScale(0.1,0.1,0.1,1) self.tar.setAlphaScale(0.7) def too_long(self,f): self.reset_fing(f) self.tar.setColorScale(0.5,0.2,0.2,1) self.tar.setAlphaScale(0.7) def reset_fing(self,f): self.players[f].setColorScale( self.p_col[f][0]/255, self.p_col[f][1]/255, self.p_col[f][2]/255, 1) self.contacts[f] = False ############### #TARGET THINGS# ############### def show_target(self): self.target_select() self.intoObject = self.tar.attachNewNode(CollisionNode('colintoNode')) if self.table[self.trial_counter,7] == "sphere": self.intoObject.node().addSolid(CollisionSphere(0,0,0,1)) elif self.table[self.trial_counter,7] == "cylinder": self.intoObject.node().addSolid(CollisionTube(0,0,-2,0,0,2,1)) else: raise NameError("No such collision type") self.tar.show() self.occSolid.show() self.occLines.show() for i in range(5): if i not in self.highlighted_indices: self.players[i].hide() def target_select(self): self.tgtscx=float(self.table[self.trial_counter,14]) self.tgtscy=float(self.table[self.trial_counter,15]) self.tgtscz=float(self.table[self.trial_counter,16]) tgttsx=float(self.table[self.trial_counter,11]) tgttsy=float(self.table[self.trial_counter,12]) tgttsz=float(self.table[self.trial_counter,13]) tgtrx=float(self.table[self.trial_counter,17]) tgtry=float(self.table[self.trial_counter,18]) tgtrz=float(self.table[self.trial_counter,19]) if self.hand == 'Left': tgttsx *= -1 tgtrx *= -1 self.static_task = (str(self.table[self.trial_counter,5]) == "True") self.target_model = str(self.table[self.trial_counter,6]) self.highlighted_indices=[int(s)-1 for s in self.table[self.trial_counter,4].split(' ')] if self.hand == 'Left': self.highlighted_indices=[4-i for i in self.highlighted_indices] self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[-2,-1],0]) + tgttsx self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[0,1],1]) + tgttsy if self.hand == 'Left': self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[0,1],0]) + tgttsx self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[-2,-1],1]) + tgttsy #self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,0]) #self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,1]) self.tgtposz = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,2]) + tgttsz self.tar = self.loader.loadModel(self.target_model) self.tar.setScale(self.tgtscx,self.tgtscy,self.tgtscz) self.tar.setPos(self.tgtposx,self.tgtposy,self.tgtposz) self.tar.setHpr(tgtrx,tgtry,tgtrz) self.tar.setColorScale(0.1, 0.1, 0.1, 1) self.tar.setAlphaScale(0.7) self.tar.setTransparency(TransparencyAttrib.MAlpha) self.tar.reparentTo(self.render) self.tar.hide() if len(self.highlighted_indices) == 2: dx = self.players[self.highlighted_indices[0]].getX() - self.players[self.highlighted_indices[1]].getX() dy = self.players[self.highlighted_indices[0]].getY() - self.players[self.highlighted_indices[1]].getY() angle = math.degrees(math.atan(dy/dx)) self.table[self.trial_counter,9] = str(angle) + ' ' + str(angle-180) self.angs=self.table[self.trial_counter,9].split(' ') self.angs = [float(a) for a in self.angs] self.tunn_width=float(self.table[self.trial_counter,10]) self.r = 1.5 if int(self.block) == 0: self.r = 0 self.x = [self.r*math.cos(math.radians(a)) for a in self.angs] self.y = [self.r*math.sin(math.radians(a)) for a in self.angs] self.occ = draw_shape(self.angs,self.tunn_width,self.r) self.occSolid = render.attachNewNode(self.occ[0]) self.occSolid.setPos(self.tgtposx,self.tgtposy,self.tgtposz) self.occSolid.setColorScale(0,1,1,0) self.occSolid.setTransparency(TransparencyAttrib.MAlpha) self.occSolid.setAlphaScale(0.6) self.occLines = render.attachNewNode(self.occ[1]) self.occLines.setPos(self.tgtposx,self.tgtposy,self.tgtposz) self.occSolid.hide() self.occLines.hide() self.delay=float(self.table[self.trial_counter,8]) self.distances = [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]] #change camera to be on top of target self.cam.setPos(self.tgtposx, self.tgtposy - 2, 12) self.back_model.setPos(self.tgtposx,self.tgtposy - 2,0) self.cam.lookAt(self.tgtposx, self.tgtposy, 0) ############## #MOVE FINGERS# ############## def read_data(self,task): error, data = self.dev.read() if data is not None: data *= 0.001 self.ts = data.time data = np.dot(data,self.rotmat) self.data = data if self.med_data is None: self.med_data = np.median(data, axis=0) if self.space: self.statenum.extend(([self.checkstate()])*len(data.time)) return task.cont def move_player(self,p,task): if self.data is not None : k = p*3 new_x = 10*np.mean(self.data[-1,k]) + self.player_offsets[p][0] - 10*self.med_data[k] new_y = 10*np.mean(self.data[-1,k + 1]) + self.player_offsets[p][1] - 10*self.med_data[k + 1] new_z = 10*np.mean(self.data[-1,k + 2]) + self.player_offsets[p][2] - 10*self.med_data[k + 2] #make sure digits do not cross each other if ((p in range(1,3) and p+1 in self.highlighted_indices and new_x > self.players[p+1].getX()) or (p in range(2,4) and p-1 in self.highlighted_indices and new_x < self.players[p-1].getX())): new_x = self.players[p].getX() #make sure digits do not cross into target if self.space == True and p in self.highlighted_indices: self.distances[p][0] = new_x - self.tar.getX() self.distances[p][1] = new_y - self.tar.getY() self.distances[p][2] = new_z - self.tar.getZ() self.check_pos(p) self.players[p].setPos(new_x, new_y, new_z) return task.cont def check_pos(self, p): x = self.distances[p][0] y = self.distances[p][1] z = self.distances[p][2] hit = True for i in range(len(self.angs)): p_ang = math.acos((x*self.x[i]+y*self.y[i])/(self.r*(x**2+y**2)**0.5)) if math.sin(p_ang)*(x**2+y**2)**0.5 < self.tunn_width and p_ang < math.pi/2: hit = False break if (abs(z) <= 1.2 #check z location and x**2 + y**2 <= self.r**2 #within radius of circle and hit == True): if self.inside[p] is False: self.ignore('colfromNode%d-into-colintoNode' % p) self.ignore('colfromNode%d-again-colintoNode' % p) self.players[p].setColorScale(1,1,0,1) self.inside[p] = True else: if self.inside[p] is True and x**2 + y**2 > self.r**2: self.accept('colfromNode%d-into-colintoNode' % p, self.collide1,[p]) self.accept('colfromNode%d-again-colintoNode' % p, self.collide2,[p]) self.players[p].setColorScale( self.p_col[p][0]/255, self.p_col[p][1]/255, self.p_col[p][2]/255, 1) self.inside[p] = False ################## #CHECK COMPLETION# ################## def close_to_target(self): for i in self.highlighted_indices: if self.contacts[i] == False: return False self.tar.setColorScale(0,1,1,1) return True def check_hold(self): if not self.close_to_target(): self.hold_timer.reset(0.5) return False return self.hold_timer.elapsed() < 0 def adjust_targets(self): #no adjustment if more than 2 fingers or position is prone if len(self.highlighted_indices) > 2 or self.wrist == 'pron': return xadj,yadj,zadj = np.mean(np.asarray(self.distances)[self.highlighted_indices],0) #xadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][0]) #yadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][1]) #zadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][2]) #do adjustment on all tasks with same name if self.hand == 'Left': xadj = -xadj for i in range(self.trial_counter+1,self.table.shape[0]): if self.table[i,1] == self.table[self.trial_counter,1]: self.table[i,11] = float(self.table[i,11]) + xadj self.table[i,12] = float(self.table[i,12]) + yadj self.table[i,13] = float(self.table[i,13]) + zadj ######### #LOGGING# ######### def play_success(self): if int(self.block) == 0: self.adjust_targets() self.pop.play() self.tar.hide() self.highlighted_indices = [0,1,2,3,4] def log_text(self): self.bgtext.setText('Now logging...') def log_data(self, task): if (self.trial_counter + 1) <= self.table.shape[0]: if self.space: self.log_file_name = os.path.join(self.grip_dir, self.sub_id+"_"+self.sess_id+"_"+self.hand+"_"+ str(self.table[self.trial_counter,1])+"_"+str(self.table[self.trial_counter,0])+".csv" ) self.movvars = np.column_stack((self.ts, self.statenum, self.data)) self.statenum = [] if self.mode=='task': with open(self.log_file_name, 'ab') as f: np.savetxt(f, self.movvars, fmt='%10.5f', delimiter=',') return task.cont else: pass def stoplog_text(self): self.dirtext.clearText() self.bgtext.setText('Done logging!') for i in range(5): self.players[i].show() ####### #RESET# ####### def delete_file(self): if (self.trial_counter + 1) <= self.table.shape[0]: self.log_file_name = os.path.join(self.grip_dir, self.sub_id+"_"+self.sess_id+"_"+self.hand+"_"+ str(self.table[self.trial_counter,1])+"_"+str(self.table[self.trial_counter,0])+".csv" ) try: os.remove(self.log_file_name) except OSError: pass else: pass def reset_baseline(self): self.med_data = None def reset_keyboard_bool(self): self.space = False def hide_target(self): self.tar.hide() self.occSolid.hide() self.occLines.hide() self.intoObject.removeNode() self.imageObject.destroy() def update_trial_command(self): self.dirtext.setText(str(self.table[self.trial_counter,2])) if self.hand == 'Left': xfac = -0.25 else: xfac = 0.25 self.imageObject = OnscreenImage(image = str(self.table[self.trial_counter,3]),scale=(xfac,0.25,0.25),pos=(-0.8, 0, 0.3)) def increment_trial_counter(self): self.trial_counter += 1 self.update_trial_command() ######## #TIMERS# ######## def start_trial_countdown(self): self.countdown_timer.reset(self.max_time) def start_hold_countdown(self): self.hold_timer.reset(0.5) def start_post_countdown(self): self.countdown_timer.reset(2) def time_elapsed(self): return self.countdown_timer.elapsed() < 0 ######### #MACHINE# ######### def update_state(self, task): self.step() return task.cont def wait_for_space(self): return self.space def space_on(self): self.space = True ##### #END# ##### def trial_counter_exceeded(self): return (self.trial_counter+1) > self.table.shape[0]-1 def clean_up(self): #write last known positions to 'final_targets' file f = open('src/pinch_task/trialtable_flex.csv') header = f.readline().rstrip() np.savetxt(self.grip_dir + '/final_targets.csv',self.table,fmt='%s',header = header, delimiter=',') f.close() sys.exit()
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 RoamingRalphDemo(CosmoniumBase): def get_local_position(self): return base.camera.get_pos() def create_terrain_appearance(self): self.terrain_appearance.set_shadow(self.shadow_caster) def create_terrain_heightmap(self): self.heightmap = PatchedHeightmap('heightmap', self.noise_size, self.height_scale, self.size, self.size, True, ShaderHeightmapPatchFactory(self.noise)) def create_terrain_biome(self): self.biome = PatchedHeightmap('biome', self.biome_size, 1.0, self.size, self.size, False, ShaderHeightmapPatchFactory(self.biome_noise)) def create_terrain_shader(self): # control4 = HeightColorMap('colormap', # [ # ColormapLayer(0.00, top=LRGBColor(0, 0.1, 0.24)), # ColormapLayer(0.40, top=LRGBColor(0, 0.1, 0.24)), # ColormapLayer(0.49, top=LRGBColor(0, 0.6, 0.6)), # ColormapLayer(0.50, bottom=LRGBColor(0.9, 0.8, 0.6), top=LRGBColor(0.5, 0.4, 0.3)), # ColormapLayer(0.80, top=LRGBColor(0.2, 0.3, 0.1)), # ColormapLayer(0.90, top=LRGBColor(0.7, 0.6, 0.4)), # ColormapLayer(1.00, bottom=LRGBColor(1, 1, 1), top=LRGBColor(1, 1, 1)), # ]) appearance = DetailMap(self.terrain_control, self.heightmap, create_normals=True) data_source = [HeightmapDataSource(self.heightmap, PatchedGpuTextureSource, filtering=HeightmapDataSource.F_none), HeightmapDataSource(self.biome, PatchedGpuTextureSource, filtering=HeightmapDataSource.F_none), TextureDictionaryDataSource(self.terrain_appearance, TextureDictionaryDataSource.F_hash)] if settings.allow_tesselation: tesselation_control = ConstantTesselationControl(invert_v=False) else: tesselation_control = None if self.fog is not None: after_effects = [Fog(**self.fog)] else: after_effects = None self.terrain_shader = BasicShader(appearance=appearance, tesselation_control=tesselation_control, geometry_control=DisplacementGeometryControl(self.heightmap), data_source=data_source, after_effects=after_effects) def create_tile(self, x, y): self.terrain_shape.add_root_patch(x, y) def create_terrain(self): self.tile_factory = TileFactory(self.tile_density, self.size, self.has_water, self.water) self.terrain_shape = TiledShape(self.tile_factory, self.size, self.max_lod, lod_control=VertexSizeMaxDistancePatchLodControl(self.max_distance, self.max_vertex_size)) self.create_terrain_heightmap() self.create_terrain_biome() self.create_terrain_appearance() self.create_terrain_shader() self.terrain = HeightmapSurface( 'surface', 0, self.terrain_shape, self.heightmap, self.biome, self.terrain_appearance, self.terrain_shader, self.size, clickable=False, average=True) self.terrain.set_parent(self) self.terrain.create_instance() def toggle_water(self): if not self.has_water: return self.water.visible = not self.water.visible self.terrain_shape.check_settings() def get_height(self, position): height = self.terrain.get_height(position) if self.has_water and self.water.visible and height < self.water.level: height = self.water.level return height #Used by populator def get_height_patch(self, patch, u, v): height = self.terrain.get_height_patch(patch, u, v) if self.has_water and self.water.visible and height < self.water.level: height = self.water.level return height def skybox_init(self): skynode = base.cam.attachNewNode('skybox') self.skybox = loader.loadModel('ralph-data/models/rgbCube') self.skybox.reparentTo(skynode) self.skybox.setTextureOff(1) self.skybox.setShaderOff(1) self.skybox.setTwoSided(True) # make big enough to cover whole terrain, else there'll be problems with the water reflections self.skybox.setScale(1.5* self.size) self.skybox.setBin('background', 1) self.skybox.setDepthWrite(False) self.skybox.setDepthTest(False) self.skybox.setLightOff(1) self.skybox.setShaderOff(1) self.skybox.setFogOff(1) #self.skybox.setColor(.55, .65, .95, 1.0) self.skybox_color = LColor(pow(0.5, 1/2.2), pow(0.6, 1/2.2), pow(0.7, 1/2.2), 1.0) self.skybox.setColor(self.skybox_color) def objects_density_for_patch(self, patch): scale = 1 << patch.lod return int(self.objects_density / scale + 1.0) def create_populator(self): if settings.allow_instancing: TerrainPopulator = GpuTerrainPopulator else: TerrainPopulator = CpuTerrainPopulator self.rock_collection = TerrainPopulator(RockFactory(self), self.objects_density_for_patch, self.objects_density, RandomObjectPlacer(self)) self.tree_collection = TerrainPopulator(TreeFactory(self), self.objects_density_for_patch, self.objects_density, RandomObjectPlacer(self)) self.object_collection = MultiTerrainPopulator() self.object_collection.add_populator(self.rock_collection) self.object_collection.add_populator(self.tree_collection) def set_light_angle(self, angle): self.light_angle = angle self.light_quat.setFromAxisAngleRad(angle * pi / 180, LVector3.forward()) self.light_dir = self.light_quat.xform(LVector3.up()) cosA = self.light_dir.dot(LVector3.up()) self.vector_to_star = self.light_dir if self.shadow_caster is not None: self.shadow_caster.set_direction(-self.light_dir) if self.directionalLight is not None: self.directionalLight.setDirection(-self.light_dir) if cosA >= 0: coef = sqrt(cosA) self.light_color = (1, coef, coef, 1) self.directionalLight.setColor(self.light_color) self.skybox.setColor(self.skybox_color * cosA) else: self.light_color = (1, 0, 0, 1) self.directionalLight.setColor(self.light_color) self.skybox.setColor(self.skybox_color * 0) self.update() def update(self): self.object_collection.update_instance() self.terrain.update_instance(None, None) def apply_instance(self, instance): pass def create_instance_delayed(self): pass def get_apparent_radius(self): return 0 def get_name(self): return "terrain" def is_emissive(self): return False def __init__(self): CosmoniumBase.__init__(self) config = RalphConfigParser() (self.noise, self.biome_noise, self.terrain_control, self.terrain_appearance, self.water, self.fog) = config.load_and_parse('ralph-data/ralph.yaml') self.tile_density = 64 self.default_size = 128 self.max_vertex_size = 64 self.max_lod = 10 self.size = 128 * 8 self.max_distance = 1.001 * self.size * sqrt(2) self.noise_size = 512 self.biome_size = 128 self.noise_scale = 0.5 * self.size / self.default_size self.objects_density = int(25 * (1.0 * self.size / self.default_size) * (1.0 * self.size / self.default_size)) self.objects_density = 250 self.height_scale = 100 * 5.0 self.has_water = True self.fullscreen = False self.shadow_caster = None self.light_angle = None self.light_dir = LVector3.up() self.vector_to_star = self.light_dir self.light_quat = LQuaternion() self.light_color = (1.0, 1.0, 1.0, 1.0) self.directionalLight = None self.shadow_size = self.default_size / 8 self.shadow_box_length = self.height_scale self.observer = RalphCamera(self.cam, self.camLens) self.observer.init() self.distance_to_obs = float('inf') self.height_under = 0.0 self.scene_position = LVector3() self.scene_scale_factor = 1 self.scene_orientation = LQuaternion() #Size of an edge seen from 4 units above self.edge_apparent_size = (1.0 * self.size / self.tile_density) / (4.0 * self.observer.pixel_size) print("Apparent size:", self.edge_apparent_size) self.win.setClearColor((135.0/255, 206.0/255, 235.0/255, 1)) # This is used to store which keys are currently pressed. self.keyMap = { "left": 0, "right": 0, "forward": 0, "backward": 0, "cam-left": 0, "cam-right": 0, "cam-up": 0, "cam-down": 0, "sun-left": 0, "sun-right": 0, "turbo": 0} # Set up the environment # # Create some lighting self.vector_to_obs = base.cam.get_pos() self.vector_to_obs.normalize() if True: self.shadow_caster = ShadowCaster(1024) self.shadow_caster.create() self.shadow_caster.set_lens(self.shadow_size, -self.shadow_box_length / 2.0, self.shadow_box_length / 2.0, -self.light_dir) self.shadow_caster.set_pos(self.light_dir * self.shadow_box_length / 2.0) self.shadow_caster.bias = 0.1 else: self.shadow_caster = None self.ambientLight = AmbientLight("ambientLight") self.ambientLight.setColor((settings.global_ambient, settings.global_ambient, settings.global_ambient, 1)) self.directionalLight = DirectionalLight("directionalLight") self.directionalLight.setDirection(-self.light_dir) self.directionalLight.setColor(self.light_color) self.directionalLight.setSpecularColor(self.light_color) render.setLight(render.attachNewNode(self.ambientLight)) render.setLight(render.attachNewNode(self.directionalLight)) render.setShaderAuto() base.setFrameRateMeter(True) self.create_terrain() self.create_populator() self.terrain_shape.set_populator(self.object_collection) self.create_tile(0, 0) self.skybox_init() self.set_light_angle(45) # Create the main character, Ralph ralphStartPos = LPoint3() self.ralph = Actor("ralph-data/models/ralph", {"run": "ralph-data/models/ralph-run", "walk": "ralph-data/models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos + (0, 0, 0.5)) self.ralph_shape = InstanceShape(self.ralph) self.ralph_shape.parent = self self.ralph_shape.set_owner(self) self.ralph_shape.create_instance() self.ralph_appearance = ModelAppearance(self.ralph) self.ralph_appearance.set_shadow(self.shadow_caster) self.ralph_shader = BasicShader() self.ralph_appearance.bake() self.ralph_appearance.apply(self.ralph_shape, self.ralph_shader) self.ralph_shader.apply(self.ralph_shape, self.ralph_appearance) self.ralph_shader.update(self.ralph_shape, self.ralph_appearance) # Create a floater object, which floats 2 units above ralph. We # use this as a target for the camera to look at. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(self.ralph) self.floater.setZ(2.0) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("control-q", sys.exit) self.accept("arrow_left", self.setKey, ["left", True]) self.accept("arrow_right", self.setKey, ["right", True]) self.accept("arrow_up", self.setKey, ["forward", True]) self.accept("arrow_down", self.setKey, ["backward", True]) self.accept("shift", self.setKey, ["turbo", True]) self.accept("a", self.setKey, ["cam-left", True], direct=True) self.accept("s", self.setKey, ["cam-right", True], direct=True) self.accept("u", self.setKey, ["cam-up", True], direct=True) self.accept("u-up", self.setKey, ["cam-up", False]) self.accept("d", self.setKey, ["cam-down", True], direct=True) self.accept("d-up", self.setKey, ["cam-down", False]) self.accept("o", self.setKey, ["sun-left", True], direct=True) self.accept("o-up", self.setKey, ["sun-left", False]) self.accept("p", self.setKey, ["sun-right", True], direct=True) self.accept("p-up", self.setKey, ["sun-right", False]) self.accept("arrow_left-up", self.setKey, ["left", False]) self.accept("arrow_right-up", self.setKey, ["right", False]) self.accept("arrow_up-up", self.setKey, ["forward", False]) self.accept("arrow_down-up", self.setKey, ["backward", False]) self.accept("shift-up", self.setKey, ["turbo", False]) self.accept("a-up", self.setKey, ["cam-left", False]) self.accept("s-up", self.setKey, ["cam-right", False]) self.accept("w", self.toggle_water) self.accept("h", self.print_debug) self.accept("f2", self.connect_pstats) self.accept("f3", self.toggle_filled_wireframe) self.accept("shift-f3", self.toggle_wireframe) self.accept("f5", self.bufferViewer.toggleEnable) self.accept("f8", self.terrain_shape.dump_tree) self.accept('alt-enter', self.toggle_fullscreen) taskMgr.add(self.move, "moveTask") # Game state variables self.isMoving = False # Set up the camera self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2) self.camera_height = 2.0 render.set_shader_input("camera", self.camera.get_pos()) self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 9) self.ralphGroundRay.setDirection(0, 0, -1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0)) self.ralphGroundCol.setIntoCollideMask(CollideMask.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) # Uncomment this line to see the collision rays #self.ralphGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring #self.cTrav.showCollisions(render) #self.terrain_shape.test_lod(LPoint3d(*self.ralph.getPos()), self.distance_to_obs, self.pixel_size, self.terrain_appearance) #self.terrain_shape.update_lod(LPoint3d(*self.ralph.getPos()), self.distance_to_obs, self.pixel_size, self.terrain_appearance) #self.terrain.shape_updated() self.terrain.update_instance(LPoint3d(*self.ralph.getPos()), None) # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # Get the time that elapsed since last frame. We multiply this with # the desired speed in order to find out with which distance to move # in order to achieve that desired speed. dt = globalClock.getDt() # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. if self.keyMap["cam-left"]: self.camera.setX(self.camera, -20 * dt) if self.keyMap["cam-right"]: self.camera.setX(self.camera, +20 * dt) if self.keyMap["cam-up"]: self.camera_height *= (1 + 2 * dt) if self.keyMap["cam-down"]: self.camera_height *= (1 - 2 * dt) if self.camera_height < 1.0: self.camera_height = 1.0 if self.keyMap["sun-left"]: self.set_light_angle(self.light_angle + 30 * dt) if self.keyMap["sun-right"]: self.set_light_angle(self.light_angle - 30 * dt) # 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. delta = 25 if self.keyMap["turbo"]: delta *= 10 if self.keyMap["left"]: self.ralph.setH(self.ralph.getH() + 300 * dt) if self.keyMap["right"]: self.ralph.setH(self.ralph.getH() - 300 * dt) if self.keyMap["forward"]: self.ralph.setY(self.ralph, -delta * dt) if self.keyMap["backward"]: self.ralph.setY(self.ralph, delta * dt) #self.limit_pos(self.ralph) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if self.keyMap["forward"] or self.keyMap["backward"] or self.keyMap["left"] or self.keyMap["right"]: 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() - self.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if camdist > 10.0: self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10)) camdist = 10.0 if camdist < 5.0: self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist)) camdist = 5.0 # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. self.cTrav.traverse(render) if False: # Adjust ralph's Z coordinate. If ralph's ray hit anything, put # him back where he was last frame. entries = list(self.ralphGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0: self.ralph.setPos(startpos) ralph_height = self.get_height(self.ralph.getPos()) self.ralph.setZ(ralph_height) # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. camera_height = self.get_height(self.camera.getPos()) + 1.0 if camera_height < ralph_height + self.camera_height: self.camera.setZ(ralph_height + self.camera_height) else: self.camera.setZ(camera_height) #self.limit_pos(self.camera) # 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.camera.lookAt(self.floater) #self.shadow_caster.set_pos(self.ralph.get_pos()) self.shadow_caster.set_pos(self.ralph.get_pos() - camvec * camdist + camvec * self.shadow_size / 2) render.set_shader_input("camera", self.camera.get_pos()) self.vector_to_obs = base.cam.get_pos() self.vector_to_obs.normalize() if self.isMoving: #self.terrain_shape.test_lod(LPoint3d(*self.ralph.getPos()), self.distance_to_obs, self.pixel_size, self.terrain_appearance) pass#self.terrain_shape.update_lod(LPoint3d(*self.ralph.getPos()), self.distance_to_obs, self.pixel_size, self.terrain_appearance) self.object_collection.update_instance() self.terrain.update_instance(LPoint3d(*self.ralph.getPos()), None) return task.cont def print_debug(self): print("Height:", self.get_height(self.ralph.getPos()), self.terrain.get_height(self.ralph.getPos())) print("Ralph:", self.ralph.get_pos()) print("Camera:", base.camera.get_pos())
class CameraControl(DirectObject): def __init__(self, panda3d): # Inicialización de variables self.winsize = [0, 0] self.panda3d = panda3d self.panda3d.mouse_on_workspace = False # Desabilita el comportamiento por defecto de la camara self.panda3d.disable_mouse() # Llama a la función self.window_rezise_event cuando la ventana cambia de tamaño self.accept('window-event', self.window_rezise_event) # self.panda3d.accept('aspectRatioChanged', lambda: print("ss")) # Creamos el punto donde se centrará la cámara target_pos = Point3(0., 0., 0.) self.panda3d.cam_target = self.panda3d.render.attach_new_node("camera_target") self.panda3d.cam_target.set_pos(target_pos) self.panda3d.camera.reparent_to(self.panda3d.cam_target) self.panda3d.camera.set_y(-50.) # Definimos la cambinación de teclas para el control de la camara self.camera_active = False self.orbit_mouse_btn = "mouse2" self.orbit_keyboard_btn = "shift" self.orbit_mouse_reference = None self.orbit_camera_reference = None self.pan_mouse_btn = "mouse2" self.pan_keyboard_btn = "mouse2" self.pan_mouse_reference = None self.pan_camera_reference = None self.zoom_mouse_btn = "mouse2" self.zoom_keyboard_btn = "control" self.zoom_mouse_reference = None self.zoom_camera_reference = None # Establecemos los valores máximos y minimos para el zoom self.max_zoom = 10 self.min_zoom = 0.1 # Creamos la tarea de control de la camara self.panda3d.task_mgr.add(self.camera_control_task, "camera_control") # El movimiento de la rueda del mouse controla el zoom self.panda3d.accept("wheel_up", self.zoom_in) self.panda3d.accept("wheel_down", self.zoom_out) # Una fución de prueba para comprobar la posición del mouse en el modelo 3d # self.panda3d.accept("mouse1", self.entity_select) # Se establece la lente ortografica en lugar de la perspectiva self.lens_type = "OrthographicLens" self.set_lens(self.lens_type) # Agrega un indicador de ejes en la esquina inferior izquierda self.corner = self.panda3d.camera.attachNewNode("corner of screen") # self.axis = self.panda3d.loader.loadModel("data/geom/custom-axis") # self.axis = self.panda3d.loader.loadModel("data/geom/view_gizmo_F") self.view_gizmo = list() self.view_gizmo.append(self.panda3d.loader.loadModel("data/geom/view_gizmo_compass")) # self.view_gizmo.append(self.panda3d.loader.loadModel("data/geom/view_gizmo_L")) # self.view_cube = ViewGizmoZone() # self.view_cube.set_geom(self.axis) for gizmo_geom in self.view_gizmo: gizmo_geom.setLightOff(1) # gizmo_geom.setColorScale(1,1,1,1) gizmo_geom.setShaderInput("colorborders", LVecBase4(0, 0, 0, 0.25)) gizmo = ViewGizmoZone() gizmo.set_geom(gizmo_geom) gizmo_geom.node().setBounds(BoundingSphere(Point3(0, 0, 0), 10)) gizmo_geom.node().setFinal(True) #gizmo_geom.showTightBounds() # gizmo_geom.showBounds() self.show_view_gizmo() # Agregamos una luz puntual en la ubicación de la camara plight = DirectionalLight("camera_light") plight.setColor((1, 1, 1, 1)) #plight.setAttenuation((1, 0, 0)) #print("getMaxDistance {}".format(plight.getMaxDistance())) self.panda3d.plight_node = self.panda3d.render.attach_new_node(plight) self.panda3d.plight_node.setPos(0, -50, 0) self.panda3d.render.setLight(self.panda3d.plight_node) self.panda3d.plight_node.reparentTo(self.panda3d.camera) # Agregamos luz ambiental que disminuya las zonas oscuras alight = AmbientLight('alight') alight.setColor((0.3, 0.3, 0.3, 1)) alnp = self.panda3d.render.attachNewNode(alight) self.panda3d.render.setLight(alnp) #def init_select_detection(self): self.traverser = CollisionTraverser("") # self.traverser.show_collisions(self.panda3d.render) self.picker_ray = CollisionRay() self.handler = CollisionHandlerQueue() self.picker_node = CollisionNode('mouseRay') self.picker_np = self.panda3d.camera.attachNewNode(self.picker_node) self.picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.picker_ray = CollisionRay() self.picker_node.addSolid(self.picker_ray) self.traverser.addCollider(self.picker_np, self.handler) def set_lens(self, lens_type="OrthographicLens"): """ Permite cambiar la lente de la camara :param lens_type: El tipo de lente a utilizar: OrthographicLens/PerspectiveLens :return: None """ self.lens_type = lens_type width = self.panda3d.win.getXSize() height = self.panda3d.win.getYSize() if lens_type is "OrthographicLens": lens = OrthographicLens() lens.setFilmSize(width, height ) if lens_type is "PerspectiveLens": lens = PerspectiveLens() lens.setFilmSize(width , height ) else: # Default value lens = OrthographicLens() lens.setFilmSize(width / 100, height / 100) print("new lens {}: {} {}".format(lens_type, width / 100, height / 100)) print(lens) self.panda3d.cam.node().setLens(lens) shader_control = self.panda3d.shader_control if shader_control is not None: shader_control.update_camera_lens(lens) def window_rezise_event(self, window=None): """ Se activa con cualquier evento de la ventana de windows, en caso de que haya cambiado de tamaño la ventana regenera la lente :param window: Información del evento :return: None """ if window is not None: # Window será igual a None si la aplicación panda3d no se inició wp = window.getProperties() newsize = [wp.getXSize(), wp.getYSize()] if self.winsize != newsize: self.winsize = newsize self.set_lens() self.show_view_gizmo() def mouse_is_over_workspace(self): """ Detecta si el mouse se encuentra dentro del area de trabajo del modelo 3d :return: True/False """ gui_objects = app.gui_objects is_over_workspace = False if self.panda3d.mouseWatcherNode.has_mouse() and app.workspace_active: is_over_workspace = True mouse_data = self.panda3d.win.getPointer(0) mouse_x, mouse_y = mouse_data.getX(), mouse_data.getY() for name, gui_obj in gui_objects.items(): if gui_obj.isHidden(): continue pos = gui_obj.getPos(pixel2d) frame_size = list(gui_obj["frameSize"]) x0 = pos[0] + frame_size[0] x1 = pos[0] + frame_size[1] y0 = -pos[2] - frame_size[2] y1 = -pos[2] - frame_size[3] x_left = min(x0, x1) x_right = max(x0, x1) y_top = min(y0, y1) y_bottom = max(y0, y1) #if name is "status_bar": #print(pos) #print("{} {} / {} {}".format(x_left, x_right, y_top, y_bottom)) overmouse_x = (x_left <= mouse_x <= x_right) overmouse_y = (y_top <= mouse_y <= y_bottom) # Revisa si el mouse se encuentra sobre un elemento de interfaz if overmouse_x and overmouse_y: # print("mouse is over {}".format(name)) is_over_workspace = False break app.mouse_on_workspace = is_over_workspace if is_over_workspace: get_mouse_3d_coords_task() return is_over_workspace def camera_control_task(self, task): """ Se ejecuta constantemente y realiza las tareas de movimiento de la camara según las teclas presionadas """ # El codigo se ejecuta si el mouse está dentro del espacio de trabajo o si ya se está realizando alguna acción if self.mouse_is_over_workspace() or self.camera_active: # Desactivamos el espacio de trabajo app.workspace_active = False # El nodo mouseWatcherNode permite recibir la entrada de mouse y teclado btn = self.panda3d.mouseWatcherNode # Obtenemos la posición del cursor mouse_data = self.panda3d.win.getPointer(0) mouse_pos = mouse_data.getX(), mouse_data.getY() # En función de la combinación de teclas se ejecuta una acción cam_task = 0 if btn.isButtonDown(self.orbit_mouse_btn) and btn.isButtonDown(self.orbit_keyboard_btn): cam_task = 1 elif btn.isButtonDown(self.zoom_mouse_btn) and btn.isButtonDown(self.zoom_keyboard_btn): cam_task = 2 elif btn.isButtonDown(self.pan_mouse_btn) and btn.isButtonDown(self.pan_keyboard_btn): cam_task = 3 # Orbit if cam_task is 1: self.camera_orbit(mouse_pos) self.camera_active = True else: self.orbit_mouse_reference = None # Zoom if cam_task is 2: self.camera_zoom(mouse_pos) self.camera_active = True else: self.zoom_mouse_reference = None # Pan if cam_task is 3: self.camera_pan(mouse_pos) self.camera_active = True else: self.pan_mouse_reference = None # Si la combinación de teclas no coincide con niguna acción se establece la camara como inactiva if cam_task is 0: self.camera_active = False # Se reactiva el espacio de trabajo app.workspace_active = True self.entity_select() else: pass # Actualizamos la posición de la luz puntual #cam = self.panda3d.camera #self.panda3d.plight_node.setPos(cam.get_pos(self.panda3d.render)) # Ejecutar solo en windows """if os.name == 'nt': # Se coloca la camra en determinadas vistas (frontal, lateral, superior, etc) al apretar el # teclado numérico # Lista de teclas http://www.kbdedit.com/manual/low_level_vk_list.html target = self.panda3d.cam_target if win32api.GetAsyncKeyState(win32con.VK_NUMPAD1): target.set_hpr(0, 0, 0.) elif win32api.GetAsyncKeyState(win32con.VK_NUMPAD3): target.set_hpr(90, 0, 0.) elif win32api.GetAsyncKeyState(win32con.VK_NUMPAD7): target.set_hpr(0, -90, 0.)""" return task.cont def camera_orbit(self, mouse_pos): """ Orbita la camara alrededor del objetivo de ésta, según la posición del mouse respecto del punto donde se hizo click """ target = self.panda3d.cam_target if self.orbit_mouse_reference is None: self.orbit_mouse_reference = mouse_pos self.orbit_camera_reference = target.get_hpr() x_diff = self.orbit_mouse_reference[0] - mouse_pos[0] y_diff = self.orbit_mouse_reference[1] - mouse_pos[1] new_h = self.orbit_camera_reference[0] + x_diff / 4 new_p = self.orbit_camera_reference[1] + y_diff / 4 target.set_hpr(new_h, new_p, 0.) def camera_pan(self, mouse_pos): """ Panea la camara alrededor del objetivo de ésta, según la posición del mouse respecto del punto donde se hizo click """ target = self.panda3d.camera if self.pan_mouse_reference is None: self.pan_mouse_reference = mouse_pos self.pan_camera_reference = target.get_pos() x_diff = self.pan_mouse_reference[0] - mouse_pos[0] y_diff = self.pan_mouse_reference[1] - mouse_pos[1] new_x = self.pan_camera_reference[0] + x_diff / 100 new_y = self.pan_camera_reference[1] new_z = self.pan_camera_reference[2] - y_diff / 100 target.set_pos(new_x, new_y, new_z) def camera_zoom(self, mouse_pos): """ Orbita la camara alrededor del objetivo de ésta, según la posición del mouse respecto del punto donde se hizo click """ target = self.panda3d.cam_target if self.zoom_mouse_reference is None: self.zoom_mouse_reference = mouse_pos self.zoom_camera_reference = target.getScale()[0] y_diff = self.zoom_mouse_reference[1] - mouse_pos[1] new_scale = self.zoom_camera_reference * math.exp(y_diff/100) new_scale = max(new_scale, 0.1) new_scale = min(new_scale, 10) target.setScale(new_scale, new_scale, new_scale) def zoom_in(self): if self.mouse_is_over_workspace(): target = self.panda3d.cam_target old_scale = target.getScale()[0] new_scale = old_scale - 0.1 * old_scale new_scale = max(new_scale, self.min_zoom) target.setScale(new_scale, new_scale, new_scale) def zoom_out(self): if self.mouse_is_over_workspace(): target = self.panda3d.cam_target old_scale = target.getScale()[0] new_scale = old_scale + 0.1 * old_scale new_scale = min(new_scale, self.max_zoom) target.setScale(new_scale, new_scale, new_scale) def show_view_gizmo(self): """ Agrega un indicador de ejes en la esquina inferior izquierda """ scale = 0.075 width = self.panda3d.win.getXSize()/100 height = self.panda3d.win.getYSize()/100 #self.corner.setPos(width / 2 - 10 * scale, 5, height / 2 - 28 * scale) self.corner.setPos(width / 2-1, 5, height / 2 - 2.4) print("DEBUG SHOW VIEW CUBE") print(height) print(height / 2 - 28 * scale) # Dibujar por encima de todos los objetos for gizmo_geom in self.view_gizmo: gizmo_geom.setLightOff(1) # gizmo_geom.setBin("fixed", 0) # gizmo_geom.set_two_sided(True) """ Tarea pendiente: Hay que corregir un error por el cual el indicador de ejes no se dubuja por encima de todos los objetos pudiendo intersectarse cona las geometrías del modelo Simplemente es un error visual, no afecta al funcionamiento axis.setDepthTest(False) https://discourse.panda3d.org/t/model-always-on-screen/8135/5 """ gizmo_geom.setScale(scale) # axis.setScale(1) gizmo_geom.reparentTo(self.corner) # gizmo_geom.setPos(0, 0, 0) gizmo_geom.setCompass() separation = 1 # gizmo_geom.setShaderInput("showborders", LVecBase4(0)) # gizmo_geom.setShaderInput("colorborders", LVecBase4(0, 0, 0, 0)) # gizmo_geom.setShaderInput("separation", LVecBase4(separation, 0, separation, 0)) def add_cube(self): """ Función de prueba, coloca cubos en la ubicación del cursor """ if self.panda3d.mouse_on_workspace: print("add_cube") pos = self.panda3d.work_plane_mouse cube = self.panda3d.loader.loadModel("models/box") # Reparent the model to render. cube.reparentTo(self.panda3d.render) # Apply scale and position transforms on the model. cube.setScale(0.25, 0.25, 0.25) cube.setPos(pos[0], pos[1], pos[2]) def entity_select(self): if self.panda3d.mouseWatcherNode.hasMouse(): """traverser = CollisionTraverser("") #traverser.show_collisions(render) picker_ray = CollisionRay() handler = CollisionHandlerQueue() picker_node = CollisionNode('mouseRay') picker_np = self.panda3d.camera.attachNewNode(picker_node) picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask()) picker_ray = CollisionRay() picker_node.addSolid(picker_ray) traverser.addCollider(picker_np, handler) picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask()) mpos = self.panda3d.mouseWatcherNode.getMouse() picker_ray.setFromLens(self.panda3d.camNode, mpos.getX(), mpos.getY()) traverser.traverse(self.panda3d.render)""" self.picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask()) mpos = self.panda3d.mouseWatcherNode.getMouse() self.picker_ray.setFromLens(self.panda3d.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(self.panda3d.render) handler = self.handler # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue. btn = self.panda3d.mouseWatcherNode if handler.getNumEntries() > 0: # This is so we get the closest object. handler.sortEntries() entity = handler.getEntry(0).getIntoNodePath() entity = entity.findNetTag('entity_id') if not entity.isEmpty(): #print("entity selected: {}".format(entity.getTag("entity_id"))) entity_id = entity.getTag("entity_id") entity_type = entity.getTag("entity_type") #print(entity_type) model = app.model_reg category_type = model.get(entity_type, dict()) entity = category_type.get(entity_id, None) #print(entity) if btn.isButtonDown("mouse1"): entity.on_click() if entity.is_editable: prop_editor = app.main_ui.prop_editor prop_editor.entity_read(entity) elif entity.is_selectable: status_bar = app.main_ui.status_bar status_bar.entity_read(entity) else: print("Hay {} entidades bajo el mouse".format(handler.getNumEntries())) else: if btn.isButtonDown("mouse1"): entities = app.model_reg.get("View", {}) if entities is None or len(entities) is 0: View() entities = app.model_reg.get("View") entity = list(entities.values())[0] prop_editor = app.main_ui.prop_editor prop_editor.entity_read(entity) else: status_bar = app.main_ui.status_bar status_bar.entity_read()
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 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 FollowCamera(TerrainCamera): def __init__(self, fulcrum, terrain): TerrainCamera.__init__(self) self.terrain = terrain self.fulcrum = fulcrum # in behind Ralph regardless of ralph's movement. self.camNode.reparentTo(fulcrum) # How far should the camera be from Ralph self.cameraDistance = 30 # Initialize the pitch of the camera self.cameraPitch = 10 self.focus = self.fulcrum.attachNewNode("focus") self.maxDistance = 500.0 self.minDistance = 2 self.maxPitch = 80 self.minPitch = -70 # 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. # 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.cameraRay = CollisionSegment(self.fulcrum.getPos(), (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.fulcrum.attachNewNode(self.cameraCol) self.cameraColHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.cameraColNp, self.cameraColHandler) def zoom(self, zoomIn): if (zoomIn): self.cameraDistance += 0.1 * self.cameraDistance; else: self.cameraDistance -= 0.1 * self.cameraDistance; if self.cameraDistance < self.minDistance: self.cameraDistance = self.minDistance if self.cameraDistance > self.maxDistance: self.cameraDistance = self.maxDistance def update(self, x, y): # alter ralph's yaw by an amount proportionate to deltaX self.fulcrum.setH(self.fulcrum.getH() - 0.3 * x) # find the new camera pitch and clamp it to a reasonable range self.cameraPitch = self.cameraPitch + 0.1 * y if (self.cameraPitch < self.minPitch): self.cameraPitch = self.minPitch if (self.cameraPitch > self.maxPitch): self.cameraPitch = self.maxPitch self.camNode.setHpr(0, self.cameraPitch, 0) # set the camera at around ralph's middle # We should pivot around here instead of the view target which is noticebly higher self.camNode.setPos(0, 0, 0) # back the camera out to its proper distance self.camNode.setY(self.camNode, self.cameraDistance) self.fixHeight() correctedDistance = self.camNode.getPos().length() # point the camera at the view target forwardOffset = -math.sin(math.radians(self.cameraPitch)) verticalOffset = 1- math.sin(math.radians(self.cameraPitch)) self.focus.setPos(0, forwardOffset, verticalOffset + correctedDistance / 8.0) #keep camera from flipping over if self.focus.getY() > self.camNode.getY()*0.9: self.focus.setY(self.camNode.getY()*0.9) self.camNode.lookAt(self.focus) # reposition the end of the camera's obstruction ray trace self.cameraRay.setPointB(self.camNode.getPos()) # We will detect anything obstructing the camera via a ray trace # from the view target around the avatar's head, to the desired camera # podition. If the ray intersects anything, we move the camera to the # the first intersection point, This brings the camera in between its # ideal position, and any present obstructions. # 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.ralph).getY(), # -x.getSurfacePoint(self.ralph).getY())) # if (len(entries)>0): # collisionPoint = entries[0].getSurfacePoint(self.ralph) # collisionVec = ( viewTarget - collisionPoint) # if ( collisionVec.lengthSquared() < self.cameraDistance * self.cameraDistance ): # self.camNode.setPos(collisionPoint) # if (entries[0].getIntoNode().getName() == "terrain"): # self.camNode.setZ(base.camera, 0.2) # self.camNode.setY(base.camera, 0.3) # def fixHeight(self): pos = self.camNode.getPos(render) minZ = self.terrain.getElevation(pos.x, pos.y) + 1.2 #logging.info( minZ) if pos.z < minZ: pos.z = minZ self.camNode.setPos(render, pos)
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 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 MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) ################ #Terrain ################ ####### #self.environ = GeoMipTerrain("terrain") #self.environ.setHeightfield("../terrain/first.png") #self.environ.setColorMap("../terrain/first-c.png") #self.environ.generate() #self.environ.getRoot().setScale(1, 1, 100) #self.environ.getRoot().setPos(0, 0, 0) #self.environ.getRoot().reparentTo(render) #self.environ.getRoot().setName("terrain") #self.environ.getRoot().setCollideMask(BitMask32.bit(0)) ####### self.environ = loader.loadModel("models/environment") self.environ.setScale(.25, .25, .25) self.environ.reparentTo(render) self.environ.setCollideMask(BitMask32.bit(0)) ################ #Game objects ################ self.pandaActor = Actor("models/panda", {"walk": "models/panda-walk"}) self.pandaActor.setScale(.5, .5, .5) self.pandaActor.setHpr(180, 0, 0) #self.pandaActor.setPos(50, 50, 50) self.pandaActor.setPythonTag("moving", False) self.pandaActor.setCollideMask(BitMask32.allOff()) self.avatarYawRot = 0 self.avatarPitchRot = 0 #self.teapot = loader.loadModel("models/teapot") #self.teapot.setScale(1, 1, 1) #self.teapot.setPos(60, 60, 50) #self.teapot.reparentTo(render) self.last_mouse_y = self.win.getPointer(0).getY() ################ #Physics ################ base.enableParticles() self.avatarNP=base.render.attachNewNode(ActorNode("actor")) # Sets up the mass. Note that in this scenario, mass is not taken into consideration. self.avatarNP.node().getPhysicsObject().setMass(100.) self.avatarNP.setPos(0,0,0) # Parent our avatar to the ready to go physics node self.pandaActor.reparentTo(self.avatarNP) gravityFN=ForceNode('world-forces') gravityFNP=render.attachNewNode(gravityFN) gravityForce=LinearVectorForce(0,0,-.1) gravityForce.setMassDependent(False) gravityFN.addForce(gravityForce) # Attach it to the global physics manager base.physicsMgr.addLinearForce(gravityForce) base.physicsMgr.attachPhysicalNode(self.avatarNP.node()) ################ #Collisions ################ self.cTrav = CollisionTraverser() self.cTrav.showCollisions(base.render) self.pandaGroundRay = CollisionSphere(0,0,0,1) self.pandaGroundRayNode = CollisionNode('pandaGroundRay') self.pandaGroundRayNode.addSolid(self.pandaGroundRay) self.pandaGroundRayNode.setFromCollideMask(BitMask32.bit(0)) self.pandaGroundRayNode.setIntoCollideMask(BitMask32.allOff()) self.pandaGroundRayNodepath = self.avatarNP.attachNewNode(self.pandaGroundRayNode) self.pandaGroundRayNodepath.show() self.pandaGroundCollisionHandler = PhysicsCollisionHandler() self.pandaGroundCollisionHandler.addCollider(self.pandaGroundRayNodepath, self.avatarNP) self.cTrav.addCollider(self.pandaGroundRayNodepath, self.pandaGroundCollisionHandler) #self.teapotRay = CollisionSphere(0,0,0,5) #self.teapotGroundCol = CollisionNode('teapotRay') #self.teapotGroundCol.addSolid(self.teapotRay) #self.teapotGroundCol.setFromCollideMask(BitMask32.allOff()) #self.teapotGroundCol.setIntoCollideMask(BitMask32.bit(0)) #self.teapotGroundColNp = self.teapot.attachNewNode(self.teapotGroundCol) #self.teapotGroundHandler = CollisionHandlerQueue() #self.cTrav.addCollider(self.teapotGroundColNp, self.teapotGroundHandler) ################ #Camera ################ self.disableMouse() self.cam_away = 20 self.cam_elevation = 0 self.rot_rate = .5 self.cam_dist = (self.cam_away**2 + self.cam_elevation**2) ** .5 self.cam.setHpr(0, 0, 0) ################ #Events ################ self.taskMgr.add(self.gameLoop, "gameLoop", priority = 35) self.keys = {"w" : 0, "s" : 0, "a" : 0, "d" : 0} self.accept("w", self.setKey, ["w", 1]) self.accept("w-up", self.setKey, ["w", 0]) self.accept("s", self.setKey, ["s", 1]) self.accept("s-up", self.setKey, ["s", 0]) self.accept("a", self.setKey, ["a", 1]) self.accept("a-up", self.setKey, ["a", 0]) self.accept("d", self.setKey, ["d", 1]) self.accept("d-up", self.setKey, ["d", 0]) self.accept("wheel_up", self.zoomCamera, [-1]) self.accept("wheel_down", self.zoomCamera, [1]) self.accept('window-event', self.handleWindowEvent) props = WindowProperties() props.setCursorHidden(True) base.win.requestProperties(props) self.last_mouse_x = self.win.getPointer(0).getX() def setKey(self, key, value): self.keys[key] = value def handleWindowEvent(self, window=None): wp = window.getProperties() self.win_center_x = wp.getXSize() / 2 self.win_center_y = wp.getYSize() / 2 def zoomCamera(self, direction): self.cam_away += direction def gameLoop(self, task): dt = globalClock.getDt() #self.avatarNP.setY(self.avatarNP, 10 * dt) if self.keys["w"]: self.avatarNP.setZ(self.avatarNP, 5 * dt) if self.keys["s"]: self.avatarNP.setZ(self.avatarNP, -5 * dt) if self.keys["a"]: self.avatarNP.setX(self.avatarNP, -5 * dt) if self.keys["d"]: self.avatarNP.setX(self.avatarNP, 5 * dt) #Mouse-based viewpoint rotation mouse_pos = self.win.getPointer(0) current_mouse_x = mouse_pos.getX() current_mouse_y = mouse_pos.getY() mouse_shift_x = current_mouse_x - self.last_mouse_x mouse_shift_y = current_mouse_y - self.last_mouse_y self.last_mouse_x = current_mouse_x self.last_mouse_y = current_mouse_y if current_mouse_x == 0 or current_mouse_x >= (self.win_center_x * 1.5): base.win.movePointer(0, self.win_center_x, self.win_center_y) self.last_mouse_x = self.win_center_x if current_mouse_y == 0 or current_mouse_y >= (self.win_center_y * 1.5): base.win.movePointer(0, self.win_center_x, self.win_center_y) self.last_mouse_y = self.win_center_y #self.cam.setP(0) yaw_shift = -((mouse_shift_x) * self.rot_rate) pitch_shift = -((mouse_shift_y) * self.rot_rate) self.avatarYawRot += yaw_shift self.avatarPitchRot += pitch_shift self.avatarNP.setH(self.avatarYawRot) self.cam.setH(self.avatarYawRot) self.cam.setP(-self.avatarPitchRot) xy_plane_cam_dist = self.cam_away*cos(radians(self.avatarPitchRot)) cam_x_adjust = xy_plane_cam_dist*sin(radians(self.avatarYawRot)) cam_y_adjust = xy_plane_cam_dist*cos(radians(self.avatarYawRot)) cam_z_adjust = self.cam_away*sin(radians(self.avatarPitchRot)) print self.camera.getPos() self.cam.setPos(self.avatarNP.getX() + cam_x_adjust, self.avatarNP.getY() - cam_y_adjust, self.avatarNP.getZ() + cam_z_adjust) print self.avatarNP.getPos() #self.cam.setP(self.x) #self.x += .01 #self.cTrav.traverse(render) #entries = [] #for i in range(self.pandaGroundCollisionHandler.getNumEntries()): # entry = self.pandaGroundCollisionHandler.getEntry(i) # entries.append(entry) #for entry in entries: # print entry.getIntoNode().getName() # if entry.getIntoNode().getName() == "terrain": # print "shiet" # self.pandaActor.setZ(entry.getSurfacePoint(render).getZ()) return Task.cont
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 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 App(ShowBase): def __init__(self): ShowBase.__init__(self) base.disableMouse() #Carrega o terreno self.terrain = loadCharEnvir().loadEnvir() #Declaracao de variaveis self.isMoving = False self.getClick = 0 #Quantos objetos foram clicados self.clickedObj = None self.terrainSize = 1024 self.numLizards = 5 self.numMaleLizards = 0 self.numFemaleLizards = 0 #self.contChamGetMed = 0 #Contador para saber se atualiza o ponto medio #Carrega os lagartos iniciais self.lizards = [] for i in range(self.numLizards): randNum = random.randint(10,20) randNum2 = random.randint(10,20) lizard = loadCharEnvir().loadLizard(100 + (randNum+randNum2)*i,150 + (randNum+randNum2)*i,3) lizard.setTag("ID",str(i)) self.lizards.append(lizard) if (lizard.getTag("femaleOrMale") == "1"): self.numMaleLizards = self.numMaleLizards + 1 else: self.numFemaleLizards = self.numFemaleLizards + 1 #Calcula o ponto medio dos lagartos, tanto femeas quantos machos self.getMedianGenderPoints() #taskMgr.add(self.getCloserToMedian, "Aproxima os lagartos do ponto medio dos generos") #Adiciona as tasks e as funcoes de teclado e mouse self.taskMgr.add(self.updateTask, "update") self.keyboardSetup() #CAMERAS: #Faz a camera seguir o lagarto #self.followcam = FollowCam(self.camera, self.lizards[0]) #Faz a camera visualizar como um deus self.MoveCam = MoveCam(self.camera) #Ativa as colisoes self.setupMouseCollision() #Funcao que ajusta o angulo def clampAngle(self, angle): while angle < -180: angle = angle + 360 while angle > 180: angle = angle -360 return angle #Atribui um valor especifico para uma chave def keyboardSetup(self): self.keyMap = {"left":0, "right":0, "forward":0, "backward":0} self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_up", self.setKey, ["forward", 1]) self.accept("arrow_up-up", self.setKey, ["forward", 0]) self.accept("arrow_down", self.setKey, ["backward", 1]) self.accept("arrow_down-up", self.setKey, ["backward", 0]) self.accept("mouse1", self.leftMouseCommands) #Pode ser adicionado um drag aqui self.accept("mouse3", self.rightMouseCommands) #Funcao que calcula o ponto medio da densidade de lagartos de cada genero def getMedianGenderPoints(self): self.medianMalePoint = (0,0,0) self.medianFemalePoint = (0,0,0) #Calculo do somatorio dos pontos para cada genero for i in range(self.numLizards): if (self.lizards[i].getTag("femaleOrMale") == "1"): self.medianMalePoint = self.lizards[i].getPos() + self.medianMalePoint else: self.medianFemalePoint = self.lizards[i].getPos() + self.medianFemalePoint #Calculo do ponto medio de cada genero if (self.numMaleLizards != 0): self.medianMalePoint = (self.medianMalePoint[0]/self.numMaleLizards, self.medianMalePoint[1]/self.numMaleLizards, self.medianMalePoint[2]/self.numMaleLizards) if (self.numFemaleLizards != 0): self.medianFemalePoint = (self.medianFemalePoint[0]/self.numFemaleLizards, self.medianFemalePoint[1]/self.numFemaleLizards, self.medianFemalePoint[2]/self.numFemaleLizards) #===================================================================================== #NAO ESTA PRONTA // NAO FUNCIONA #Funcao que faz com que os lagartos, dependendo do genero, aproximem-se #===================================================================================== """ def getCloserToMedian(self, task): maleMedianPoint = render.attachNewNode("male median point") maleMedianPoint.setPos(self.medianMalePoint) femaleMedianPoint = render.attachNewNode("female median point") femaleMedianPoint.setPos(self.medianFemalePoint) for i in range(self.numLizards): #Se for macho, procura for femeas if (self.lizards[i].getTag("femaleOrMale") == 1): lizardAuxPoint = render.attachNewNode("ponto auxiliar para obter heading") lizardAuxPoint.setPos(self.lizards[i].getPos()) lizardAuxPoint.lookAt(femaleMedianPoint) self.lizards[i].setH(self.clampAngle(lizardAuxPoint.getH() + 180)) self.lizards[i].setPos(self.lizards[i], self.lizards[i].getRelativeVector(femaleMedianPoint, Vec3(0.1,-0.1,0))) print self.lizards[i].getRelativeVector(femaleMedianPoint, Vec3(0.1,-0.1,0)) #Respeitando os limites do terreno if (self.lizards[i].getX() < 0): self.lizards[i].setX(0) elif (self.lizards[i].getX() > self.terrainSize): self.lizards[i].setX(self.terrainSize) if (self.lizards[i].getY() < 0): self.lizards[i].setY(0) elif (self.lizards[i].getY() > self.terrainSize): self.lizards[i].setY(self.terrainSize) #Se for femea, procura por machos else: self.lizards[i].lookAt(maleMedianPoint) self.lizards[i].setPos(self.lizards[i], self.lizards[i].getRelativeVector(maleMedianPoint, Vec3(0.1,-0.1,0))) #Respeitando os limites do terreno if (self.lizards[i].getX() < 0): self.lizards[i].setX(0) elif (self.lizards[i].getX() > self.terrainSize): self.lizards[i].setX(self.terrainSize) if (self.lizards[i].getY() < 0): self.lizards[i].setY(0) elif (self.lizards[i].getY() > self.terrainSize): self.lizards[i].setY(self.terrainSize) #Faz uma atualizacao pra saber se deve atualizar o ponto medio self.contChamGetMed = self.contChamGetMed + 1 if (self.contChamGetMed == 1000): self.contChamGetMed = 0 self.getMedianGenderPoints() return task.cont""" #===================================================================================== #A ATRIBUICAO DO BOTAO DIREITO SERA COMPLETAMENTE REFEITA, E ESTA SERVE APENAS PARA ILUSTRAR A IDEIA #ESTA ATRIBUICAO ESTA ERRADA #===================================================================================== def rightMouseCommands(self): if self.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() if (self.clickedObj != None): self.moveCharacter(mpos.getX(), mpos.getY()) #FUNCAO PROVISORIA: #FALTA AJUSTAR - COMO FAZER PARA OPERAR AS ENTRADAS SEPARADAMENTE? def moveCharacter(self, posX, posY): self.mClickRay.setFromLens(self.camNode, posX, posY) self.mClicker.traverse(self.render) if (self.mCollisionQue.getNumEntries() > 0): self.mCollisionQue.sortEntries() entry = self.mCollisionQue.getEntry(0) self.target = render.attachNewNode("target point") self.target.setPos(2*self.clickedObj.getX() - entry.getSurfacePoint(render).getX(), 2*self.clickedObj.getY() - entry.getSurfacePoint(render).getY(), entry.getSurfacePoint(render).getZ()) self.finalPosY = self.target.getY() self.finalPosX = self.target.getX() finalHeading = render.attachNewNode("final heading") finalHeading.setPos(self.clickedObj.getPos()) finalHeading.lookAt(self.target.getPos()) self.Heading = finalHeading.getH() self.Heading = self.clampAngle(self.Heading) if (self.Heading-self.clickedObj.getH() > 150): turnTime = 4 else: if (self.Heading-self.clickedObj.getH() > 100): turnTime = 3 else: if (self.Heading-self.clickedObj.getH() > 50): turnTime = 2 else: if (self.Heading-self.clickedObj.getH() < -50): turnTime = 2 else: if (self.Heading-self.clickedObj.getH() < -100): turnTime = 3 else: if (self.Heading-self.clickedObj.getH() < -150): turnTime = 4 else: turnTime = 1 self.deltaSX = self.target.getX()-self.clickedObj.getX() self.deltaSY = self.target.getY()-self.clickedObj.getY() self.deltaS = sqrt((self.target.getY()-self.clickedObj.getY())*(self.target.getY()-self.clickedObj.getY()) + (self.target.getX()-self.clickedObj.getX())*(self.target.getX()-self.clickedObj.getX())) t = self.deltaS/3 changeHeading = self.clickedObj.hprInterval(turnTime, (self.Heading,0,0), (self.clickedObj.getH(),0,0)) changePos = self.clickedObj.posInterval(t, self.target.getPos(), self.clickedObj.getPos()) self.clickedObj.loop("walk", restart = 0) self.counter = 0 moveInterv = Sequence(changeHeading, Func(self.stopAnimation)) moveInterv.start() def stopAnimation(self): taskMgr.add(self.movingCharacter, "moving character") def movingCharacter(self,task): if self.counter < 130: self.clickedObj.setX(self.clickedObj.getX() - self.deltaSX/130) self.clickedObj.setY(self.clickedObj.getY() - self.deltaSY/130) self.counter = self.counter + 1 return task.cont else: self.clickedObj.stop() taskMgr.remove("moving character") #===================================================================================== #===================================================================================== #===================================================================================== #Atribui valor a uma chave def setKey(self, key, value): self.keyMap[key] = value #Atualiza o game def updateTask(self, task): self.updateLizard() return Task.cont #Funcao do botao esquerdo do mouse def leftMouseCommands(self): if self.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.mClickRay.setFromLens(self.camNode, mpos.getX(), mpos.getY()) self.mClicker.traverse(self.render) if (self.mCollisionQue.getNumEntries() > 0): self.mCollisionQue.sortEntries() entry = self.mCollisionQue.getEntry(0) clickedObject = entry.getIntoNodePath() clickedObject = clickedObject.findNetTag("clickable") if not clickedObject.isEmpty(): pos = entry.getSurfacePoint(self.render) self.getClick = 1 clickedObjectId = clickedObject.findNetTag("ID") self.clickedObjId = clickedObjectId #Procura o lagarto clicado for i in range(self.numLizards): if (self.lizards[i].getTag("ID") == self.clickedObjId.getTag("ID")): self.clickedObj = self.lizards[i] return else: #Zera se nao houverem objetos clicaveis proximos self.getClick = 0 #Define a colisao do mouse com objetos no terreno def setupMouseCollision(self): self.mClicker = CollisionTraverser() self.mCollisionQue = CollisionHandlerQueue() self.mClickRay = CollisionRay() self.mClickRay.setOrigin(self.camera.getPos(self.render)) self.mClickRay.setDirection(render.getRelativeVector(camera, Vec3(0,1,0))) self.mClickNode = CollisionNode('clickRay') self.mClickNode.addSolid(self.mClickRay) self.mClickNP = self.camera.attachNewNode(self.mClickNode) self.mClickNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.mClicker.addCollider(self.mClickNP, self.mCollisionQue) #Atualiza o personagem se algum botao foi pressionado #POSTERIORMENTE SERA RETIRADA - ESTA AQUI APENAS PARA DEBUG/EXEMPLIFICACAO def updateLizard(self): speedFactor = 3 if (self.getClick != 0): #Se o personagem esta se mexendo, rode a animacao #BUG - Se o jogador estiver pressionando o botao de andar enquanto muda de personagem, trava a animacao 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.clickedObj.loop("walk", restart = 0) self.isMoving = True else: if self.isMoving: self.clickedObj.stop() self.isMoving = False #if (self.clicked != None): if (self.keyMap["left"]!=0): self.clickedObj.setH(self.clickedObj.getH()+1) elif (self.keyMap["right"]!=0): self.clickedObj.setH(self.clickedObj.getH()-1) if (self.keyMap["forward"]!=0): self.clickedObj.setY(self.clickedObj, -speedFactor) elif (self.keyMap["backward"]!=0): self.clickedObj.setY(self.clickedObj, speedFactor) #Respeitando os limites do terreno if (self.clickedObj.getX() < 0): self.clickedObj.setX(0) elif (self.clickedObj.getX() > self.terrainSize): self.clickedObj.setX(self.terrainSize) if (self.clickedObj.getY() < 0): self.clickedObj.setY(0) elif (self.clickedObj.getY() > self.terrainSize): self.clickedObj.setY(self.terrainSize)
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 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 Game(ShowBase): def __init__(self): ShowBase.__init__(self) #Background sound (does not play infinitely) self.backgroundSound = base.loader.loadSfx("sounds/DireDireDocks.mp3") taskMgr.add(self.update, "moveTask") #Disable the mouse so that we may use it for our control scheme. self.props = WindowProperties() self.props.setSize(1920, 1080) self.props.setFullscreen(True) self.props.setCursorHidden(True) base.win.requestProperties(self.props) base.disableMouse() self.buildKeyMap() self.inMenu = True self.menuScreen = OnscreenImage("titlescreen.png", (0, .01, 0)) self.menu() def initialize(self): self.timer = 0 base.enableParticles() #base.setFrameRateMeter(True) ########## # # SETUP COLLISION HANDLERS AND FLAMIE'S MODEL # ########## #Create the collision handlers in order to build the level. WALL_MASK = BitMask32.bit(2) FLOOR_MASK = BitMask32.bit(1) #Start up the collision system self.cTrav = CollisionTraverser() #Determine how collisions with walls will be handled self.wallHandler = CollisionHandlerPusher() self.bobbing = False #Setup flamie's model self.flamieNP = base.render.attachNewNode(ActorNode('flamieNP')) self.flamieNP.reparentTo(base.render) self.flamie = loader.loadModel('models/Flame/body') self.flamie.setScale(.5) self.flamie.setTransparency(TransparencyAttrib.MAlpha) self.flamie.setAlphaScale(0) self.flamie.reparentTo(self.flamieNP) self.flamie.setCollideMask(BitMask32.allOff()) flameLight = DirectionalLight("flameLight") fl = self.flamie.attachNewNode(flameLight) fl.setColor(255, 255, 255, 1) flameLight.setDirection((-5, -5, -5)) self.flamie.setLight(fl) self.flamie2 = loader.loadModel("models/p.obj") self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f7.png")) self.flamie2.reparentTo(self.flamieNP) self.flamie2.setScale(4) self.flamie2OriZ = 2 self.flamie2.setPos(-6.5, 0, self.flamie2OriZ) #(length, depth, height) self.flamie2.setLight(fl) self.flamie2.setTransparency(TransparencyAttrib.MAlpha) self.flamieFire = PointLight('fire') self.flamieFire.setColor(VBase4(1,1,1,1)) self.flamieFire.setAttenuation((1,0,1)) plnp = render.attachNewNode(self.flamieFire) plnp.setPos(self.flamieNP.getPos()) self.flamielight = AmbientLight('light') self.flamielight.setColor(VBase4(1, 0.5, 0.6, 1)) self.flamielight = self.flamie2.attachNewNode(self.flamielight) self.flamie2.setLight(self.flamielight) self.flamie2.setLight(plnp) self.mayFlamieBob = True #self.flamie2.setAlphaScale(0.5) '''self.tree = loader.loadModel("models/p2.obj") self.tree.setTexture(loader.loadTexture("deadTree.png")) self.tree.reparentTo(render) self.tree.setScale(4) self.tree.setPos(25,25,0) #(length, depth, height) self.tree.setLight(fl) self.tree.setTransparency(TransparencyAttrib.MAlpha) self.treelight = AmbientLight('light') self.treelight.setColor(VBase4(0.9, 0.9, 0.6, 1)) self.treelight = self.tree.attachNewNode(self.treelight) self.tree.setLight(self.treelight)''' x = 150 y = 20 offset1 = 0 treeList2 = [loader.loadModel("models/p2.obj") for i in range(7)] for j in treeList2: k = random.randint(1, 100) if k%5 is 1 or k%5 is 2: j.setTexture(loader.loadTexture("deadTree.png")) else: j.setTexture(loader.loadTexture("tree.png")) j.reparentTo(render) j.setScale(random.randint(4,7)) j.setTransparency(TransparencyAttrib.MAlpha) j.setPos(x + 3*offset1, y + 4*offset1, 0) treelight = AmbientLight('light') treelight = j.attachNewNode(treelight) j.setLight(treelight) offset1 = offset1 + random.randint(4, 10) x = 4 y = 90 offset1 = 0 treeList2 = [loader.loadModel("models/p2.obj") for i in range(6)] for j in treeList2: k = random.randint(1, 100) if k%5 is 1 or k%5 is 2: j.setTexture(loader.loadTexture("deadTree.png")) else: j.setTexture(loader.loadTexture("tree.png")) j.reparentTo(render) j.setScale(random.randint(4,7)) j.setTransparency(TransparencyAttrib.MAlpha) j.setPos(x + 3*offset1, y + 4*offset1, 0) treelight = AmbientLight('light') treelight = j.attachNewNode(treelight) j.setLight(treelight) offset1 = offset1 + random.randint(4, 10) x = 3 y = 120 offset1 = 0 treeList2 = [loader.loadModel("models/p2.obj") for i in range(4)] for j in treeList2: k = random.randint(1, 100) if k%5 is 1 or k%5 is 2: j.setTexture(loader.loadTexture("deadTree.png")) else: j.setTexture(loader.loadTexture("tree.png")) j.reparentTo(render) j.setScale(random.randint(4,7)) j.setTransparency(TransparencyAttrib.MAlpha) j.setPos(x + 3*offset1, y + 4*offset1, 0) treelight = AmbientLight('light') treelight = j.attachNewNode(treelight) j.setLight(treelight) offset1 = offset1 + random.randint(4, 10) x = 200 y = 20 offset1 = 0 treeList2 = [loader.loadModel("models/p2.obj") for i in range(4)] for j in treeList2: k = random.randint(1, 100) if k%5 is 1 or k%5 is 2: j.setTexture(loader.loadTexture("deadTree.png")) else: j.setTexture(loader.loadTexture("tree.png")) j.reparentTo(render) j.setScale(random.randint(4,7)) j.setTransparency(TransparencyAttrib.MAlpha) j.setPos(x + 3*offset1, y + 4*offset1, 0) treelight = AmbientLight('light') treelight = j.attachNewNode(treelight) j.setLight(treelight) offset1 = offset1 + random.randint(4, 10) ### Something that should look like water ### w = loader.loadModel("models/flatP.obj") w.setTexture(loader.loadTexture("ice.png")) w.reparentTo(render) w.setScale(75) w.setTransparency(TransparencyAttrib.MAlpha) w.setAlphaScale(.7) w.setLight(treelight) w.setPos(-200, 0, -10) self.waterOrigiZ = -10 self.waterSecZ = -95 self.waterThirdZ = -120 self.water = w ### Reskying the sky ### w = loader.loadModel("models/biggerFlatP.obj") w.setTexture(loader.loadTexture("models/n2.jpg")) w.reparentTo(self.flamie2) w.setScale(15) w.setLight(treelight) w.setPos(-200, 450, -200) #(length, depth, height) #Give flamie gravity self.floorHandler = CollisionHandlerGravity() self.floorHandler.setGravity(9.81+100) self.floorHandler.setMaxVelocity(100) ########## # # GENERATING LEVEL PARTS # ########## self.ice_reset = () self.start = PlatformSeg(LVector3(0,0,0)) self.start.generateAllParts(render) self.checkpointCreator(70, 90, self.start.pos.z, 10) self.floater = False for p in self.start.parts: if isinstance(p, Prism): self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, p.dep, 'terraincollision', 'wallcollision') if isinstance(p, Square): self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, 3, 'terraincollision', 'wallcollision') if isinstance(p, IceCube): p.model.setCollideMask(BitMask32.allOff()) self.ice_reset += (p,) iceCubefloor= p.model.find("**/iceFloor") iceCubewall = p.model.find("**/iceWall") iceCubefloor.node().setIntoCollideMask(FLOOR_MASK) iceCubewall.node().setIntoCollideMask(WALL_MASK) self.lostWood = LostWood(LVector3(self.start.pos.x + 750, self.start.parts[0].pos.y + self.start.parts[0].wid, self.start.pos.z)) self.lostWood.generateAllParts(render) self.checkpointCreator(self.lostWood.pos.x+120, self.lostWood.pos.y+150, self.lostWood.pos.z,20) self.checkpointCreator(self.lostWood.parts[6].pos.x + self.lostWood.parts[6].len/2, self.lostWood.parts[6].pos.y + self.lostWood.parts[6].wid/2, self.lostWood.pos.z, 40) for p in self.lostWood.parts: if isinstance(p, Prism): self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, p.dep, 'terraincollision', 'wallcollision') if isinstance(p, Square): self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, 3, 'terraincollision', 'wallcollision') if isinstance(p, IceCube): p.model.setCollideMask(BitMask32.allOff()) self.ice_reset += (p,) iceCubefloor= p.model.find("**/iceFloor") iceCubewall = p.model.find("**/iceWall") iceCubefloor.node().setIntoCollideMask(FLOOR_MASK) iceCubewall.node().setIntoCollideMask(WALL_MASK) self.cave = Cave(LVector3(self.lostWood.pos.x + 1100, self.lostWood.pos.y + 2000, self.lostWood.pos.z - 50)) self.cave.generateAllParts(render) self.checkpointCreator(self.cave.thirdRoomParts[5].pos.x + self.cave.thirdRoomParts[5].len/2, self.cave.thirdRoomParts[5].pos.y + self.cave.thirdRoomParts[5].wid/2, self.cave.thirdRoomParts[5].pos.z, 30) for p in self.cave.parts: if isinstance(p, Prism): self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, p.dep, 'terraincollision', 'wallcollision') if isinstance(p, Square): self.collisionBoxCreator(p.pos.x, p.pos.y, p.pos.z, p.len, p.wid, 3, 'terraincollision', 'wallcollision') if isinstance(p, IceCube): p.model.setCollideMask(BitMask32.allOff()) self.ice_reset += (p,) iceCubefloor= p.model.find("**/iceFloor") iceCubewall = p.model.find("**/iceWall") iceCubefloor.node().setIntoCollideMask(FLOOR_MASK) iceCubewall.node().setIntoCollideMask(WALL_MASK) self.end = End(LVector3(self.cave.thirdRoomParts[8].pos.x - 200, self.cave.thirdRoomParts[8].pos.y + self.cave.thirdRoomParts[8].wid, self.cave.thirdRoomParts[8].pos.z)) self.end.generate(render) self.collisionBoxCreator(self.end.floor.pos.x, self.end.floor.pos.y, self.end.floor.pos.z, self.end.floor.len, self.end.floor.wid, self.end.floor.dep, 'terraincollision', 'wallcollision') ######### # DRAWING THE CABIN AND FINAL CAMPFIRE ######### self.checkpointCreator(self.end.floor.pos.x + self.end.floor.len/2, self.end.floor.pos.y + self.end.floor.wid/2, self.end.floor.pos.z, 30) self.cabin = loader.loadModel("models/p2.obj") self.cabin.setTexture(loader.loadTexture("models/cabin.png")) self.cabin.setScale(50) self.cabin.reparentTo(render) self.cabin.setPos(self.end.floor.pos.x + self.end.floor.len/2, self.end.floor.pos.y + self.end.floor.wid/1.1, self.end.floor.pos.z) self.cabin.setTransparency(TransparencyAttrib.MAlpha) #Manually creating starting position. Copy and paste the first three parameters of the checkpoint you want to start at. self.startPos = LVector3(70, 90, self.start.pos.z) self.flamieNP.setPos(self.startPos) '''#Testing the tree model self.tree = loader.loadModel('models/Tree/log') self.tree.reparentTo(render) self.tree.setPos(-50,0,100) self.tree.setScale(2)''' '''#Add sky background self.sky = loader.loadModel('models/sphere.obj') self.sky.reparentTo(self.camera) self.sky.set_two_sided(True) self.skyTexture = loader.loadTexture("models/n2.jpg") self.sky.setTexture(self.skyTexture) self.sky.set_bin('background', 0) self.sky.set_depth_write(False) self.sky.set_compass()''' ########## # # CREATE FLAMIE'S COLLISION GEOMETRY # ########## #Give flamie a collision sphere in order to collide with walls flamieCollider = self.flamie.attachNewNode(CollisionNode('flamiecnode')) flamieCollider.node().addSolid(CollisionSphere(0,0,0,5)) flamieCollider.node().setFromCollideMask(WALL_MASK) flamieCollider.node().setIntoCollideMask(BitMask32.allOff()) self.wallHandler.addCollider(flamieCollider, self.flamieNP) self.cTrav.addCollider(flamieCollider, self.wallHandler) #Give flamie a collision ray to collide with the floor flamieRay = self.flamie.attachNewNode(CollisionNode('flamieRay')) flamieRay.node().addSolid(CollisionRay(0,0,8,0,0,-1)) flamieRay.node().setFromCollideMask(FLOOR_MASK) flamieRay.node().setIntoCollideMask(BitMask32.allOff()) self.floorHandler.addCollider(flamieRay, self.flamieNP) self.cTrav.addCollider(flamieRay, self.floorHandler) #Add a sensor that lets us melt ice cubes without standing on the cube. meltSensor = self.flamie.attachNewNode(CollisionNode('meltSensor')) cs = CollisionSphere(-2,0,10, 50) meltSensor.node().addSolid(cs) meltSensor.node().setFromCollideMask(WALL_MASK) meltSensor.node().setIntoCollideMask(BitMask32.allOff()) cs.setTangible(0) self.wallHandler.addCollider(meltSensor, self.flamieNP) self.cTrav.addCollider(meltSensor, self.wallHandler) self.wallHandler.addInPattern('%fn-into-%in') self.wallHandler.addAgainPattern('%fn-again-%in') self.accept('meltSensor-into-iceWall', self.melt) self.accept('meltSensor-again-iceWall', self.melt) self.accept('meltSensor-into-checkpointCol', self.newstart) #Add in an event handle to prevent the jumping glitch found on the bobbing ice cubes. self.floorHandler.addInPattern('%fn-into-%in') self.floorHandler.addAgainPattern('%fn-again-%in') self.floorHandler.addOutPattern('%fn-out-%in') self.accept('flamieRay-into-iceFloor', self.jittercancel) self.accept('flamieRay-again-iceFloor', self.jittercancel) self.accept('flamieRay-out-iceFloor', self.jittercanceloff) #Uncomment these lines to see flamie's collision geometry #flamieCollider.show() #flamieRay.show() #meltSensor.show() #Uncomment this line to see the actual collisions. #self.cTrav.showCollisions(render) #This plane is found at the very bottom of the level and adds global gravity. killfloor = CollisionPlane(Plane(Vec3(0,0,1), Point3(0,0,-1000))) killfloorCol = CollisionNode('kfcollision') killfloorCol.addSolid(killfloor) killfloorCol.setIntoCollideMask(BitMask32.bit(1)) killfloorColNp = self.render.attachNewNode(killfloorCol) #################### # # Setting light so that we could see the definition in the walls # #################### render.setShaderAuto() self.dlight = DirectionalLight('dlight') self.dlight.setColor(LVector4(0.3, 0.1, 0.7, 1)) dlnp = render.attachNewNode(self.dlight) dlnp.setHpr(90, 20, 0) render.setLight(dlnp) self.alight = render.attachNewNode(AmbientLight("Ambient")) self.alight.node().setColor(LVector4(0.5, 0.5, 1, .1)) render.setLight(self.alight) self.snow = loader.loadTexture("models/ground.jpg") #Create a floater object and have it float 2 units above fireball. #And use this as a target for the camera to focus on. #This idea is taken from the roaming ralph sample that came with the #Panda3D SDK. self.camFocus = NodePath(PandaNode("floater")) self.camFocus.reparentTo(render) self.camFocusCurrZ = self.flamie.getZ() + 10 #The camera is locked to the avatar so it always follows regardless of movement. self.camera.reparentTo(render) self.cameraTargetHeight = 8.0 self.cameraDistance = 100 self.cameraHeightModes = (self.start.parts[0].pos.z + 45, self.start.parts[0].pos.z + 125, self.camFocus.getZ() + 10, self.camFocus.getZ() + 150, self.end.floor.pos.z + 10) self.cameraHeight = self.cameraHeightModes[0] ################# # Changes Camera orientation depending on where the player is in the stage to compensate for the fact that # the player has no direct control of the camera. # Checks using the arrays from the level parts. ################## def cameraModes(self, delta): #Is the fireball within the platforming section between the starting area and the lost woods? #Is the fireball near the simple platforming sections of the LostWoods? #Is the fireball near the drop off point into the cave? #Is the fireball near the entrance to the second room in the cave? #If yes to any of these, bring the camera up to give a bird's eye view of the platforming if ((self.flamieNP.getX() > self.start.parts[1].pos.x and self.flamieNP.getY() > self.start.parts[1].pos.y - self.start.parts[1].wid and self.flamieNP.getX() < self.lostWood.parts[0].pos.x) or (self.flamieNP.getX() > self.lostWood.parts[0].pos.x + self.lostWood.parts[0].len/1.1 and self.flamieNP.getX() < self.lostWood.parts[2].pos.x + self.lostWood.parts[0].len/11 and self.flamieNP.getY() < self.lostWood.parts[0].pos.y + self.lostWood.parts[0].wid) or (self.flamieNP.getY() > self.cave.parts[0].pos.y - 20 and self.flamieNP.getY() <= self.cave.parts[0].pos.y + self.cave.parts[0].wid/2) or (self.flamieNP.getX() < self.cave.parts[1].pos.x + self.cave.parts[1].wid/10 and self.flamieNP.getY() >= self.cave.parts[1].pos.x)): camMode = 1 #Is the fireball in the beginning of the cave area? #If yes, bring the camera closer elif self.flamieNP.getY() > self.cave.parts[1].pos.y - self.cave.parts[0].wid/2 and self.flamieNP.getY() < self.cave.thirdRoomParts[5].pos.y: camMode = 2 else: camMode = 0 if self.flamieNP.getY() >= self.cave.thirdRoomParts[6].pos.y: self.cave.thirdRoomParts[0].hide() camMode = 3 if self.flamieNP.getY() >= self.cave.thirdRoomParts[8].pos.y + self.cave.thirdRoomParts[8].wid/1.5: camMode = 4 self.lerpCam(camMode, delta) def lerpCam(self, camMode, delta): CAMLERPSPEED = 25 if camMode == 0: if not self.cameraHeight == self.cameraHeightModes[camMode]: if self.cameraHeight - CAMLERPSPEED * delta <= self.cameraHeightModes[camMode]: self.cameraHeight = self.cameraHeightModes[camMode] else: self.cameraHeight = self.cameraHeight - CAMLERPSPEED * delta elif camMode == 1: if not self.cameraHeight == self.cameraHeightModes[camMode]: if self.cameraHeight - CAMLERPSPEED * delta >= self.cameraHeightModes[camMode]: self.cameraHeight = self.cameraHeightModes[camMode] else: if self.cameraHeight < self.cameraHeightModes[camMode]: self.cameraHeight = self.cameraHeight + CAMLERPSPEED * delta else: self.cameraHeight = self.cameraHeight - CAMLERPSPEED * delta elif camMode == 2: if not self.cameraHeight == self.cameraHeightModes[camMode]: if self.cameraHeight - CAMLERPSPEED * delta <= self.cameraHeightModes[camMode]: self.cameraHeight = self.cameraHeightModes[camMode] self.camFocusCurrZ = self.flamieNP.getZ() + 10 else: self.cameraHeight = self.cameraHeight - CAMLERPSPEED * delta self.camFocusCurrZ = self.flamieNP.getZ() + 10 elif camMode == 3: if not self.cameraHeight == self.cameraHeightModes[camMode]: if self.cameraHeight + CAMLERPSPEED * 3 * delta >= self.cameraHeightModes[camMode]: self.cameraHeight = self.cameraHeightModes[camMode] else: self.cameraHeight = self.cameraHeight + CAMLERPSPEED * 3 * delta elif camMode == 4: if not self.cameraHeight == self.cameraHeightModes[camMode]: if self.cameraHeight - CAMLERPSPEED * 3 * delta <= self.cameraHeightModes[camMode]: self.cameraHeight = self.cameraHeightModes[camMode] else: self.cameraHeight = self.cameraHeight - CAMLERPSPEED * 3 * delta def waterControl(self, delta): WATERLERPSPEED = .75 if self.flamieNP.getY() <= self.lostWood.parts[6].pos.y + self.lostWood.parts[6].wid/2: if not self.water.getZ() == self.waterOrigiZ: if self.water.getZ() - WATERLERPSPEED * delta < self.waterOrigiZ and self.water.getZ() > self.waterOrigiZ: self.water.setZ(self.waterOrigiZ) elif self.water.getZ() + WATERLERPSPEED * delta > self.waterOrigiZ and self.water.getZ() < self.waterOrigiZ: self.water.setZ(self.waterOrigiZ) else: if self.water.getZ() > self.waterOrigiZ: self.water.setZ(self.water, - WATERLERPSPEED * delta) if self.water.getZ() < self.waterOrigiZ: self.water.setZ(self.waterOrigiZ) else: self.water.setZ(self.water, + WATERLERPSPEED * delta) if self.water.getZ() > self.waterOrigiZ: self.water.setZ(self.waterOrigiZ) elif self.flamieNP.getY() <= self.cave.parts[1].pos.y: if not self.water.getZ() == self.waterSecZ: if self.water.getZ() - WATERLERPSPEED * delta < self.waterSecZ: self.water.setZ(self.waterSecZ) else: self.water.setZ(self.water, - WATERLERPSPEED * delta) else: if not self.water.getZ() == self.waterThirdZ: if self.water.getZ() - WATERLERPSPEED * delta < self.waterThirdZ: self.water.setZ(self.waterThirdZ) else: self.water.setZ(self.water, - WATERLERPSPEED * delta) def reset(self): self.flamieNP.setPos(self.startPos) self.camFocusCurrZ = self.flamieNP.getZ() + 10 for p in self.ice_reset: p.model.setScale(p.original_scale) def jump(self, dt): if self.bobbing: if self.floorHandler.getAirborneHeight() < 0.15: self.floorHandler.addVelocity(60) elif self.floorHandler.isOnGround(): self.floorHandler.addVelocity(60) def jittercancel(self, collEntry): model = collEntry.getIntoNodePath().getParent() modelRef = model.getPythonTag("iceRef") if model.getScale()[0] > 1.2: model.setScale(model.getScale()- modelRef.meltspeed) self.bobbing = True def jittercanceloff(self, collEntry): self.bobbing = False def melt(self, collEntry): model = collEntry.getIntoNodePath().getParent() modelRef = model.getPythonTag("iceRef") if model.getScale()[0] > 1.2 and self.bobbing != True: model.setScale(model.getScale()- modelRef.meltspeed) def newstart(self, collEntry): entry = collEntry.getInto().getCenter() self.startPos = (entry[0]+10, entry[1]+10, entry[2] +10) cp = loader.loadModel('models/Campfire/fire') cp.setPos(entry[0],entry[1], entry[2]) cp.reparentTo(render) def buildKeyMap(self): self.keyMap = {"left": 0, "right": 0, "forward": 0, "back": 0, "down": 0, "up": 0, "lookUp": 0, "lookDown": 0, "lookLeft": 0, "lookRight": 0} #I changed the control scheme let me know if you would like me to try something else. #WASD for movement, space for jump self.accept("escape", sys.exit) self.accept("a", self.setKey, ["left", True]) self.accept("a-up", self.setKey, ["left", False]) self.accept("d", self.setKey, ["right", True]) self.accept("d-up", self.setKey, ["right", False]) self.accept("w", self.setKey, ["forward", True]) self.accept("w-up", self.setKey, ["forward", False]) self.accept("s", self.setKey, ["back", True]) self.accept("s-up", self.setKey, ["back", False]) self.accept("space", self.setKey, ["down", True]) self.accept("space-up", self.setKey, ["down", False]) self.accept("shift", self.setKey, ["up", True]) self.accept("shift-up", self.setKey, ["up", False]) def setKey(self, key, value): self.keyMap[key] = value def update(self, task): delta = globalClock.getDt() if not self.inMenu: SPEED = 125 #Variable that holds what direction the player is inputting fblr = 0 self.timer += delta * 25 self.killPlane = self.water.getZ() - 25 if self.flamieNP.getZ() < self.killPlane: self.reset() if self.keyMap["left"]: fblr = 1 old_fblr = fblr self.flamieNP.setX(self.flamie, - SPEED * delta) if self.keyMap["right"]: fblr = 2 old_fblr = fblr self.flamieNP.setX(self.flamie, + SPEED * delta) if self.keyMap["forward"]: fblr = 3 old_fblr = fblr self.flamieNP.setY(self.flamie, + SPEED * delta) if self.keyMap["back"]: fblr = 4 old_fblr = fblr self.flamieNP.setY(self.flamie, - SPEED * delta) if self.keyMap["up"]: #self.flamieNP.setZ(self.flamie, - SPEED * dt) self.reset() #self.cameraDistance = 20+self.cameraDistance if self.keyMap["down"] and self.timer > 1: #self.flamieNP.setZ(self.flamie, + SPEED * dt) self.timer = 0 self.jump(delta) if fblr == 1: self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f8.png")) elif fblr == 2: self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f6.png")) elif fblr == 3: if old_fblr == 1: self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f1.png")) elif old_fblr == 2: self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f4.png")) else: self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f3.png")) else: self.flamie2.setTexture(loader.loadTexture("models/flamie2D/f7.png")) if self.floorHandler.isOnGround: self.flamieBob(delta) #The camera control is borrowed from Kristina's Tech Demo #This is also a demo found at: http://www.panda3d.org/forums/viewtopic.php?t=8452 '''# mouse-controlled camera begins # Use mouse input to turn both the Character and the Camera if base.mouseWatcherNode.hasMouse(): 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) # alter flamie's yaw by an amount proportionate to deltaX self.flamie.setH(self.flamie.getH() - 0.3* 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 ralph's middle # 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()) # mouse-controlled camera ends''' self.waterControl(delta) self.water.setX(self.flamieNP.getX() - 250) self.water.setY(self.flamieNP.getY() - 250) self.cameraModes(delta) base.camera.setPos(self.flamieNP.getX(), self.flamieNP.getY() - self.cameraDistance, self.cameraHeight) self.camFocus.setPos(self.flamieNP.getX(), self.flamieNP.getY(), self.camFocusCurrZ) base.camera.lookAt(self.camFocus) ''' ###################### # # SIMPLE OCCLUSION FOR START AREA # ###################### for p in self.start.parts: if p.type == 'IceCube': if math.fabs((math.sqrt((p.model.getX() * p.model.getX()) + (p.model.getY() * p.model.getY())) - math.sqrt((self.camFocus.getX() * self.camFocus.getX()) + (self.camFocus.getY() * self.camFocus.getY())))) <= 400: p.show() #Ice cube movement p.bob(delta) else: p.hide() if p.type == 'Prism': if p.type == 'Prism': if math.fabs((math.sqrt((p.pos.x * p.pos.x) + (p.pos.y * p.pos.y)) - math.sqrt((self.camFocus.getX() * self.camFocus.getX()) + (self.camFocus.getY() * self.camFocus.getY())))) <= 1000: p.show() else: p.hide() ###################### # # SIMPLE OCCLUSION FOR CAVE PARTS # ###################### for p in self.cave.parts: if p.type == 'Prism': if math.fabs((math.sqrt((p.pos.x * p.pos.x) + (p.pos.y * p.pos.y)) - math.sqrt((self.flamieNP.getX() * self.flamieNP.getX()) + (self.flamieNP.getY() * self.flamieNP.getY())))) <= 2500: p.show() else: p.hide() if p.type == 'IceCube': if math.fabs((math.sqrt((p.model.getX() * p.model.getX()) + (p.model.getY() * p.model.getY())) - math.sqrt((self.flamieNP.getX() * self.flamieNP.getX()) + (self.flamieNP.getY() * self.flamieNP.getY())))) <= 2000: p.show() #Ice cube movement self.cave.moveIceCubes(delta/25) for p in self.cave.iceCubesThirdRoom: p.bob(delta/25) for p in self.cave.iceCubesSecondRoom: p.bob(delta/25) self.cave.bigCube.bob(delta/25) for p in self.start.iceCubes: p.bob(delta) else: p.hide() ''' #Ice cube movement self.cave.moveIceCubes(delta) for p in self.cave.iceCubesThirdRoom: p.bob(delta) for p in self.cave.iceCubesSecondRoom: p.bob(delta) self.cave.bigCube.bob(delta) for p in self.start.iceCubes: p.bob(delta) elif self.inMenu: self.menu() if self.backgroundSound.status() is not self.backgroundSound.PLAYING: self.backgroundSound.play() return task.cont def menu(self): if self.keyMap["down"]: self.inMenu = False self.menuScreen.destroy() self.initialize() def flamieBob(self, delta): if self.mayFlamieBob: self.flamie2.setZ(self.flamie2.getZ() + .5*delta) if self.flamie2.getZ() - self.flamie2OriZ > 1: self.mayFlamieBob = False else: self.flamie2.setZ(self.flamie2.getZ() - .5*delta) if self.flamie2.getZ() - self.flamie2OriZ < -2: self.mayFlamieBob = True #Function to create a box collision using six polygon. The top face is created as terrain and thus provides gravity. #While the rest of the faces only act as wall pushers. def collisionBoxCreator(self, posx, posy, posz, length, width, height, floorname, wallname): ret = () #Create top face terrain = CollisionPolygon(Point3(posx, posy+width, posz), Point3(posx, posy, posz), Point3(posx+length, posy, posz), Point3(posx+length, posy+width, posz)) terrainCol = CollisionNode(floorname) terrainCol.addSolid(terrain) terrainCol.setIntoCollideMask(BitMask32.bit(1)) terrainColNp = self.render.attachNewNode(terrainCol) self.cTrav.addCollider(terrainColNp, self.floorHandler) ret += (terrainColNp,) #Create left face sideLeft = CollisionPolygon(Point3(posx, posy+width, posz-height), Point3(posx, posy, posz-height), Point3(posx, posy, posz), Point3(posx, posy+width, posz)) sideLeftCol = CollisionNode(wallname) sideLeftCol.addSolid(sideLeft) sideLeftCol.setIntoCollideMask(BitMask32.bit(2)) sideLeftColNp = self.render.attachNewNode(sideLeftCol) self.cTrav.addCollider(sideLeftColNp, self.wallHandler) ret += (sideLeftColNp,) #Create right face sideRight = CollisionPolygon(Point3(posx+length, posy+width, posz), Point3(posx+length, posy, posz), Point3(posx+length, posy, posz-height), Point3(posx+length, posy+width, posz-height)) sideRightCol = CollisionNode(wallname) sideRightCol.addSolid(sideRight) sideRightCol.setIntoCollideMask(BitMask32.bit(2)) sideRightColNp = self.render.attachNewNode(sideRightCol) self.cTrav.addCollider(sideRightColNp, self.wallHandler) ret += (sideRightColNp,) #Create front face sideFront = CollisionPolygon(Point3(posx, posy+width, posz-height), Point3(posx, posy+width, posz), Point3(posx+length, posy+width, posz), Point3(posx+length, posy+width, posz-height)) sideFrontCol = CollisionNode(wallname) sideFrontCol.addSolid(sideFront) sideFrontCol.setIntoCollideMask(BitMask32.bit(2)) sideFrontColNp = self.render.attachNewNode(sideFrontCol) self.cTrav.addCollider(sideFrontColNp, self.wallHandler) ret += (sideFrontColNp,) #Create back face sideBack = CollisionPolygon(Point3(posx, posy, posz), Point3(posx, posy, posz-height), Point3(posx+length, posy, posz-height), Point3(posx+length, posy, posz)) sideBackCol = CollisionNode(wallname) sideBackCol.addSolid(sideBack) sideBackCol.setIntoCollideMask(BitMask32.bit(2)) sideBackColNp = self.render.attachNewNode(sideBackCol) self.cTrav.addCollider(sideBackColNp, self.wallHandler) ret += (sideBackColNp,) #Create bottom face sideBot = CollisionPolygon(Point3(posx, posy, posz-height), Point3(posx, posy+width, posz-height), Point3(posx+length, posy+width, posz-height), Point3(posx+length, posy, posz-height)) sideBotCol = CollisionNode(wallname) sideBotCol.addSolid(sideBot) sideBotCol.setIntoCollideMask(BitMask32.bit(2)) sideBotColNp = self.render.attachNewNode(sideBotCol) self.cTrav.addCollider(sideBotColNp, self.wallHandler) ret += (sideBotColNp,) #Uncomment these lines to see the collision polygons. '''terrainColNp.show() sideLeftColNp.show() sideRightColNp.show() sideFrontColNp.show() sideBackColNp.show() sideBotColNp.show()''' return ret #Old way of creating box collisions (left here for reference) '''box = CollisionBox((posx+(length/2), posy+(width/2),-(posz+height/2)), length/2, width/2, height/2) boxCol = CollisionNode('testcollision') boxCol.addSolid(box) boxCol.setIntoCollideMask(BitMask32.bit(2)) boxColNp = self.render.attachNewNode(boxCol) boxHandler = CollisionHandlerQueue() self.cTrav.addCollider(boxColNp, self.wallHandler) #Uncomment this line to see the collision solids. #boxColNp.show()''' def checkpointCreator(self, posx, posy, posz, radius): cp = loader.loadModel('models/Campfire/logs') cp.setPos(posx,posy, posz) cp.reparentTo(render) checkpoint = CollisionSphere(cp.getX(),cp.getY(),cp.getZ(),radius) checkpoint.setTangible(0) checkpointCol = CollisionNode('checkpointCol') checkpointCol.addSolid(checkpoint) checkpointCol.setIntoCollideMask(BitMask32.bit(2)) checkpointColNp = self.render.attachNewNode(checkpointCol) self.cTrav.addCollider(checkpointColNp, self.wallHandler)
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 Moving(ShowBase): def __init__(self): ShowBase.__init__(self) # This is used to store which keys are currently pressed. self.keyMap = { "left": 0, "right": 0, "forward": 0, "back": 0, "up": 0} # 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("EggMod/SandPlan.egg") self.environ.reparentTo(render) self.environ.setScale(20) StartPos = LVector3(0,0,94) self.movint = loader.loadModel("EggMod/HailPar.egg") self.movint.reparentTo(render) self.movint.setScale(2) self.movint.setPos(StartPos + (0, 0, 0.5)) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left", True]) self.accept("arrow_right", self.setKey, ["right", True]) self.accept("arrow_up", self.setKey, ["forward", True]) self.accept("arrow_down", self.setKey, ["back", True]) self.accept("f", self.setKey, ["up", True]) self.accept("arrow_left-up", self.setKey, ["left", False]) self.accept("arrow_right-up", self.setKey, ["right", False]) self.accept("arrow_up-up", self.setKey, ["forward", False]) self.accept("arrow_down-up", self.setKey, ["back", False]) self.accept("f-up", self.setKey, ["up", False]) self.mopan=Pmango() self.alin = LinearEulerIntegrator() self.mopan.attachLinearIntegrator(self.alin) self.arin = AngularEulerIntegrator() self.mopan.attachAngularIntegrator(self.arin) taskMgr.add(self.move, "moveTask") self.cTrav = CollisionTraverser() #base.cTrav.setRespectPrevTransform(True) self.actMove = NodePath("ActMove") self.actMove.reparentTo(render) self.an = ActorNode("BMova") self.anp = self.actMove.attachNewNode(self.an) self.mopan.attachPhysicalNode(self.an) self.movint.reparentTo(self.anp) self.anp.node().getPhysicsObject().setMass(1) #self.an.getPhysicsObject().setTerminalVelocity(1.0) self.dvi=0 self.grava=ForceNode('GravAll') self.grar=render.attachNewNode(self.grava) self.grdi=LinearVectorForce(0.0,-0.0,-8.0) #self.grdi.setMassDependent(1) self.grava.addForce(self.grdi) #Forces have to be added to force nodes and to # a physics manager self.mopan.addLinearForce(self.grdi) self.BMoveBalance = CollisionSphere(0, 0, -7.0, 1) self.BMoveBalanceNode = CollisionNode('BMove') self.BMoveBalanceNode.addSolid(self.BMoveBalance) self.BMoveBalancePath = self.movint.attachNewNode(self.BMoveBalanceNode) self.DinGro = PhysicsCollisionHandler() self.DinGro.setStaticFrictionCoef(1) self.DinGro.setDynamicFrictionCoef(2) self.DinGro.setAlmostStationarySpeed(0.1) self.DinGro.addCollider(self.BMoveBalancePath,self.anp) #Colliders use nodepaths for collisions instead of nodes self.cTrav.addCollider(self.BMoveBalancePath, self.DinGro) # Uncomment this line to see the collision rays self.BMoveBalancePath.show() # Uncomment this line to show a visual representation of the # collisions occuring self.cTrav.showCollisions(render) # Create some lighting directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection((-5, -5, -5)) 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): # Get the time that elapsed since last frame. We multiply this with # the desired speed in order to find out with which distance to move # in order to achieve that desired speed. dt = globalClock.getDt() self.dvi+=dt self.anr=self.an.getPhysicsObject() print(self.anr.getVelocity()) if dt<=.2: self.mopan.doPhysics(dt) if self.keyMap["left"]: self.movint.setH(self.movint.getH() + 200 * dt) if self.keyMap["right"]: self.movint.setH(self.movint.getH() - 200 * dt) if self.keyMap["forward"]: self.movint.setFluidY(self.movint, -25 * dt) if self.keyMap["back"]: self.movint.setFluidY(self.movint, 25 * dt) if self.keyMap["up"]: self.movint.setFluidZ(self.movint, 25 * dt) # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. #self.cTrav.traverse(render) return task.cont
class Raycaster(Entity): line_model = Mesh(vertices=[Vec3(0, 0, 0), Vec3(0, 0, 1)], mode='line') _boxcast_box = Entity(model='cube', origin_z=-.5, collider='box', color=color.white33, enabled=False) def __init__(self): super().__init__(name='raycaster', eternal=True) self._picker = CollisionTraverser() # Make a traverser self._pq = CollisionHandlerQueue() # Make a handler self._pickerNode = CollisionNode('raycaster') self._pickerNode.set_into_collide_mask(0) self._pickerNP = self.attach_new_node(self._pickerNode) self._picker.addCollider(self._pickerNP, self._pq) def distance(self, a, b): return sqrt(sum((a - b)**2 for a, b in zip(a, b))) def raycast(self, origin, direction=(0, 0, 1), distance=inf, traverse_target=scene, ignore=list(), debug=False): self.position = origin self.look_at(self.position + direction) self._pickerNode.clearSolids() ray = CollisionRay() ray.setOrigin(Vec3(0, 0, 0)) ray.setDirection(Vec3(0, 0, 1)) self._pickerNode.addSolid(ray) if debug: temp = Entity(position=origin, model=Raycaster.line_model, scale=Vec3(1, 1, min(distance, 9999)), add_to_scene_entities=False) temp.look_at(self.position + direction) destroy(temp, 1 / 30) self._picker.traverse(traverse_target) if self._pq.get_num_entries() == 0: self.hit = HitInfo(hit=False, distance=distance) return self.hit ignore += tuple([e for e in scene.entities if not e.collision]) self._pq.sort_entries() self.entries = [ # filter out ignored entities e for e in self._pq.getEntries() if e.get_into_node_path().parent not in ignore and self.distance( self.world_position, Vec3( *e.get_surface_point(render))) <= distance ] if len(self.entries) == 0: self.hit = HitInfo(hit=False, distance=distance) return self.hit self.collision = self.entries[0] nP = self.collision.get_into_node_path().parent point = Vec3(*self.collision.get_surface_point(nP)) world_point = Vec3(*self.collision.get_surface_point(render)) hit_dist = self.distance(self.world_position, world_point) self.hit = HitInfo(hit=True, distance=distance) for e in scene.entities: if e == nP: self.hit.entity = e nPs = [e.get_into_node_path().parent for e in self.entries] self.hit.entities = [e for e in scene.entities if e in nPs] self.hit.point = point self.hit.world_point = world_point self.hit.distance = hit_dist self.hit.normal = Vec3(*self.collision.get_surface_normal( self.collision.get_into_node_path().parent).normalized()) self.hit.world_normal = Vec3( *self.collision.get_surface_normal(render).normalized()) return self.hit self.hit = HitInfo(hit=False, distance=distance) return self.hit def boxcast(self, origin, direction=(0, 0, 1), distance=9999, thickness=(1, 1), traverse_target=scene, ignore=list(), debug=False): # similar to raycast, but with width and height if isinstance(thickness, (int, float, complex)): thickness = (thickness, thickness) Raycaster._boxcast_box.enabled = True Raycaster._boxcast_box.collision = True Raycaster._boxcast_box.position = origin Raycaster._boxcast_box.scale = Vec3(abs(thickness[0]), abs(thickness[1]), abs(distance)) Raycaster._boxcast_box.always_on_top = debug Raycaster._boxcast_box.visible = debug Raycaster._boxcast_box.look_at(origin + direction) hit_info = Raycaster._boxcast_box.intersects( traverse_target=traverse_target, ignore=ignore) if hit_info.world_point: hit_info.distance = ursinamath.distance(origin, hit_info.world_point) else: hit_info.distance = distance if debug: Raycaster._boxcast_box.collision = False Raycaster._boxcast_box.scale_z = hit_info.distance invoke(setattr, Raycaster._boxcast_box, 'enabled', False, delay=.2) else: Raycaster._boxcast_box.enabled = False return hit_info
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 Mouse(): def __init__(self): self.enabled = False self.locked = False self.position = Vec3(0, 0, 0) self.delta = Vec3(0, 0, 0) self.prev_x = 0 self.prev_y = 0 self.start_x = 0 self.start_y = 0 self.velocity = Vec3(0, 0, 0) self.prev_click_time = time.time() self.double_click_distance = .5 self.hovered_entity = None # returns the closest hovered entity with a collider. self.left = False self.right = False self.middle = False self.delta_drag = Vec3(0, 0, 0) self.update_step = 1 self.traverse_target = scene self._i = 0 self._mouse_watcher = None self._picker = CollisionTraverser() # Make a traverser self._pq = CollisionHandlerQueue() # Make a handler self._pickerNode = CollisionNode('mouseRay') self._pickerNP = camera.attach_new_node(self._pickerNode) self._pickerRay = CollisionRay() # Make our ray self._pickerNode.addSolid(self._pickerRay) self._picker.addCollider(self._pickerNP, self._pq) self._pickerNode.set_into_collide_mask(0) self.raycast = True self.collision = None self.collisions = list() self.enabled = True @property def x(self): if not self._mouse_watcher.has_mouse(): return 0 return self._mouse_watcher.getMouseX( ) / 2 * window.aspect_ratio # same space as ui stuff @x.setter def x(self, value): self.position = (value, self.y) @property def y(self): if not self._mouse_watcher.has_mouse(): return 0 return self._mouse_watcher.getMouseY() / 2 @y.setter def y(self, value): self.position = (self.x, value) @property def position(self): return Vec3(self.x, self.y, 0) @position.setter def position(self, value): base.win.move_pointer( 0, round(value[0] + (window.size[0] / 2) + (value[0] / 2 * window.size[0]) * 1.124), # no idea why I have * with 1.124 round(value[1] + (window.size[1] / 2) - (value[1] * window.size[1])), ) def __setattr__(self, name, value): if name == 'visible': window.set_cursor_hidden(not value) application.base.win.requestProperties(window) if name == 'locked': try: object.__setattr__(self, name, value) window.set_cursor_hidden(value) if value: window.set_mouse_mode(window.M_relative) else: window.set_mouse_mode(window.M_absolute) application.base.win.requestProperties(window) except: pass try: super().__setattr__(name, value) # return except: pass def input(self, key): if not self.enabled: return if key.endswith('mouse down'): self.start_x = self.x self.start_y = self.y elif key.endswith('mouse up'): self.delta_drag = Vec3(self.x - self.start_x, self.y - self.start_y, 0) if key == 'left mouse down': self.left = True if self.hovered_entity: if hasattr(self.hovered_entity, 'on_click'): self.hovered_entity.on_click() for s in self.hovered_entity.scripts: if hasattr(s, 'on_click'): s.on_click() # double click if time.time( ) - self.prev_click_time <= self.double_click_distance: base.input('double click') if self.hovered_entity: if hasattr(self.hovered_entity, 'on_double_click'): self.hovered_entity.on_double_click() for s in self.hovered_entity.scripts: if hasattr(s, 'on_double_click'): s.on_double_click() self.prev_click_time = time.time() if key == 'left mouse up': self.left = False if key == 'right mouse down': self.right = True if key == 'right mouse up': self.right = False if key == 'middle mouse down': self.middle = True if key == 'middle mouse up': self.middle = False def update(self): if not self.enabled or not self._mouse_watcher.has_mouse(): self.velocity = Vec3(0, 0, 0) return self.moving = self.x + self.y != self.prev_x + self.prev_y if self.moving: if self.locked: self.velocity = self.position self.position = (0, 0) else: self.velocity = Vec3(self.x - self.prev_x, (self.y - self.prev_y) / window.aspect_ratio, 0) else: self.velocity = Vec3(0, 0, 0) if self.left or self.right or self.middle: self.delta = Vec3(self.x - self.start_x, self.y - self.start_y, 0) self.prev_x = self.x self.prev_y = self.y self._i += 1 if self._i < self.update_step: return # collide with ui self._pickerNP.reparent_to(scene.ui_camera) self._pickerRay.set_from_lens(camera._ui_lens_node, self.x * 2 / window.aspect_ratio, self.y * 2) self._picker.traverse(camera.ui) if self._pq.get_num_entries() > 0: # print('collided with ui', self._pq.getNumEntries()) self.find_collision() return # collide with world self._pickerNP.reparent_to(camera) self._pickerRay.set_from_lens(scene.camera.lens_node, self.x * 2 / window.aspect_ratio, self.y * 2) try: self._picker.traverse(self.traverse_target) except: # print('error: mouse._picker could not traverse', self.traverse_target) return if self._pq.get_num_entries() > 0: self.find_collision() else: # print('mouse miss', base.render) # unhover all if it didn't hit anything for entity in scene.entities: if hasattr(entity, 'hovered') and entity.hovered: entity.hovered = False self.hovered_entity = None if hasattr(entity, 'on_mouse_exit'): entity.on_mouse_exit() for s in entity.scripts: if hasattr(s, 'on_mouse_exit'): s.on_mouse_exit() @property def normal(self): if not self.collision: return None return self.collision.normal @property def world_normal(self): if not self.collision: return None return self.collision.world_normal @property def point(self): # returns the point hit in local space if self.collision: return self.collision.point return None @property def world_point(self): if self.collision: return self.collision.world_point return None def find_collision(self): self.collisions = list() self.collision = None if not self.raycast or self._pq.get_num_entries() == 0: self.unhover_everything_not_hit() return False self._pq.sortEntries() for entry in self._pq.getEntries(): for entity in scene.entities: if entry.getIntoNodePath( ).parent == entity and entity.collision: if entity.collision: hit = HitInfo( hit=entry.collided(), entity=entity, distance=distance(entry.getSurfacePoint(scene), camera.getPos()), point=entry.getSurfacePoint(entity), world_point=entry.getSurfacePoint(scene), normal=entry.getSurfaceNormal(entity), world_normal=entry.getSurfaceNormal(scene), ) self.collisions.append(hit) break if self.collisions: self.collision = self.collisions[0] self.hovered_entity = self.collision.entity if not self.hovered_entity.hovered: self.hovered_entity.hovered = True if hasattr(self.hovered_entity, 'on_mouse_enter'): self.hovered_entity.on_mouse_enter() for s in self.hovered_entity.scripts: if hasattr(s, 'on_mouse_enter'): s.on_mouse_enter() self.unhover_everything_not_hit() def unhover_everything_not_hit(self): for e in scene.entities: if e == self.hovered_entity: continue if e.hovered: e.hovered = False if hasattr(e, 'on_mouse_exit'): e.on_mouse_exit() for s in e.scripts: if hasattr(s, 'on_mouse_exit'): s.on_mouse_exit()
class MapEditor(): def __init__(self, terrain): self.terrain = terrain self.terrain.setTag('EditableTerrain', '1') self.cursor = render.attachNewNode('EditCursor') loader.loadModel("models/sphere").reparentTo(self.cursor) self.size = 10.0 self.cursor.setScale(self.size) #self.cursor.setSz(self.size / self.terrain.getSz()) self.cursor.setRenderModeWireframe() self.setupMouseCollision() self.on = False self.disable() def enable(self): taskMgr.add(self.update, "terrainEditor") self.cursor.unstash() def disable(self): taskMgr.remove("terrainEditor") self.cursor.stash() def toggle(self, value = None): if value == None: self.on = not self.on else: self.on = value if self.on: self.enable() else: self.disable() def update(self, task): self.onMouseTask() return Task.cont def onMouseTask(self): """ """ #do we have a mouse logging.info("onMouseTask") if (base.mouseWatcherNode.hasMouse() == False): logging.error("no mouse") return #get the mouse position mpos = base.mouseWatcherNode.getMouse() #Set the position of the ray based on the mouse position if not self.mPickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()): logging.error("point is not acceptable") #for this small example I will traverse everything, for bigger projects #this is probably a bad idea self.mPickerTraverser.traverse(self.terrain) logging.info("Mouse pick ray traversing terrain.") if (self.mCollisionQueue.getNumEntries() > 0): self.mCollisionQueue.sortEntries() entry = self.mCollisionQueue.getEntry(0); pickedObj = entry.getIntoNodePath() #pickedObj = pickedObj.findNetTag('EditableTerrain') if not pickedObj.isEmpty(): #here is how you get the surface collsion pos = entry.getSurfacePoint(render) #pos.z *= self.terrain.getSz() logging.info(str(pickedObj)) logging.info(str(pos)) self.cursor.setPos(pos) #handlePickedObject(pickedObj) else: logging.info("picked object is empty") else: logging.info("Nothing collided with mouse pick ray") def setupMouseCollision(self): """ """ #Since we are using collision detection to do picking, we set it up #any other collision detection system with a traverser and a handler self.mPickerTraverser = CollisionTraverser() #Make a traverser self.mCollisionQueue = CollisionHandlerQueue() #create a collision solid ray to detect against self.mPickRay = CollisionRay() #self.mPickRay.setOrigin(base.camera.getPos(render)) #self.mPickRay.setDirection(render.getRelativeVector(base.camera, Vec3(0,1,0))) #create our collison Node to hold the ray self.mPickNode = CollisionNode('pickRay') 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) #well 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(GeomNode.getDefaultCollideMask()) #Register the ray as something that can cause collisions self.mPickerTraverser.addCollider(self.mPickNP, self.mCollisionQueue)
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 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 Demo(ShowBase): _speed = 25 def reset(self): x = random.random() * 40 - 20 y = random.random() * 40 - 20 self.ralph.setPos((x, y, 0)) def __init__(self, img_size=512, screen_off=True): self.img_size = img_size loadPrcFileData("", "transform-cache false") loadPrcFileData("", "audio-library-name null") # Prevent ALSA errors loadPrcFileData("", "win-size %d %d" % (img_size, img_size)) loadPrcFileData("", "parallax-mapping-samples 3\n" "parallax-mapping-scale 0.1") if screen_off: # Spawn an offscreen buffer loadPrcFileData("", "window-type offscreen") # Initialize the ShowBase class from which we inherit, which will # create a window and set up everything we need for rendering into it. ShowBase.__init__(self) # Load the 'abstract room' model. This is a model of an # empty room containing a pillar, a pyramid, and a bunch # of exaggeratedly bumpy textures. self.room = loader.loadModel("models/abstractroom") self.room.reparentTo(render) # Create the main character, Ralph self.ralph = Actor("models/ralph", {"run": "models/ralph-run", "walk": "models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.reset() self.pieces = [Piece(self.room) for _ in range(200)] ################################################## cnodePath = self.room.attachNewNode(CollisionNode('cnode')) plane = CollisionPlane(Plane(Vec3(1, 0, 0), Point3(-60, 0, 0))) # left cnodePath.node().addSolid(plane) plane = CollisionPlane( Plane(Vec3(-1, 0, 0), Point3(60, 0, 0))) # right cnodePath.node().addSolid(plane) plane = CollisionPlane(Plane(Vec3(0, 1, 0), Point3(0, -60, 0))) # back cnodePath.node().addSolid(plane) plane = CollisionPlane( Plane(Vec3(0, -1, 0), Point3(0, 60, 0))) # front cnodePath.node().addSolid(plane) sphere = CollisionSphere(-25, -25, 0, 12.5) cnodePath.node().addSolid(sphere) box = CollisionBox(Point3(5, 5, 0), Point3(45, 45, 10)) cnodePath.node().addSolid(box) # Make the mouse invisible, turn off normal mouse controls self.disableMouse() self.camLens.setFov(80) # Set the current viewing target self.focus = LVector3(55, -55, 20) self.heading = 180 self.pitch = 0 self.mousex = 0 self.mousey = 0 self.last = 0 self.mousebtn = [0, 0, 0] # Add a light to the scene. self.lightpivot = render.attachNewNode("lightpivot") self.lightpivot.setPos(0, 0, 25) self.lightpivot.hprInterval(10, LPoint3(360, 0, 0)).loop() plight = PointLight('plight') plight.setColor((5, 5, 5, 1)) plight.setAttenuation(LVector3(0.7, 0.05, 0)) plnp = self.lightpivot.attachNewNode(plight) plnp.setPos(45, 0, 0) self.room.setLight(plnp) # Add an ambient light alight = AmbientLight('alight') alight.setColor((0.2, 0.2, 0.2, 1)) alnp = render.attachNewNode(alight) self.room.setLight(alnp) # Create a sphere to denote the light sphere = loader.loadModel("models/icosphere") sphere.reparentTo(plnp) self.cameraModel = self.ralph camera.reparentTo(self.cameraModel) camera.setZ(2) self.cTrav = CollisionTraverser() cs = CollisionSphere(0, 0, 0, 1) cnodePath = self.ralph.attachNewNode(CollisionNode('cnode')) cnodePath.node().addSolid(cs) cnodePath.show() self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(cnodePath, self.ralphGroundHandler) self.cnodePath = cnodePath # Tell Panda that it should generate shaders performing per-pixel # lighting for the room. self.room.setShaderAuto() self.shaderenable = 1 tex = Texture() self.depthmap = tex tex.setFormat(Texture.FDepthComponent) altBuffer = self.win.makeTextureBuffer( "hello", img_size, img_size, tex, True) self.altBuffer = altBuffer altCam = self.makeCamera(altBuffer) altCam.reparentTo(self.ralph) # altRender) altCam.setZ(2) l = altCam.node().getLens() l.setFov(80) ################### end init def step(self, rotation): dt = 0.02 self.ralph.setH(self.ralph.getH() + rotation * dt) self.ralph.setY(self.ralph, self._speed * dt) for _ in range(5): random.choice(self.pieces).step(dt) f = taskMgr.getAllTasks()[-1].getFunction() f(None) f = taskMgr.getAllTasks()[2].getFunction() f(None) entries = (self.ralphGroundHandler.getEntries()) if len(entries) > 0: self.reset() return 1 else: return 0 def resetGame(self): while True: self.reset() for p in self.pieces: p.reset() if 0 == self.step(0): break def renderFrame(self): base.graphicsEngine.renderFrame() def getDepthMapT(self): tex = self.depthmap #tex = self.altBuffer.getTexture() r = tex.getRamImage() s = r.getData() i = np.fromstring(s, dtype='float32') i = i.reshape((self.img_size, self.img_size)) i = np.flipud(i) return i
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 Entity(NodePath): rotation_directions = (-1,-1,1) default_shader = None def __init__(self, add_to_scene_entities=True, **kwargs): super().__init__(self.__class__.__name__) self.name = camel_to_snake(self.type) self.enabled = True # disabled entities wil not be visible nor run code self.visible = True self.ignore = False # if True, will not try to run code self.eternal = False # eternal entities does not get destroyed on scene.clear() self.ignore_paused = False self.ignore_input = False self.parent = scene self.add_to_scene_entities = add_to_scene_entities # set to False to be ignored by the engine, but still get rendered. if add_to_scene_entities: scene.entities.append(self) self.model = None # set model with model='model_name' (without file type extention) self.color = color.white self.texture = None # set model with texture='texture_name'. requires a model to be set beforehand. self.reflection_map = scene.reflection_map self.reflectivity = 0 self.render_queue = 0 self.double_sided = False self.shader = Entity.default_shader # self.always_on_top = False self.collision = False # toggle collision without changing collider. self.collider = None # set to 'box'/'sphere'/'mesh' for auto fitted collider. self.scripts = list() # add with add_script(class_instance). will assign an 'entity' variable to the script. self.animations = list() self.hovered = False # will return True if mouse hovers entity. self.origin = Vec3(0,0,0) self.position = Vec3(0,0,0) # right, up, forward. can also set self.x, self.y, self.z self.rotation = Vec3(0,0,0) # can also set self.rotation_x, self.rotation_y, self.rotation_z self.scale = Vec3(1,1,1) # can also set self.scale_x, self.scale_y, self.scale_z self.line_definition = None # returns a Traceback(filename, lineno, function, code_context, index). if application.trace_entity_definition and add_to_scene_entities: from inspect import getframeinfo, stack _stack = stack() caller = getframeinfo(_stack[1][0]) if len(_stack) > 2 and _stack[1].code_context and 'super().__init__()' in _stack[1].code_context[0]: caller = getframeinfo(_stack[2][0]) self.line_definition = caller if caller.code_context: self.code_context = caller.code_context[0] if (self.code_context.count('(') == self.code_context.count(')') and ' = ' in self.code_context and not 'name=' in self.code_context and not 'Ursina()' in self.code_context): self.name = self.code_context.split(' = ')[0].strip().replace('self.', '') # print('set name to:', self.code_context.split(' = ')[0].strip().replace('self.', '')) if application.print_entity_definition: print(f'{Path(caller.filename).name} -> {caller.lineno} -> {caller.code_context}') for key, value in kwargs.items(): setattr(self, key, value) def _list_to_vec(self, value): if isinstance(value, (int, float, complex)): return Vec3(value, value, value) if len(value) % 2 == 0: new_value = Vec2() for i in range(0, len(value), 2): new_value.add_x(value[i]) new_value.add_y(value[i+1]) if len(value) % 3 == 0: new_value = Vec3() for i in range(0, len(value), 3): new_value.add_x(value[i]) new_value.add_y(value[i+1]) new_value.add_z(value[i+2]) return new_value def enable(self): self.enabled = True def disable(self): self.enabled = False def __setattr__(self, name, value): if name == 'enabled': try: # try calling on_enable() on classes inheriting from Entity if value == True: self.on_enable() else: self.on_disable() except: pass if value == True: if hasattr(self, 'is_singleton') and not self.is_singleton(): self.unstash() else: if hasattr(self, 'is_singleton') and not self.is_singleton(): self.stash() if name == 'eternal': for c in self.children: c.eternal = value if name == 'world_parent': self.reparent_to(value) if name == 'model': if value is None: if hasattr(self, 'model') and self.model: self.model.removeNode() # print('removed model') object.__setattr__(self, name, value) return None if isinstance(value, NodePath): # pass procedural model if self.model is not None and value != self.model: self.model.removeNode() object.__setattr__(self, name, value) elif isinstance(value, str): # pass model asset name m = load_model(value, application.asset_folder) if not m: m = load_model(value, application.internal_models_compressed_folder) if m: if self.model is not None: self.model.removeNode() object.__setattr__(self, name, m) # if isinstance(m, Mesh): # m.recipe = value # print('loaded model successively') else: # if '.' in value: # print(f'''trying to load model with specific filename extention. please omit it. '{value}' -> '{value.split('.')[0]}' ''') print('missing model:', value) return if self.model: self.model.reparentTo(self) self.model.setTransparency(TransparencyAttrib.M_dual) self.color = self.color # reapply color after changing model self.texture = self.texture # reapply texture after changing model self._vert_cache = None if isinstance(value, Mesh): if hasattr(value, 'on_assign'): value.on_assign(assigned_to=self) return if name == 'color' and value is not None: if isinstance(value, str): value = color.hex(value) if not isinstance(value, Vec4): value = Vec4(value[0], value[1], value[2], value[3]) if self.model: self.model.setColorScaleOff() # prevent inheriting color from parent self.model.setColorScale(value) object.__setattr__(self, name, value) if name == 'collision' and hasattr(self, 'collider') and self.collider: if value: self.collider.node_path.unstash() else: self.collider.node_path.stash() object.__setattr__(self, name, value) return if name == 'render_queue': if self.model: self.model.setBin('fixed', value) if name == 'double_sided': self.setTwoSided(value) try: super().__setattr__(name, value) except: pass # print('failed to set attribiute:', name) @property def parent(self): try: return self._parent except: return None @parent.setter def parent(self, value): self._parent = value if value is None: destroy(self) else: try: self.reparentTo(value) except: print('invalid parent:', value) @property def type(self): # get class name. return self.__class__.__name__ @property def types(self): # get all class names including those this inhertits from. from inspect import getmro return [c.__name__ for c in getmro(self.__class__)] @property def visible(self): return self._visible @visible.setter def visible(self, value): self._visible = value if value: self.show() else: self.hide() @property def visible_self(self): # set visibility of self, without affecting children. if not hasattr(self, '_visible_self'): return True return self._visible_self @visible_self.setter def visible_self(self, value): self._visible_self = value if not self.model: return if value: self.model.show() else: self.model.hide() @property def collider(self): return self._collider @collider.setter def collider(self, value): # destroy existing collider if value and hasattr(self, 'collider') and self._collider: self._collider.remove() self._collider = value if value == 'box': if self.model: self._collider = BoxCollider(entity=self, center=-self.origin, size=self.model_bounds) else: self._collider = BoxCollider(entity=self) self._collider.name = value elif value == 'sphere': self._collider = SphereCollider(entity=self, center=-self.origin) self._collider.name = value elif value == 'mesh' and self.model: self._collider = MeshCollider(entity=self, mesh=None, center=-self.origin) self._collider.name = value elif isinstance(value, Mesh): self._collider = MeshCollider(entity=self, mesh=value, center=-self.origin) elif isinstance(value, str): m = load_model(value) if not m: return self._collider = MeshCollider(entity=self, mesh=m, center=-self.origin) self._collider.name = value self.collision = bool(self.collider) return @property def origin(self): return self._origin @origin.setter def origin(self, value): if not self.model: self._origin = Vec3(0,0,0) return if not isinstance(value, (Vec2, Vec3)): value = self._list_to_vec(value) if isinstance(value, Vec2): value = Vec3(*value, self.origin_z) self._origin = value self.model.setPos(-value[0], -value[1], -value[2]) @property def origin_x(self): return self.origin[0] @origin_x.setter def origin_x(self, value): self.origin = (value, self.origin_y, self.origin_z) @property def origin_y(self): return self.origin[1] @origin_y.setter def origin_y(self, value): self.origin = (self.origin_x, value, self.origin_z) @property def origin_z(self): return self.origin[2] @origin_z.setter def origin_z(self, value): self.origin = (self.origin_x, self.origin_y, value) @property def world_position(self): return Vec3(self.get_position(render)) @world_position.setter def world_position(self, value): if not isinstance(value, (Vec2, Vec3)): value = self._list_to_vec(value) if isinstance(value, Vec2): value = Vec3(*value, self.z) self.setPos(render, Vec3(value[0], value[1], value[2])) @property def world_x(self): return self.getX(render) @property def world_y(self): return self.getY(render) @property def world_z(self): return self.getZ(render) @world_x.setter def world_x(self, value): self.setX(render, value) @world_y.setter def world_y(self, value): self.setY(render, value) @world_z.setter def world_z(self, value): self.setZ(render, value) @property def position(self): return Vec3(*self.getPos()) @position.setter def position(self, value): if not isinstance(value, (Vec2, Vec3)): value = self._list_to_vec(value) if isinstance(value, Vec2): value = Vec3(*value, self.z) self.setPos(value[0], value[1], value[2]) @property def x(self): return self.getX() @x.setter def x(self, value): self.setX(value) @property def y(self): return self.getY() @y.setter def y(self, value): self.setY(value) @property def z(self): return self.getZ() @z.setter def z(self, value): self.setZ(value) @property def world_rotation(self): rotation = self.getHpr(base.render) return Vec3(rotation[1], rotation[0], rotation[2]) * Entity.rotation_directions @world_rotation.setter def world_rotation(self, value): rotation = self.setHpr(Vec3(value[1], value[0], value[2]) * Entity.rotation_directions, base.render) @property def world_rotation_x(self): return self.world_rotation[0] @world_rotation_x.setter def world_rotation_x(self, value): self.world_rotation = Vec3(value, self.world_rotation[1], self.world_rotation[2]) @property def world_rotation_y(self): return self.world_rotation[1] @world_rotation_y.setter def world_rotation_y(self, value): self.world_rotation = Vec3(self.world_rotation[0], value, self.world_rotation[2]) @property def world_rotation_z(self): return self.world_rotation[2] @world_rotation_z.setter def world_rotation_z(self, value): self.world_rotation = Vec3(self.world_rotation[0], self.world_rotation[1], value) @property def rotation(self): rotation = self.getHpr() return Vec3(rotation[1], rotation[0], rotation[2]) * Entity.rotation_directions @rotation.setter def rotation(self, value): if not isinstance(value, (Vec2, Vec3)): value = self._list_to_vec(value) if isinstance(value, Vec2): value = Vec3(*value, self.rotation_z) self.setHpr(Vec3(value[1], value[0], value[2]) * Entity.rotation_directions) @property def rotation_x(self): return self.rotation.x @rotation_x.setter def rotation_x(self, value): self.rotation = Vec3(value, self.rotation[1], self.rotation[2]) @property def rotation_y(self): return self.rotation.y @rotation_y.setter def rotation_y(self, value): self.rotation = Vec3(self.rotation[0], value, self.rotation[2]) @property def rotation_z(self): return self.rotation.z @rotation_z.setter def rotation_z(self, value): self.rotation = Vec3(self.rotation[0], self.rotation[1], value) @property def world_scale(self): return Vec3(*self.getScale(base.render)) @world_scale.setter def world_scale(self, value): if isinstance(value, (int, float, complex)): value = Vec3(value, value, value) self.setScale(base.render, value) @property def world_scale_x(self): return self.getScale(base.render)[0] @world_scale_x.setter def world_scale_x(self, value): self.setScale(base.render, Vec3(value, self.world_scale_y, self.world_scale_z)) @property def world_scale_y(self): return self.getScale(base.render)[1] @world_scale_y.setter def world_scale_y(self, value): self.setScale(base.render, Vec3(self.world_scale_x, value, self.world_scale_z)) @property def world_scale_z(self): return self.getScale(base.render)[2] @world_scale_z.setter def world_scale_z(self, value): self.setScale(base.render, Vec3(self.world_scale_x, value, self.world_scale_z)) @property def scale(self): scale = self.getScale() return Vec3(scale[0], scale[1], scale[2]) @scale.setter def scale(self, value): if not isinstance(value, (Vec2, Vec3)): value = self._list_to_vec(value) if isinstance(value, Vec2): value = Vec3(*value, self.scale_z) value = [e if e!=0 else .001 for e in value] self.setScale(value[0], value[1], value[2]) @property def scale_x(self): return self.scale[0] @scale_x.setter def scale_x(self, value): self.setScale(value, self.scale_y, self.scale_z) @property def scale_y(self): return self.scale[1] @scale_y.setter def scale_y(self, value): self.setScale(self.scale_x, value, self.scale_z) @property def scale_z(self): return self.scale[2] @scale_z.setter def scale_z(self, value): self.setScale(self.scale_x, self.scale_y, value) @property def forward(self): # get forward direction. return render.getRelativeVector(self, (0, 0, 1)) @property def back(self): # get backwards direction. return -self.forward @property def right(self): # get right direction. return render.getRelativeVector(self, (1, 0, 0)) @property def left(self): # get left direction. return -self.right @property def up(self): # get up direction. return render.getRelativeVector(self, (0, 1, 0)) @property def down(self): # get down direction. return -self.up @property def screen_position(self): # get screen position(ui space) from world space. from ursina import camera p3 = camera.getRelativePoint(self, Vec3.zero()) full = camera.lens.getProjectionMat().xform(Vec4(*p3, 1)) recip_full3 = 1 / full[3] p2 = Vec3(full[0], full[1], full[2]) * recip_full3 screen_pos = Vec3(p2[0]*camera.aspect_ratio/2, p2[1]/2, 0) return screen_pos @property def shader(self): return self._shader @shader.setter def shader(self, value): self._shader = value if value is None: self.setShaderAuto() return if isinstance(value, Panda3dShader): #panda3d shader self.setShader(value) return if isinstance(value, Shader): if not value.compiled: value.compile() self.setShader(value._shader) value.entity = self for key, value in value.default_input.items(): self.set_shader_input(key, value) def set_shader_input(self, name, value): if isinstance(value, Texture): value = value._texture # make sure to send the panda3d texture to the shader super().set_shader_input(name, value) @property def texture(self): if not hasattr(self, '_texture'): return None return self._texture @texture.setter def texture(self, value): if value is None and self._texture: # print('remove texture') self._texture = None self.setTextureOff(True) return if value.__class__ is Texture: texture = value elif isinstance(value, str): texture = load_texture(value) # print('loaded texture:', texture) if texture is None: print('no texture:', value) return if texture.__class__ is MovieTexture: self._texture = texture self.model.setTexture(texture, 1) return self._texture = texture if self.model: self.model.setTexture(texture._texture, 1) @property def texture_scale(self): if not hasattr(self, '_texture_scale'): return Vec2(1,1) return self._texture_scale @texture_scale.setter def texture_scale(self, value): self._texture_scale = value if self.model and self.texture: self.model.setTexScale(TextureStage.getDefault(), value[0], value[1]) @property def texture_offset(self): return self._texture_offset @texture_offset.setter def texture_offset(self, value): if self.model and self.texture: self.model.setTexOffset(TextureStage.getDefault(), value[0], value[1]) self.texture = self.texture self._texture_offset = value @property def alpha(self): return self.color[3] @alpha.setter def alpha(self, value): if value > 1: value = value / 255 self.color = color.color(self.color.h, self.color.s, self.color.v, value) @property def always_on_top(self): return self._always_on_top @always_on_top.setter def always_on_top(self, value): self._always_on_top = value self.set_bin("fixed", 0) self.set_depth_write(not value) self.set_depth_test(not value) @property def billboard(self): # set to True to make this Entity always face the camera. return self._billboard @billboard.setter def billboard(self, value): self._billboard = value if value: self.setBillboardPointEye(value) @property def reflection_map(self): return self._reflection_map @reflection_map.setter def reflection_map(self, value): if value.__class__ is Texture: texture = value elif isinstance(value, str): texture = load_texture(value) self._reflection_map = texture @property def reflectivity(self): return self._reflectivity @reflectivity.setter def reflectivity(self, value): self._reflectivity = value if value == 0: self.texture = None if value > 0: # if self.reflection_map == None: # self.reflection_map = scene.reflection_map # # if not self.reflection_map: # print('error setting reflectivity. no reflection map') # return if not self.normals: self.model.generate_normals() # ts = TextureStage('env') # ts.setMode(TextureStage.MAdd) # self.model.setTexGen(ts, TexGenAttrib.MEyeSphereMap) # print('---------------set reflectivity', self.reflection_map) # self.model.setTexture(ts, self.reflection_map) self.texture = self._reflection_map # print('set reflectivity') def generate_sphere_map(self, size=512, name=f'sphere_map_{len(scene.entities)}'): from ursina import camera _name = 'textures/' + name + '.jpg' org_pos = camera.position camera.position = self.position base.saveSphereMap(_name, size=size) camera.position = org_pos print('saved sphere map:', name) self.model.setTexGen(TextureStage.getDefault(), TexGenAttrib.MEyeSphereMap) self.reflection_map = name def generate_cube_map(self, size=512, name=f'cube_map_{len(scene.entities)}'): from ursina import camera _name = 'textures/' + name org_pos = camera.position camera.position = self.position base.saveCubeMap(_name+'.jpg', size=size) camera.position = org_pos print('saved cube map:', name + '.jpg') self.model.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldCubeMap) self.reflection_map = _name + '#.jpg' self.model.setTexture(loader.loadCubeMap(_name + '#.jpg'), 1) @property def model_bounds(self): if self.model: bounds = self.model.getTightBounds() bounds = Vec3( Vec3(bounds[1][0], bounds[1][1], bounds[1][2]) # max point - Vec3(bounds[0][0], bounds[0][1], bounds[0][2]) # min point ) return bounds return (0,0,0) @property def bounds(self): return Vec3( self.model_bounds[0] * self.scale_x, self.model_bounds[1] * self.scale_y, self.model_bounds[2] * self.scale_z ) def reparent_to(self, entity): if entity is not None: self.wrtReparentTo(entity) self._parent = entity def get_position(self, relative_to=scene): return self.getPos(relative_to) def set_position(self, value, relative_to=scene): self.setPos(relative_to, Vec3(value[0], value[1], value[2])) def add_script(self, class_instance): if isinstance(class_instance, object) and type(class_instance) is not str: class_instance.entity = self class_instance.enabled = True setattr(self, camel_to_snake(class_instance.__class__.__name__), class_instance) self.scripts.append(class_instance) # print('added script:', camel_to_snake(name.__class__.__name__)) return class_instance def combine(self, analyze=False, auto_destroy=True, ignore=[]): from ursina.scripts.combine import combine self.model = combine(self, analyze, auto_destroy, ignore) return self.model def flip_faces(self): if not hasattr(self, '_vertex_order'): self._vertex_order = True self._vertex_order = not self._vertex_order if self._vertex_order: self.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullClockwise)) else: self.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullCounterClockwise)) def look_at(self, target, axis='forward'): from panda3d.core import Quat if not isinstance(target, Entity): target = Vec3(*target) self.lookAt(target) if axis == 'forward': return rotation_offset = { 'back' : Quat(0,0,1,0), 'down' : Quat(-.707,.707,0,0), 'up' : Quat(-.707,-.707,0,0), 'right' : Quat(-.707,0,.707,0), 'left' : Quat(-.707,0,-.707,0), }[axis] self.setQuat(rotation_offset * self.getQuat()) def look_at_2d(self, target, axis='z'): from math import degrees, atan2 if isinstance(target, Entity): target = Vec3(target.world_position) pos = target - self.world_position if axis == 'z': self.rotation_z = degrees(atan2(pos[0], pos[1])) def has_ancestor(self, possible_ancestor): p = self if isinstance(possible_ancestor, Entity): # print('ENTITY') for i in range(100): if p.parent: if p.parent == possible_ancestor: return True p = p.parent if isinstance(possible_ancestor, list) or isinstance(possible_ancestor, tuple): # print('LIST OR TUPLE') for e in possible_ancestor: for i in range(100): if p.parent: if p.parent == e: return True break p = p.parent elif isinstance(possible_ancestor, str): print('CLASS NAME', possible_ancestor) for i in range(100): if p.parent: if p.parent.__class__.__name__ == possible_ancestor: return True break p = p.parent return False @property def children(self): return [e for e in scene.entities if e.parent == self] @property def attributes(self): # attribute names. used by duplicate() for instance. return ('name', 'enabled', 'eternal', 'visible', 'parent', 'origin', 'position', 'rotation', 'scale', 'model', 'color', 'texture', 'texture_scale', 'texture_offset', # 'world_position', 'world_x', 'world_y', 'world_z', # 'world_rotation', 'world_rotation_x', 'world_rotation_y', 'world_rotation_z', # 'world_scale', 'world_scale_x', 'world_scale_y', 'world_scale_z', # 'x', 'y', 'z', # 'origin_x', 'origin_y', 'origin_z', # 'rotation_x', 'rotation_y', 'rotation_z', # 'scale_x', 'scale_y', 'scale_z', 'render_queue', 'always_on_top', 'collision', 'collider', 'scripts') #------------ # ANIMATIONS #------------ def animate(self, name, value, duration=.1, delay=0, curve=curve.in_expo, loop=False, resolution=None, interrupt='kill', time_step=None, auto_destroy=True): animator_name = name + '_animator' # print('start animating value:', name, animator_name ) if interrupt and hasattr(self, animator_name): getattr(getattr(self, animator_name), interrupt)() # call kill() or finish() depending on what the interrupt value is. # print('interrupt', interrupt, animator_name) sequence = Sequence(loop=loop, time_step=time_step, auto_destroy=auto_destroy) setattr(self, animator_name, sequence) self.animations.append(sequence) sequence.append(Wait(delay)) if not resolution: resolution = max(int(duration * 60), 1) for i in range(resolution+1): t = i / resolution t = curve(t) sequence.append(Wait(duration / resolution)) sequence.append(Func(setattr, self, name, lerp(getattr(self, name), value, t))) sequence.start() return sequence def animate_position(self, value, duration=.1, **kwargs): x = self.animate('x', value[0], duration, **kwargs) y = self.animate('y', value[1], duration, **kwargs) z = None if len(value) > 2: z = self.animate('z', value[2], duration, **kwargs) return x, y, z def animate_rotation(self, value, duration=.1, **kwargs): x = self.animate('rotation_x', value[0], duration, **kwargs) y = self.animate('rotation_y', value[1], duration, **kwargs) z = self.animate('rotation_z', value[2], duration, **kwargs) return x, y, z def animate_scale(self, value, duration=.1, **kwargs): if isinstance(value, (int, float, complex)): value = Vec3(value, value, value) return self.animate('scale', value, duration, **kwargs) # generate animation functions for e in ('x', 'y', 'z', 'rotation_x', 'rotation_y', 'rotation_z', 'scale_x', 'scale_y', 'scale_z'): exec(dedent(f''' def animate_{e}(self, value, duration=.1, delay=0, **kwargs): return self.animate('{e}', value, duration=duration, delay=delay, **kwargs) ''')) def shake(self, duration=.2, magnitude=1, speed=.05, direction=(1,1)): import random s = Sequence() original_position = self.position for i in range(int(duration / speed)): s.append(Func(self.set_position, Vec3( original_position[0] + (random.uniform(-.1, .1) * magnitude * direction[0]), original_position[1] + (random.uniform(-.1, .1) * magnitude * direction[1]), original_position[2], ))) s.append(Wait(speed)) s.append(Func(self.set_position, original_position)) s.start() return s def animate_color(self, value, duration=.1, interrupt='finish', **kwargs): return self.animate('color', value, duration, interrupt=interrupt, **kwargs) def fade_out(self, value=0, duration=.5, **kwargs): return self.animate('color', Vec4(self.color[0], self.color[1], self.color[2], value), duration, **kwargs) def fade_in(self, value=1, duration=.5, **kwargs): return self.animate('color', Vec4(self.color[0], self.color[1], self.color[2], value), duration, **kwargs) def blink(self, value=color.clear, duration=.1, delay=0, curve=curve.in_expo_boomerang, interrupt='finish', **kwargs): return self.animate_color(value, duration=duration, delay=delay, curve=curve, interrupt=interrupt, **kwargs) def intersects(self, traverse_target=scene, ignore=(), debug=False): from ursina.hit_info import HitInfo if not self.collision or not self.collider: self.hit = HitInfo(hit=False) return self.hit from ursina import distance if not hasattr(self, '_picker'): from panda3d.core import CollisionTraverser, CollisionNode, CollisionHandlerQueue from panda3d.core import CollisionRay, CollisionSegment, CollisionBox self._picker = CollisionTraverser() # Make a traverser self._pq = CollisionHandlerQueue() # Make a handler self._pickerNode = CollisionNode('raycaster') self._pickerNode.set_into_collide_mask(0) self._pickerNP = self.attach_new_node(self._pickerNode) self._picker.addCollider(self._pickerNP, self._pq) self._pickerNP.show() self._pickerNode.addSolid(self._collider.shape) if debug: self._pickerNP.show() else: self._pickerNP.hide() self._picker.traverse(traverse_target) if self._pq.get_num_entries() == 0: self.hit = HitInfo(hit=False) return self.hit ignore += (self, ) ignore += tuple([e for e in scene.entities if not e.collision]) self._pq.sort_entries() self.entries = [ # filter out ignored entities e for e in self._pq.getEntries() if e.get_into_node_path().parent not in ignore ] if len(self.entries) == 0: self.hit = HitInfo(hit=False, distance=0) return self.hit collision = self.entries[0] nP = collision.get_into_node_path().parent point = collision.get_surface_point(nP) point = Vec3(*point) world_point = collision.get_surface_point(render) world_point = Vec3(*world_point) hit_dist = distance(self.world_position, world_point) self.hit = HitInfo(hit=True) self.hit.entity = next(e for e in scene.entities if e == nP) self.hit.point = point self.hit.world_point = world_point self.hit.distance = hit_dist normal = collision.get_surface_normal(collision.get_into_node_path().parent).normalized() self.hit.normal = Vec3(*normal) normal = collision.get_surface_normal(render).normalized() self.hit.world_normal = Vec3(*normal) self.hit.entities = [] for collision in self.entries: self.hit.entities.append(next(e for e in scene.entities if e == collision.get_into_node_path().parent)) return self.hit
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 Collision(): def __init__(self, ui): self.ui = ui # 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.ui.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.ui.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.ui.maze.find("**/ground_collide") self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1)) # 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.ui.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.ui.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)
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 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 RoamingRalphDemo(ShowBase): def __init__(self): # Set up the window, camera, etc. ShowBase.__init__(self) # Set the background color to black self.win.setClearColor((0, 0, 0, 1)) # This is used to store which keys are currently pressed. self.keyMap = { "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0 } # Post the instructions self.title = addTitle( "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)") self.inst1 = addInstructions(0.06, "[ESC]: Quit") self.inst2 = addInstructions(0.12, "[Left Arrow]: Rotate Ralph Left") self.inst3 = addInstructions(0.18, "[Right Arrow]: Rotate Ralph Right") self.inst4 = addInstructions(0.24, "[Up Arrow]: Run Ralph Forward") self.inst6 = addInstructions(0.30, "[A]: Rotate Camera Left") self.inst7 = addInstructions(0.36, "[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) # 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 + (0, 0, 0.5)) # Create a floater object, which floats 2 units above ralph. We # use this as a target for the camera to look at. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(self.ralph) self.floater.setZ(2.0) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left", True]) self.accept("arrow_right", self.setKey, ["right", True]) self.accept("arrow_up", self.setKey, ["forward", True]) self.accept("a", self.setKey, ["cam-left", True]) self.accept("s", self.setKey, ["cam-right", True]) self.accept("arrow_left-up", self.setKey, ["left", False]) self.accept("arrow_right-up", self.setKey, ["right", False]) self.accept("arrow_up-up", self.setKey, ["forward", False]) self.accept("a-up", self.setKey, ["cam-left", False]) self.accept("s-up", self.setKey, ["cam-right", False]) taskMgr.add(self.move, "moveTask") # Game state variables self.isMoving = False # Set up the camera self.disableMouse() self.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, 9) self.ralphGroundRay.setDirection(0, 0, -1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0)) self.ralphGroundCol.setIntoCollideMask(CollideMask.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, 9) self.camGroundRay.setDirection(0, 0, -1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(CollideMask.bit(0)) self.camGroundCol.setIntoCollideMask(CollideMask.allOff()) self.camGroundColNp = self.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((.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection((-5, -5, -5)) directionalLight.setColor((1, 1, 1, 1)) directionalLight.setSpecularColor((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): # Get the time that elapsed since last frame. We multiply this with # the desired speed in order to find out with which distance to move # in order to achieve that desired speed. dt = globalClock.getDt() # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. if self.keyMap["cam-left"]: self.camera.setX(self.camera, -20 * dt) if self.keyMap["cam-right"]: self.camera.setX(self.camera, +20 * dt) # 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"]: self.ralph.setH(self.ralph.getH() + 300 * dt) if self.keyMap["right"]: self.ralph.setH(self.ralph.getH() - 300 * dt) if self.keyMap["forward"]: self.ralph.setY(self.ralph, -25 * dt) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap[ "right"]: 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() - self.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if camdist > 10.0: self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10)) camdist = 10.0 if camdist < 5.0: self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist)) camdist = 5.0 # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. #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 = list(self.ralphGroundHandler.getEntries()) entries.sort(key=lambda x: 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 = list(self.camGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0 and entries[0].getIntoNode().getName( ) == "terrain": self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0) if self.camera.getZ() < self.ralph.getZ() + 2.0: self.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.camera.lookAt(self.floater) return task.cont
class GameContainer(ShowBase): def __init__(self): ShowBase.__init__(self) ########## Window configuration ######### wp = WindowProperties() wp.setSize(1024, 860) self.win.requestProperties(wp) ########## Gameplay settings ######### self.GAME_MODE = PLAY self.play_mode = SPACE self.level = 1.5 self.mode_initialized = False ######### Camera ######### self.disableMouse() self.mainCamera = Camera(self.camera) self.mainCamera.camObject.setHpr(0, 0, 0) #Trigger game chain self.loadLevel(LEVEL) ######### Events ######### self.taskMgr.add(self.gameLoop, "gameLoop", priority = 35) self.keys = {"w" : 0, "s" : 0, "a" : 0, "d" : 0, "space" : 0} self.accept("w", self.setKey, ["w", 1]) self.accept("w-up", self.setKey, ["w", 0]) self.accept("s", self.setKey, ["s", 1]) self.accept("s-up", self.setKey, ["s", 0]) self.accept("a", self.setKey, ["a", 1]) self.accept("a-up", self.setKey, ["a", 0]) self.accept("d", self.setKey, ["d", 1]) self.accept("d-up", self.setKey, ["d", 0]) self.accept("space", self.setKey, ["space", 1]) self.accept("space-up", self.setKey, ["space", 0]) self.accept("wheel_up", self.zoomCamera, [-1]) self.accept("wheel_down", self.zoomCamera, [1]) self.accept("escape", self.switchGameMode, [IN_GAME_MENU]) self.accept("window-event", self.handleWindowEvent) self.accept("playerGroundRayJumping-in", self.avatar.handleCollisionEvent, ["in"]) self.accept("playerGroundRayJumping-out", self.avatar.handleCollisionEvent, ["out"]) ######### GUI ######### self.gui_elements = [] def loadSpaceTexture(self, level): if level < 10: return 'textures/space#.jpg' elif level < 15: pass def loadLevel(self, level): #Resets self.avatarActor = Actor("models/panda", {"walk": "models/panda-walk"}) self.avatarActor.setScale(.5, .5, .5) self.avatarActor.setHpr(180, 0, 0) self.avatarActor.setCollideMask(BitMask32.allOff()) self.asteroidManager = AsteroidManager() #Alternate modes if int(self.level) == self.level: self.play_mode = TERRAIN else: self.play_mode = SPACE #Specifics if self.play_mode == SPACE: self.avatar = Avatar(self.avatarActor) self.avatar.objectNP.reparentTo(render) ########## Sky ######### cubeMap = loader.loadCubeMap(self.loadSpaceTexture(self.level)) self.spaceSkyBox = loader.loadModel('models/box') self.spaceSkyBox.setScale(100) self.spaceSkyBox.setBin('background', 0) self.spaceSkyBox.setDepthWrite(0) self.spaceSkyBox.setTwoSided(True) self.spaceSkyBox.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldCubeMap) self.spaceSkyBox.setTexture(cubeMap, 1) #self.spaceSkyBox.setEffect(CompassEffect.make(render)) parentNP = render.attachNewNode('parent') self.spaceSkyBox.reparentTo(parentNP) self.spaceSkyBox.setPos(-self.spaceSkyBox.getSx()/2, -self.spaceSkyBox.getSy()/2, -self.spaceSkyBox.getSz()/2) self.asteroidManager.initialize(self.level) elif self.play_mode == TERRAIN: ########## Terrain ######### #self.environ = loader.loadModel("../mystuff/test.egg") self.environ = loader.loadModel("models/environment") self.environ.setName("terrain") self.environ.reparentTo(render) self.environ.setPos(0, 0, 0) self.environ.setCollideMask(BitMask32.bit(0)) ######### Models ######### ######### Physics ######### base.enableParticles() gravityForce = LinearVectorForce(0, 0, -9.81) gravityForce.setMassDependent(False) gravityFN = ForceNode("world-forces") gravityFN.addForce(gravityForce) render.attachNewNode(gravityFN) base.physicsMgr.addLinearForce(gravityForce) self.avatarPhysicsActorNP = render.attachNewNode(ActorNode("player")) self.avatarPhysicsActorNP.node().getPhysicsObject().setMass(50.) self.avatarActor.reparentTo(self.avatarPhysicsActorNP) base.physicsMgr.attachPhysicalNode(self.avatarPhysicsActorNP.node()) self.avatarPhysicsActorNP.setPos(15, 10, 5) ######### Game objects ######### self.avatar = Avatar(self.avatarPhysicsActorNP) ######### Collisions ######### self.cTrav = CollisionTraverser() #Make player rigid body self.pandaBodySphere = CollisionSphere(0, 0, 4, 3) self.pandaBodySphereNode = CollisionNode("playerBodyRay") self.pandaBodySphereNode.addSolid(self.pandaBodySphere) self.pandaBodySphereNode.setFromCollideMask(BitMask32.bit(0)) self.pandaBodySphereNode.setIntoCollideMask(BitMask32.allOff()) self.pandaBodySphereNodepath = self.avatar.objectNP.attachNewNode(self.pandaBodySphereNode) self.pandaBodySphereNodepath.show() self.pandaBodyCollisionHandler = PhysicsCollisionHandler() self.pandaBodyCollisionHandler.addCollider(self.pandaBodySphereNodepath, self.avatar.objectNP) #Keep player on ground self.pandaGroundSphere = CollisionSphere(0, 0, 1, 1) self.pandaGroundSphereNode = CollisionNode("playerGroundRay") self.pandaGroundSphereNode.addSolid(self.pandaGroundSphere) self.pandaGroundSphereNode.setFromCollideMask(BitMask32.bit(0)) self.pandaGroundSphereNode.setIntoCollideMask(BitMask32.allOff()) self.pandaGroundSphereNodepath = self.avatar.objectNP.attachNewNode(self.pandaGroundSphereNode) self.pandaGroundSphereNodepath.show() self.pandaGroundCollisionHandler = PhysicsCollisionHandler() self.pandaGroundCollisionHandler.addCollider(self.pandaGroundSphereNodepath, self.avatar.objectNP) #Notify when player lands self.pandaGroundRayJumping = CollisionSphere(0, 0, 1, 1) self.pandaGroundRayNodeJumping = CollisionNode("playerGroundRayJumping") self.pandaGroundRayNodeJumping.addSolid(self.pandaGroundRayJumping) self.pandaGroundRayNodeJumping.setFromCollideMask(BitMask32.bit(0)) self.pandaGroundRayNodeJumping.setIntoCollideMask(BitMask32.allOff()) self.pandaGroundRayNodepathJumping = self.avatar.objectNP.attachNewNode(self.pandaGroundRayNodeJumping) self.pandaGroundRayNodepathJumping.show() self.collisionNotifier = CollisionHandlerEvent() self.collisionNotifier.addInPattern("%fn-in") self.collisionNotifier.addOutPattern("%fn-out") self.cTrav.addCollider(self.pandaGroundSphereNodepath, self.pandaGroundCollisionHandler) self.cTrav.addCollider(self.pandaGroundRayNodepathJumping, self.collisionNotifier) self.cTrav.addCollider(self.pandaBodySphereNodepath, self.pandaBodyCollisionHandler) def maintainTurrets(self): pass def setKey(self, key, value): self.keys[key] = value def zoomCamera(self, direction): Camera.AVATAR_DIST += direction def b(self, hey): self.avatarLanded = True def handleWindowEvent(self, window=None): wp = window.getProperties() self.win_center_x = wp.getXSize() / 2 self.win_center_y = wp.getYSize() / 2 def switchGameMode(self, newGameMode=None): self.cleanupGUI() if self.GAME_MODE == IN_GAME_MENU: if newGameMode == PLAY: render.clearFog() elif newGameMode == MAIN_MENU: pass elif True: pass self.GAME_MODE = newGameMode self.mode_initialized = False def cleanupGUI(self): for gui_element in self.gui_elements: gui_element.destroy() def evenButtonPositions(self, button_spacing, button_height, num_buttons): center_offset = (button_spacing/(2.0) if (num_buttons % 2 == 0) else 0) button_positions = [] current_pos = center_offset + ((num_buttons - 1)/2) * button_spacing for i in range(0, num_buttons): button_positions.append(current_pos + (button_height/2.0)) current_pos -= button_spacing return button_positions def buildInGameMenu(self): props = WindowProperties() props.setCursorHidden(False) base.win.requestProperties(props) resume_button = DirectButton(text = "Resume", scale = .1, command = (lambda: self.switchGameMode(PLAY)), rolloverSound=None) main_menu_button = DirectButton(text = "Main Menu", scale = .1, command = self.b, rolloverSound=None) options_button = DirectButton(text = "Options", scale = .1, command = self.b, rolloverSound=None) exit_button = DirectButton(text = "Exit", scale = .1, command = exit, rolloverSound=None) BUTTON_SPACING = .2 BUTTON_HEIGHT = resume_button.getSy() button_positions = self.evenButtonPositions(BUTTON_SPACING, BUTTON_HEIGHT, 4) resume_button.setPos(Vec3(0, 0, button_positions[0])) main_menu_button.setPos(Vec3(0, 0, button_positions[1])) options_button.setPos(Vec3(0, 0, button_positions[2])) exit_button.setPos(Vec3(0, 0, button_positions[3])) self.gui_elements.append(resume_button) self.gui_elements.append(main_menu_button) self.gui_elements.append(options_button) self.gui_elements.append(exit_button) def buildMainMenu(self): props = WindowProperties() props.setCursorHidden(False) base.win.requestProperties(props) start_game_button = DirectButton(text = "Start", scale = .1, command = self.b) select_level_button = DirectButton(text = "Select Level", scale = .1, command = self.b) game_options_button = DirectButton(text = "Options", scale = .1, command = self.b) exit_button = DirectButton(text = "Exit", scale = .1, command = exit) BUTTON_SPACING = .2 BUTTON_HEIGHT = start_game_button.getSy() button_positions = self.evenButtonPositions(BUTTON_SPACING, BUTTON_HEIGHT) start_game_button.setPos(Vec3(0, 0, button_positions[0])) select_level_button.setPos(Vec3(0, 0, button_positions[1])) game_options_button.setPos(Vec3(0, 0, button_positions[2])) exit_button.setPos(Vec3(0, 0, button_positions[3])) self.gui_elements.append(start_game_button) self.gui_elements.append(select_level_button) self.gui_elements.append(game_options_button) self.gui_elements.append(exit_button) def gameLoop(self, task): #Compensate for inconsistent update intervals dt = globalClock.getDt() if self.GAME_MODE == MAIN_MENU: if not self.mode_initialized: self.buildMainMenu() self.mode_initialized = True if self.GAME_MODE == IN_GAME_MENU: if not self.mode_initialized: #Fog out background inGameMenuFogColor = (50, 150, 50) inGameMenuFog = Fog("inGameMenuFog") inGameMenuFog.setMode(Fog.MExponential) inGameMenuFog.setColor(*inGameMenuFogColor) inGameMenuFog.setExpDensity(.01) render.setFog(inGameMenuFog) self.buildInGameMenu() self.mode_initialized = True if self.GAME_MODE == PLAY: if not self.mode_initialized: props = WindowProperties() props.setCursorHidden(True) base.win.requestProperties(props) self.last_mouse_x = self.win.getPointer(0).getX() self.last_mouse_y = self.win.getPointer(0).getY() self.mode_initialized = True if self.play_mode == TERRAIN: self.maintainTurrets() self.avatar.move(dt) elif self.play_mode == SPACE: self.asteroidManager.maintainAsteroidField(self.avatar.objectNP.getPos(), self.avatar.speed, dt) #Handle keyboard input self.avatar.handleKeys(self.keys, self.play_mode) ########## Mouse-based viewpoint rotation ########## mouse_pos = self.win.getPointer(0) current_mouse_x = mouse_pos.getX() current_mouse_y = mouse_pos.getY() #Side to side if self.play_mode == TERRAIN: mouse_shift_x = current_mouse_x - self.last_mouse_x self.last_mouse_x = current_mouse_x if current_mouse_x < 5 or current_mouse_x >= (self.win_center_x * 1.5): base.win.movePointer(0, self.win_center_x, current_mouse_y) self.last_mouse_x = self.win_center_x yaw_shift = -((mouse_shift_x) * Camera.ROT_RATE[0]) self.avatar.yawRot += yaw_shift self.avatar.objectNP.setH(self.avatar.yawRot) #Up and down mouse_shift_y = current_mouse_y - self.last_mouse_y self.last_mouse_y = current_mouse_y if current_mouse_y < 5 or current_mouse_y >= (self.win_center_y * 1.5): base.win.movePointer(0, current_mouse_x, self.win_center_y) self.last_mouse_y = self.win_center_y pitch_shift = -((mouse_shift_y) * Camera.ROT_RATE[1]) self.mainCamera.pitchRot += pitch_shift if self.mainCamera.pitchRot > Camera.FLEX_ROT_MAG[0]: self.mainCamera.pitchRot = Camera.FLEX_ROT_MAG[0] elif self.mainCamera.pitchRot < -Camera.FLEX_ROT_MAG[0]: self.mainCamera.pitchRot = -Camera.FLEX_ROT_MAG[0] xy_plane_cam_dist = Camera.AVATAR_DIST cam_x_adjust = xy_plane_cam_dist*sin(radians(self.avatar.yawRot)) cam_y_adjust = xy_plane_cam_dist*cos(radians(self.avatar.yawRot)) cam_z_adjust = Camera.ELEVATION self.mainCamera.camObject.setH(self.avatar.yawRot) self.mainCamera.camObject.setP(self.mainCamera.pitchRot) self.mainCamera.camObject.setPos(self.avatar.objectNP.getX() + cam_x_adjust, self.avatar.objectNP.getY() - cam_y_adjust, self.avatar.objectNP.getZ() + cam_z_adjust) #Find collisions #self.cTrav.traverse(render) #print self.environ.getBounds() return Task.cont
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 RoamingRalphDemo(ShowBase): def __init__(self): # Set up the window, camera, etc. ShowBase.__init__(self) # Set the background color to black self.win.setClearColor((0, 0, 0, 1)) # This is used to store which keys are currently pressed. self.keyMap = { "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0} # Post the instructions self.title = addTitle( "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)") self.inst1 = addInstructions(0.06, "[ESC]: Quit") self.inst2 = addInstructions(0.12, "[Left Arrow]: Rotate Ralph Left") self.inst3 = addInstructions(0.18, "[Right Arrow]: Rotate Ralph Right") self.inst4 = addInstructions(0.24, "[Up Arrow]: Run Ralph Forward") self.inst6 = addInstructions(0.30, "[A]: Rotate Camera Left") self.inst7 = addInstructions(0.36, "[S]: Rotate Camera Right") self.dirText = addInstructions(0.42, "pos") self.anglesText = addInstructions(0.48, "angle") # 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.createArm() # 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 + (0, 0, 0.5)) # Create a floater object, which floats 2 units above ralph. We # use this as a target for the camera to look at. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(self.ralph) self.floater.setZ(2.0) # Accept the control keys for movement and rotation self.accept("escape", self.exitButton) self.accept("arrow_left", self.setKey, ["left", True]) self.accept("arrow_right", self.setKey, ["right", True]) self.accept("arrow_up", self.setKey, ["forward", True]) self.accept("a", self.setKey, ["cam-left", True]) self.accept("s", self.setKey, ["cam-right", True]) self.accept("arrow_left-up", self.setKey, ["left", False]) self.accept("arrow_right-up", self.setKey, ["right", False]) self.accept("arrow_up-up", self.setKey, ["forward", False]) self.accept("a-up", self.setKey, ["cam-left", False]) self.accept("s-up", self.setKey, ["cam-right", False]) taskMgr.add(self.move, "moveTask") # Game state variables self.isMoving = False # Set up the camera self.disableMouse() self.camera.setPos(15, 0, 3)#self.ralph.getX(), self.ralph.getY() + 10, 2) self.camera.setHpr(90, -5, 0) # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above ralph's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 9) self.ralphGroundRay.setDirection(0, 0, -1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0)) self.ralphGroundCol.setIntoCollideMask(CollideMask.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, 9) self.camGroundRay.setDirection(0, 0, -1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(CollideMask.bit(0)) self.camGroundCol.setIntoCollideMask(CollideMask.allOff()) self.camGroundColNp = self.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((.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection((-5, -5, -5)) directionalLight.setColor((1, 1, 1, 1)) directionalLight.setSpecularColor((1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) def exitButton(self): servos.exit() __import__('sys').exit() def createArm(self): self.robotarm = Actor("models/robotarm") self.robotarm.reparentTo(render) self.robotarm.setPos(0,0,0) self.robotarm.setScale(.2) self.jointForearm = self.robotarm.controlJoint(None, "modelRoot", "forearm") self.jointBase = self.robotarm.controlJoint(None, "modelRoot", "base") taskMgr.add(self.monitorArm, "robot arm") inc = 15 self.accept("i", self.setForearm, [inc]) self.accept("u", self.setForearm, [-inc]) self.accept("j", self.setBase, [inc]) self.accept("k", self.setBase, [-inc]) def monitorArm(self, task): def clamp1(x): return min(1, max(-1, x)) direction = self.ralph.get_pos() - self.robotarm.get_pos() direction.z += 1 direction.normalize() # camera starts facing along x dec = math.asin(direction.x) cosdec = math.cos(dec) if cosdec > 1e-05: ra = math.asin(clamp1(direction.z / cosdec)) ra2 = math.acos(clamp1(direction.y / cosdec)) else: ra = ra2 = math.pi/2#float('nan') #print(cosdec, direction) #print(dec, ra, ra2, cosdec) if direction.z < 0: if ra2 < math.pi/2: ra2 = 0 else: ra2 = math.pi self.jointForearm.setH(-dec * 180/math.pi) self.jointBase.setP(ra2 * 180/math.pi) self.dirText.setText(str(direction)) self.anglesText.setText(str((dec, ra, ra2, cosdec))) a = self.jointForearm.getH() / 90.0 * 300 + 512 b = self.jointBase.getP() / 90.0 * 300 + 212 #print(a, b) baseID = 9 servos.setAngle({baseID:int(round(b)), (baseID+1):int(round(a))}) return task.again def monitorArmServos(self, task): baseID = 9 a = self.jointForearm.getH() / 90.0 * 300 + 512 b = self.jointBase.getP() / 90.0 * 300 + 212 #print(a, b) servos.setAngle({baseID:int(round(a)), (baseID+1):int(round(b))}) # frac = task.time - int(task.time) # if frac > .9 and frac < .99: #print(self.jointForearm.getH(), self.jointBase.getP()) return task.again def setForearm(self, inc): #self.jointForearm.setH(random.random()*180-90) self.jointForearm.setH(self.jointForearm.getH() + inc) def setBase(self, inc): #self.jointBase.setP(random.random()*180) self.jointBase.setP(self.jointBase.getP() + inc) # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # Get the time that elapsed since last frame. We multiply this with # the desired speed in order to find out with which distance to move # in order to achieve that desired speed. dt = globalClock.getDt() # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. if self.keyMap["cam-left"]: self.camera.setX(self.camera, -20 * dt) if self.keyMap["cam-right"]: self.camera.setX(self.camera, +20 * dt) # 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"]: self.ralph.setH(self.ralph.getH() + 300 * dt) if self.keyMap["right"]: self.ralph.setH(self.ralph.getH() - 300 * dt) if self.keyMap["forward"]: self.ralph.setY(self.ralph, -25 * dt) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"]: 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() - self.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if camdist > 10.0: self.camera.setPos(self.camera.getPos() + camvec * (camdist - 10)) camdist = 10.0 if camdist < 5.0: self.camera.setPos(self.camera.getPos() - camvec * (5 - camdist)) camdist = 5.0 # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. #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 = list(self.ralphGroundHandler.getEntries()) entries.sort(key=lambda x: 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 = list(self.camGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain": self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0) if self.camera.getZ() < self.ralph.getZ() + 2.0: self.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.camera.lookAt(self.floater)""" return task.cont
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 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 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 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 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 RoamingRalphDemo(ShowBase): def __init__(self): # Set up the window, camera, etc. ShowBase.__init__(self) self.orbCollisionHandler = CollisionHandlerQueue() self.cTrav = CollisionTraverser() self.cTrav.setRespectPrevTransform(True) #hbPath = NodePath() utilsKristina2.setUpKeys(self) utilsKristina2.loadModels(self) utilsKristina2.setUpLighting(self) utilsKristina2.setUpFloatingSpheres(self) utilsKristina2.setUpRalphsShot(self) utilsKristina2.setUpCamera(self) utilsKristina2.setUpCollisionSpheres(self) self.healthTxt = utilsKristina2.addInstructions(.06,"Health: 100") self.orbTxt = utilsKristina2.addInstructions(.18,"Orbs: 0") self.vec = LVector3(0,1,0)#vector for pawns shot # Create a frame #frame = DirectFrame(text = "main", scale = 0.001) # Add button #bar = DirectWaitBar(text = "", value = 50, pos = (0,.4,.4)) #bar.reparent(render) # Game state variables self.isMoving = False self.jumping = False self.vz = 0 self.numOrbs = 0 self.healthCount = 100 #self.shotList = [] #self.sphere = CollisionBox((self.ralph.getX() + -10,self.ralph.getY(),self.ralph.getZ()),10,10,10) self.sphere = CollisionSphere(0,-5,4,3) self.sphere3 = CollisionSphere(0,5,5,3) self.sphere4 = CollisionSphere(-4,0,5,2) self.sphere5 = CollisionSphere(4,0,5,2) self.sphere2 = CollisionSphere(0,0,3,2) self.cnodePath = self.ralph.attachNewNode((CollisionNode("ralphColNode"))) self.cnodePath2 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck"))) self.cnodePath3 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck2"))) self.cnodePath4 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck3"))) self.cnodePath5 = self.ralph.attachNewNode((CollisionNode("ralphWallCheck4"))) self.cnodePath.node().addSolid(self.sphere2) self.cnodePath2.node().addSolid(self.sphere) self.cnodePath3.node().addSolid(self.sphere3) self.cnodePath4.node().addSolid(self.sphere4) self.cnodePath5.node().addSolid(self.sphere5) #self.cnodePath.node().addSolid(self.sphere2) self.cnodePath.show() #self.cnodePath2.show() #self.cnodePath3.show() #self.cnodePath4.show() #self.cnodePath5.show() self.cTrav.addCollider(self.cnodePath2, self.orbCollisionHandler) self.cTrav.addCollider(self.cnodePath3, self.orbCollisionHandler) self.cTrav.addCollider(self.cnodePath4, self.orbCollisionHandler) self.cTrav.addCollider(self.cnodePath5, self.orbCollisionHandler) self.pusher = CollisionHandlerPusher() self.pusher.addCollider(self.cnodePath, self.ralph) #self.cTrav.addCollider(self.cnodePath, self.ralphCollisionHandler) self.cTrav.addCollider(self.cnodePath, self.pusher) self.chrisLastShotTime = globalClock.getFrameTime() self.chrisTimer = globalClock.getDt() #def __init__(self, pos,showbase, colPathName, dir, length): self.chrisList = [utilsKristina2.chris((15,0,0.5),self,"chrisColPath0","X",6), utilsKristina2.chris((18,29,0.5),self,"chrisColPath1","X",6), utilsKristina2.chris((-6,67,0.5),self,"chrisColPath2","X",6), utilsKristina2.chris((-41,72,0.5),self,"chrisColPath7","X",6)] #,utilsKristina2.chris((-42,106,0.5),self,"chrisColPath3","X",6)]#, utilsKristina2.chris((-62,108,0.5),self,"chrisColPath4","X",6), #utilsKristina2.chris((-74,70,0.5),self,"chrisColPath5","y",6)] #def _init_(self,showbase,pos,color,speed,radius): self.orbList = [utilsKristina2.orb(self,(0,0,2),(0,0,1,1),20,4)] self.donutList = [utilsKristina2.donut(self,(0,0,2),40,3)] self.cameraCollided = False self.ralphSpeed = 60 self.ralphHit = False self.ralphRedTime = 0 self.ralphLife=True taskMgr.add(self.move, "moveTask") taskMgr.add(self.moveChris,"moveChrisTask") # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value def startEnemyThread(self): showbase = self class enemyThread(threading.Thread): def run(self): dt = globalClock.getDt() for chris in showbase.chrisList: chris.moveChris(dt,showbase,showbase.chrisList) def moveChris(self,task): dt = globalClock.getDt() for chris in self.chrisList: chris.moveChris(dt,self,self.chrisList) return task.cont # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # Get the time that elapsed since last frame. We multiply this with # the desired speed in order to find out with which distance to move # in order to achieve that desired speed. dt = globalClock.getDt() #utilsKristina2.moveChris(self,dt) #self.chris2.moveChris(dt,self) #self.startEnemyThread() if globalClock.getFrameTime()- self.ralphRedTime > .3 and self.ralphHit == True: self.ralph.clearColor() self.ralphHit = False # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. if self.keyMap["cam-left"]: self.camera.setZ(self.camera, -20 * dt) if self.keyMap["cam-right"]: self.camera.setZ(self.camera, +20 * dt) # 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"]: self.ralph.setH(self.ralph.getH() + 75 * dt) #self.camera.setX(self.camera, +15.5 * dt) if self.keyMap["right"]: self.ralph.setH(self.ralph.getH() - 75 * dt) #self.camera.setX(self.camera, -15.5 * dt) if self.keyMap["forward"]: self.ralph.setFluidY(self.ralph, -1*self.ralphSpeed * dt) #self.camera.setY(self.camera, -35 * dt) if self.keyMap["back"]: self.ralph.setFluidY(self.ralph, self.ralphSpeed * dt) #self.camera.setY(self.camera, 35 * dt) if self.keyMap["space"]: if self.jumping is False: #self.ralph.setZ(self.ralph.getZ() + 100 * dt) self.jumping = True self.vz = 8 if self.keyMap["c"] or self.keyMap["enter"]: if self.keyMap["c"]: self.keyMap["c"]=False if self.keyMap["enter"]: self.keyMap["enter"] = False self.shotList[self.shotCount].lpivot.setPos(self.ralph.getPos()) self.shotList[self.shotCount].lpivot.setZ(self.ralph.getZ() + .5) self.shotList[self.shotCount].lpivot.setX(self.ralph.getX() - .25) print self.ralph.getPos() #self.shotList.append(rShot) #self.lightpivot3.setPos(self.ralph.getPos()) #self.lightpivot3.setZ(self.ralph.getZ() + .5) #self.lightpivot3.setX(self.ralph.getX() - .25) #self.myShot.setHpr(self.ralph.getHpr()) #parent to ralph #node = NodePath("tmp") #node.setHpr(self.ralph.getHpr()) #vec = render.getRelativeVector(node,(0,-1,0)) #self.myShotVec = vec node = NodePath("tmp") node.setHpr(self.ralph.getHpr()) vec = render.getRelativeVector(node,(0,-1,0)) self.shotList[self.shotCount].vec = vec self.shotCount = (self.shotCount + 1) % 10 for rs in self.shotList: rs.lpivot.setPos(rs.lpivot.getPos() + rs.vec * dt * 25 ) #if shot is too far stop updating if self.jumping is True: self.vz = self.vz - 16* dt self.ralph.setZ(self.ralph.getZ() + self.vz * dt ) if self.ralph.getZ() < 0: self.ralph.setZ(0) self.jumping = False else: if self.ralph.getZ() < 0.25: self.ralph.setZ(0.25) elif self.ralph.getZ() > 0.25: self.ralph.setZ(self.ralph.getZ() -7 * dt) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"] or self.keyMap["space"] or self.keyMap["forward"] or self.keyMap["back"]: 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 # update pawns shot or set up new shot after it reaches a certain distance node = NodePath("tmp") node.setHpr(self.pawn.getHpr()) vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0)) self.shot.setPos(self.shot.getPos() + self.vec * dt * 10 ) if self.shot.getY() < -15 or self.shot.getY() > 30 or self.shot.getX() < 5 or self.shot.getX() > 15: self.shot.setPos(self.pawn.getPos() + (0,0,0)) self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0)) self.vec = render.getRelativeVector(node,(random.random() * random.randrange(-1,2),random.random() + 1,0)) # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. #self.camera.lookAt(self.floater) camvec = self.ralph.getPos() - self.camera.getPos() #camvec = Vec3(0,camvec.getY(),0) camdist = camvec.length() x = self.camera.getZ() camvec.normalize() #if camdist > 6.0: # self.camera.setPos(self.camera.getPos() + camvec * (camdist - 6)) #if camdist < 6.0: # self.camera.setPos(self.camera.getPos() - camvec * (6 - camdist)) # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. #self.cTrav.traverse(render) # Adjust camera so it stays at same height if self.cameraCollided == False: if self.camera.getZ() < self.ralph.getZ() + 1 or self.camera.getZ() > self.ralph.getZ() + 1: self.camera.setZ(self.ralph.getZ() + 1) # 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.camera.lookAt(self.floater) entries = list(self.orbCollisionHandler.getEntries()) if(len(entries) > 0): #self.lightpivot.reparentTo(NodePath()) orbCollected = False self.cameraCollided = False self.ralphSpeed = 65 for entry in self.orbCollisionHandler.getEntries(): #print(entry) fromColNp = entry.getFromNodePath() toColNp = entry.getIntoNodePath() if fromColNp.getName() == "orbColPath" and toColNp.getName() == "ralphColNode": if orbCollected == False: fromColNp.getParent().reparentTo(NodePath()) self.orbTxt.destroy() self.numOrbs += 1 str1 = "Orbs: " + str(self.numOrbs) self.orbTxt = utilsKristina2.addInstructions(.18, str1) orbCollected = True elif toColNp.getName() == "orbColPath" and fromColNp.getName() == "ralphColNode": if orbCollected == False: toColNp.getParent().reparentTo(NodePath()) self.orbTxt.destroy() self.numOrbs += 1 str1 = "Orbs: " + str(self.numOrbs) self.orbTxt = utilsKristina2.addInstructions(.18, str1) orbCollected = True elif toColNp.getName() == "ralphOrbColPath" and (fromColNp.getName()[:-1] == "chrisColPath" or fromColNp.getName()[:-2] == "chrisColPath"): toColNp.getParent().setZ(20) for chriss in self.chrisList: if chriss.chrisColName == fromColNp.getName(): chris = chriss break chris.chrisHealth = chris.chrisHealth - 1 chris.chris.setColor(1,0,0,1) chris.chrisHit = True chris.chrisRedTime = globalClock.getFrameTime() #print chris.chrisRedTime if chris.chrisHealth < 0: fromColNp.getParent().removeNode() chris.chrisAlive = False chris.chrisShot.setZ(26) elif (toColNp.getName()[:-1] == "chrisColPath" or toColNp.getName()[:-2] == "chrisColPath") and fromColNp.getName() == "ralphOrbColPath": fromColNp.getParent().setZ(20) for chriss in self.chrisList: if chriss.chrisColName == toColNp.getName(): chris = chriss break chris.chrisHealth = chris.chrisHealth - 1 chris.chris.setColor(1,0,0,1) chris.chrisHit = True chris.chrisRedTime = globalClock.getFrameTime() #print chris.chrisRedTime if chris.chrisHealth < 0: toColNp.getParent().removeNode() chris.chrisAlive = False chris.chrisShot.setZ(26) elif toColNp.getName() == "enemyOrbColPath" and fromColNp.getName() == "ralphColNode": toColNp.getParent().setZ(26) self.healthTxt.destroy() self.healthCount -= 3 str1 = "Health: " + str(self.healthCount) self.healthTxt = utilsKristina2.addInstructions(.06, str1) self.ralphHit = True self.ralph.setColor((1,0,0,1)) self.ralphRedTime = globalClock.getFrameTime() if self.healthCount <=0: sys.exit() elif toColNp.getName() == "ralphColNode" and fromColNp.getName() == "enemyOrbColPath": fromColNp.getParent().setZ(26) self.healthTxt.destroy() self.healthCount -= 3 str1 = "Health: " + str(self.healthCount) self.healthTxt = utilsKristina2.addInstructions(.06, str1) self.ralphHit = True self.ralph.setColor((1,0,0,1)) self.ralphRedTime = globalClock.getFrameTime() if self.healthCount <=0: sys.exit() elif fromColNp.getName() == "ralphOrbColPath" and toColNp.getName() == "allinclusive": fromColNp.getParent().setZ(50) elif toColNp.getName() == "ralphOrbColPath" and fromColNp.getName() == "allinclusive": toColNp.getParent().setZ(50) elif fromColNp.getName() == "enemyOrbWallCheck" and toColNp.getName() == "allinclusive": fromColNp.getParent().setZ(50) #print toColNp.getName() elif toColNp.getName() == "enemyOrbWallCheck" and fromColNp.getName() == "allinclusive": toColNp.getParent().setZ(50) #print fromColNp.getName() elif fromColNp.getName() == "ralphWallCheck" and toColNp.getName() == "allinclusive": #node = NodePath("tmp") #node.setHpr(self.ralph.getHpr()) #vec = render.getRelativeVector(node,(0,-1,0)) #self.ralph.setPos(self.ralph.getPos()-vec) #fromColNp.getParent().setZ(26) self.ralphSpeed = 25 elif toColNp.getName() == "ralphWallCheck" and fromColNp.getName() == "allinclusive": #node = NodePath("tmp") #node.setHpr(self.ralph.getHpr()) #vec = render.getRelativeVector(node,(0,-1,0)) #self.ralph.setPos(self.ralph.getPos()-vec) #print "wtf" #toColNp.getParent().setZ(26) self.ralphSpeed = 25 elif fromColNp.getName() == "ralphWallCheck2" and toColNp.getName() == "allinclusive": #node = NodePath("tmp") #node.setHpr(self.ralph.getHpr()) #vec = render.getRelativeVector(node,(0,1,0)) #self.ralph.setPos(self.ralph.getPos()-vec) #fromColNp.getParent().setZ(26) self.ralphSpeed = 25 elif toColNp.getName() == "ralphWallCheck2" and fromColNp.getName() == "allinclusive": #node = NodePath("tmp") #node.setHpr(self.ralph.getHpr()) #vec = render.getRelativeVector(node,(0,1,0)) #self.ralph.setPos(self.ralph.getPos()-vec) #self.camera.setPos(self.ralph.getPos()) #self.cameraCollided = True self.ralphSpeed = 25 elif fromColNp.getName() == "ralphWallCheck3" and toColNp.getName() == "allinclusive": #node = NodePath("tmp") #node.setHpr(self.ralph.getHpr()) #vec = render.getRelativeVector(node,(-1,0,0)) #self.ralph.setPos(self.ralph.getPos()-vec) #fromColNp.getParent().setZ(26) self.ralphSpeed = 25 print "3" elif toColNp.getName() == "ralphWallCheck3" and fromColNp.getName() == "allinclusive": #node = NodePath("tmp") #node.setHpr(self.ralph.getHpr()) #vec = render.getRelativeVector(node,(-1,0,0)) #self.ralph.setPos(self.ralph.getPos()-vec) #self.camera.setPos(self.ralph.getPos()) #self.cameraCollided = True self.ralphSpeed = 25 print "3" elif fromColNp.getName() == "ralphWallCheck4" and toColNp.getName() == "allinclusive": #node = NodePath("tmp") #node.setHpr(self.ralph.getHpr()) #vec = render.getRelativeVector(node,(1,0,0)) #self.ralph.setPos(self.ralph.getPos()-vec) #fromColNp.getParent().setZ(26) self.ralphSpeed = 25 print "4" elif toColNp.getName() == "ralphWallCheck4" and fromColNp.getName() == "allinclusive": #node = NodePath("tmp") #node.setHpr(self.ralph.getHpr()) #vec = render.getRelativeVector(node,(1,0,0)) #self.ralph.setPos(self.ralph.getPos()-vec) #self.camera.setPos(self.ralph.getPos()) #self.cameraCollided = True self.ralphSpeed = 25 print "4" return task.cont