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
class ShipCollision: def __init__(self, game): self.game = game self.setup_collision() self.queue = CollisionHandlerQueue() self.traverser = CollisionTraverser('Collision Traverser') self.traverser.showCollisions(render) self.traverser.add_collider(self.target_nodepath, self.queue) base.taskMgr.add(self.collide, "Collision Task") def setup_collision(self): self.target = CollisionSphere(0, 0, 0, 0.5) self.target_node = CollisionNode('collision_ship') self.target_node.setFromCollideMask(ENEMIES) self.target_node.setIntoCollideMask(ALLIES) self.target_nodepath = self.game.ship.model.attach_new_node( self.target_node) self.target_nodepath.node().addSolid(self.target) self.target_nodepath.show() def collide(self, task): self.traverser.traverse(render) for entry in self.queue.get_entries(): print("Ship:") print(entry) return task.cont
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 EntityCollision: def __init__(self, entity): self.entity = entity self.setup_collision() self.queue = CollisionHandlerQueue() self.traverser = CollisionTraverser('Collision Traverser') self.traverser.showCollisions(render) self.traverser.add_collider(self.target_nodepath, self.queue) base.taskMgr.add(self.collide, "Collision Task") def setup_collision(self): self.target = CollisionSphere(0, 0, 0, 1) self.target_node = CollisionNode('collision_entity') self.target_node.setFromCollideMask(ALLIES) # unused self.target_node.setIntoCollideMask(ENEMIES) self.target_nodepath = self.entity.model.attach_new_node(self.target_node) self.target_nodepath.node().addSolid(self.target) self.target_nodepath.show() def collide(self, task): self.traverser.traverse(render) for entry in self.queue.get_entries(): # print("Entity:") pos = entry.getSurfacePoint(self.entity.model) pos_x = pos[0] pos_z = pos[2] self.entity.spawn_particles(pos_x, pos_z) self.entity.life -= 1 return task.cont
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 BulletCollision: def __init__(self, bullet): self.bullet = bullet self.setup_collision() self.queue = CollisionHandlerQueue() self.traverser = CollisionTraverser('Collision Traverser') self.traverser.showCollisions(render) self.traverser.add_collider(self.target_nodepath, self.queue) base.taskMgr.add(self.collide, "Collision Task") def setup_collision(self): self.target = CollisionSphere(0, 0, 0, 0.1) self.target_node = CollisionNode('collision_bullet') self.target_node.setFromCollideMask(ENEMIES) self.target_node.setIntoCollideMask(ALLIES) self.target_nodepath = self.bullet.model.attach_new_node( self.target_node) self.target_nodepath.node().addSolid(self.target) self.target_nodepath.show() def collide(self, task): self.traverser.traverse(render) for entry in self.queue.get_entries(): #print("Bullet:") #print(entry) self.bullet.model.removeNode() return task.cont
class ShipCollision: def __init__(self, ship): self.ship = ship self.setup_collision() self.queue = CollisionHandlerQueue() self.traverser = CollisionTraverser('Collision Traverser') self.traverser.showCollisions(render) self.traverser.add_collider(self.target_nodepath, self.queue) base.taskMgr.add(self.collide, "Collision Task") def setup_collision(self): self.target = CollisionSphere(0, 0, 0, 0.5) self.target_node = CollisionNode('collision_ship') self.target_node.setFromCollideMask(ENEMIES) self.target_node.setIntoCollideMask(ALLIES) self.target_nodepath = self.ship.model.attach_new_node(self.target_node) self.target_nodepath.node().addSolid(self.target) #self.target_nodepath.show() def collide(self, task): self.traverser.traverse(render) for entry in self.queue.get_entries(): #print("Ship:") #print(entry) self.ship.model.cleanup() self.ship.model.removeNode() return task.cont
class RayThatCollidesWithScene: def __init__(self): self.hitters = [self.setup_collision_ray(offset, bitmask) for offset, bitmask in [ (-3, BM_LEFT), (3, BM_RIGHT), ]] self.queue = CollisionHandlerQueue() self.traverser = CollisionTraverser('Collision Traverser') self.traverser.showCollisions(base.render) for ray in self.hitters: self.traverser.add_collider(ray, self.queue) base.taskMgr.add(self.collide, "Collision Task") def setup_collision_ray(self, offset, bitmask): # Hitter. Do note that not every combination of object works, # there is a table for that in the manual. hitter = CollisionRay(0, 0, 0, 0, 1, 0) hitter_node = CollisionNode('collision_hitter') hitter_node.setFromCollideMask(bitmask) hitter_nodepath = base.render.attach_new_node(hitter_node) hitter_nodepath.node().addSolid(hitter) hitter_nodepath.set_pos(offset, -2, 0) hitter_nodepath.show() return hitter_nodepath def collide(self, task): self.traverser.traverse(render) for entry in self.queue.get_entries(): print(entry) return task.cont
class EntityCollision: def __init__(self, entity): self.entity = entity self.setup_collision() self.queue = CollisionHandlerQueue() self.traverser = CollisionTraverser('Collision Traverser') self.traverser.showCollisions(render) self.traverser.add_collider(self.target_nodepath, self.queue) base.taskMgr.add(self.collide, "Collision Task") def setup_collision(self): self.target = CollisionSphere(0, 0, 0, 1) self.target_node = CollisionNode('collision_entity') self.target_node.setFromCollideMask(ALLIES) # unused self.target_node.setIntoCollideMask(ENEMIES) self.target_nodepath = self.entity.model.attach_new_node( self.target_node) self.target_nodepath.node().addSolid(self.target) self.target_nodepath.show() def collide(self, task): self.traverser.traverse(render) for entry in self.queue.get_entries(): # print("Entity:") pos = entry.getSurfacePoint(self.entity.model) pos_x = pos[0] pos_z = pos[2] self.entity.spawn_particles(pos_x, pos_z) self.entity.life -= 1 return task.cont
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 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 checkcmcdlistlist(objcmlist0, objcmlist1, toggleplot=False): """ detect the collision between two collision model lists :return: True or False author: weiwei, Toyonaka date: 20190422 """ oocnp0 = NodePath("collision nodepath") oocnp1 = NodePath("collision nodepath") obj0cnplist = [] for objcm0 in objcmlist0: obj0cnplist.append(objcm0.copycdnpTo(oocnp0)) obj1cnplist = [] for objcm1 in objcmlist1: obj1cnplist.append(objcm1.copycdnpTo(oocnp1)) if toggleplot: oocnp0.reparentTo(base.render) oocnp1.reparentTo(base.render) for obj0cnp in obj0cnplist: obj0cnp.show() for obj1cnp in obj1cnplist: obj1cnp.show() ctrav = CollisionTraverser() chan = CollisionHandlerQueue() for obj0cnp in obj0cnplist: ctrav.addCollider(obj0cnp, chan) ctrav.traverse(oocnp1) if chan.getNumEntries() > 0: return True else: return False
class RayThatCollidesWithScene: def __init__(self): self.hitters = [ self.setup_collision_ray(offset, bitmask) for offset, bitmask in [ (-3, BM_LEFT), (3, BM_RIGHT), ] ] self.queue = CollisionHandlerQueue() self.traverser = CollisionTraverser('Collision Traverser') self.traverser.showCollisions(base.render) for ray in self.hitters: self.traverser.add_collider(ray, self.queue) base.taskMgr.add(self.collide, "Collision Task") def setup_collision_ray(self, offset, bitmask): # Hitter. Do note that not every combination of object works, # there is a table for that in the manual. hitter = CollisionRay(0, 0, 0, 0, 1, 0) hitter_node = CollisionNode('collision_hitter') hitter_node.setFromCollideMask(bitmask) hitter_nodepath = base.render.attach_new_node(hitter_node) hitter_nodepath.node().addSolid(hitter) hitter_nodepath.set_pos(offset, -2, 0) hitter_nodepath.show() return hitter_nodepath def collide(self, task): self.traverser.traverse(render) for entry in self.queue.get_entries(): print(entry) return task.cont
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 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 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
def make_collision(solid_from, solid_into): node_from = CollisionNode("from") node_from.add_solid(solid_from) node_into = CollisionNode("into") node_into.add_solid(solid_into) root = NodePath("root") trav = CollisionTraverser() queue = CollisionHandlerQueue() np_from = root.attach_new_node(node_from) np_into = root.attach_new_node(node_into) trav.add_collider(np_from, queue) trav.traverse(root) entry = None for e in queue.get_entries(): if e.get_into() == solid_into: entry = e return (entry, np_from, np_into)
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
def make_collision(solid_from, solid_into): node_from = CollisionNode("from") node_from.add_solid(solid_from) node_into = CollisionNode("into") node_into.add_solid(solid_into) root = NodePath("root") trav = CollisionTraverser() queue = CollisionHandlerQueue() np_from = root.attach_new_node(node_from) np_into = root.attach_new_node(node_into) trav.add_collider(np_from, queue) trav.traverse(root) entry = None for e in queue.get_entries(): if e.get_into() == solid_into: entry = e return (entry, np_from, np_into)
class MousePicker(object): def __init__(self, pickTag="MyPickingTag", nodeName="pickRay", showCollisions=False): self.pickTag = pickTag self.nodeName = nodeName self.showCollisions = showCollisions def create(self): self.mPickerTraverser = CollisionTraverser() self.mCollisionQue = CollisionHandlerQueue() self.mPickRay = CollisionRay() self.mPickRay.setOrigin(base.camera.getPos(base.render)) self.mPickRay.setDirection(base.render.getRelativeVector(base.camera, Vec3(0, 1, 0))) # create our collison Node to hold the ray self.mPickNode = CollisionNode(self.nodeName) self.mPickNode.addSolid(self.mPickRay) # Attach that node to the camera since the ray will need to be positioned # relative to it, returns a new nodepath # well use the default geometry mask # this is inefficent but its for mouse picking only self.mPickNP = base.camera.attachNewNode(self.mPickNode) # we'll use what panda calls the "from" node. This is reall a silly convention # but from nodes are nodes that are active, while into nodes are usually passive environments # this isnt a hard rule, but following it usually reduces processing # Everything to be picked will use bit 1. This way if we were doing other # collision we could seperate it, we use bitmasks to determine what we check other objects against # if they dont have a bitmask for bit 1 well skip them! self.mPickNode.setFromCollideMask(BitMask32(1)) # Register the ray as something that can cause collisions self.mPickerTraverser.addCollider(self.mPickNP, self.mCollisionQue) # Setup 2D picker self.mPickerTraverser2D = CollisionTraverser() self.mCollisionQue2D = CollisionHandlerQueue() self.mPickNode2D = CollisionNode("2D PickNode") self.mPickNode2D.setFromCollideMask(BitMask32(1)) self.mPickNode2D.setIntoCollideMask(BitMask32.allOff()) self.mPick2DNP = base.camera2d.attachNewNode(self.mPickNode2D) self.mPickRay2D = CollisionRay() self.mPickNode2D.addSolid(self.mPickRay2D) self.mPickerTraverser2D.addCollider(self.mPick2DNP, self.mCollisionQue2D) if self.showCollisions: self.mPickerTraverser.showCollisions(base.render) self.mPickerTraverser2D.showCollisions(base.aspect2d) def mousePick(self, traverse=None, tag=None): # do we have a mouse if base.mouseWatcherNode.hasMouse() == False: return None, None traverse = traverse or base.render tag = tag or self.pickTag mpos = base.mouseWatcherNode.getMouse() # Set the position of the ray based on the mouse position self.mPickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.mPickerTraverser.traverse(traverse) if self.mCollisionQue.getNumEntries() > 0: self.mCollisionQue.sortEntries() for entry in self.mCollisionQue.getEntries(): pickedObj = entry.getIntoNodePath() pickedObj = pickedObj.findNetTag(tag) if not pickedObj.isEmpty(): pos = entry.getSurfacePoint(base.render) return pickedObj, pos return None, None def mousePick2D(self, traverse=None, tag=None, all=False): # do we have a mouse if base.mouseWatcherNode.hasMouse() == False: return None, None traverse = traverse or base.render tag = tag or self.pickTag mpos = base.mouseWatcherNode.getMouse() self.mPickRay2D.setFromLens(base.cam2d.node(), mpos.getX(), mpos.getY()) self.mPickerTraverser2D.traverse(base.aspect2d) if self.mCollisionQue2D.getNumEntries() > 0: self.mCollisionQue2D.sortEntries() if all: return ( [ (entry.getIntoNodePath().findNetTag(tag), entry.getSurfacePoint(base.aspect2d)) for entry in self.mCollisionQue2D.getEntries() ], None, ) else: entry = self.mCollisionQue2D.getEntry(0) pickedObj = entry.getIntoNodePath() pickedObj = pickedObj.findNetTag(tag) if not pickedObj.isEmpty(): pos = entry.getSurfacePoint(base.aspect2d) return pickedObj, pos return None, None
class 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 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 = NORMAL self.NAVIGATION_MODE = TERRAIN self.mode_initialized = False self.loadWorld() ######### Camera ######### self.disableMouse() self.mainCamera = Camera(self.camera) self.mainCamera.camObject.setHpr(0, 0, 0) ######### 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 loadWorld(self, level=1): ########## Terrain ######### 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 ######### self.avatarActor = Actor("models/panda", {"walk": "models/panda-walk"}) self.avatarActor.setScale(.5, .5, .5) self.avatarActor.setHpr(180, 0, 0) self.avatarActor.setPythonTag("moving", False) self.avatarActor.setCollideMask(BitMask32.allOff()) ######### 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 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 == NORMAL: render.clearFog() elif newGameMode == MAIN_MENU: print "bubbles!" 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(NORMAL)), 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: 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 == NORMAL: 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 #Handle keyboard input self.avatar.handleKeys(self.keys) self.avatar.move(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 < 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 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 yaw_shift = -((mouse_shift_x) * Camera.ROT_RATE[0]) pitch_shift = -((mouse_shift_y) * Camera.ROT_RATE[1]) self.avatar.yawRot += yaw_shift self.mainCamera.pitchRot += pitch_shift if self.mainCamera.pitchRot > Camera.MAX_PITCH_ROT: self.mainCamera.pitchRot = Camera.MAX_PITCH_ROT elif self.mainCamera.pitchRot < Camera.MIN_PITCH_ROT: self.mainCamera.pitchRot = Camera.MIN_PITCH_ROT self.avatar.objectNP.setH(self.avatar.yawRot) self.mainCamera.camObject.setH(self.avatar.yawRot) self.mainCamera.camObject.setP(self.mainCamera.pitchRot) if self.NAVIGATION_MODE == TERRAIN: xy_plane_cam_dist = Camera.AVATAR_DIST cam_z_adjust = Camera.ELEVATION elif self.NAVIGATION_MODE == SPACE: xy_plane_cam_dist = Camera.AVATAR_DIST*cos(radians(self.pitchRot)) cam_z_adjust = Camera.AVATAR_DIST*sin(radians(self.pitchRot)) cam_x_adjust = xy_plane_cam_dist*sin(radians(self.avatar.yawRot)) cam_y_adjust = xy_plane_cam_dist*cos(radians(self.avatar.yawRot)) 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) return Task.cont
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 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 Raycaster(Entity): 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) self._pickerNP.show() def distance(self, a, b): return math.sqrt(sum((a - b)**2 for a, b in zip(a, b))) def raycast(self, origin, direction=(0, 0, 1), distance=math.inf, traverse_target=scene, ignore=list(), debug=False): self.position = origin self.look_at(self.position + direction) self._pickerNode.clearSolids() # if thickness == (0,0): if distance == math.inf: ray = CollisionRay() ray.setOrigin(Vec3(0, 0, 0)) ray.setDirection(Vec3(0, 1, 0)) else: ray = CollisionSegment(Vec3(0, 0, 0), Vec3(0, distance, 0)) self._pickerNode.addSolid(ray) if debug: self._pickerNP.show() else: self._pickerNP.hide() self._picker.traverse(traverse_target) if self._pq.get_num_entries() == 0: self.hit = Hit(hit=False) 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 ] if len(self.entries) == 0: self.hit = Hit(hit=False) return self.hit self.collision = self.entries[0] nP = self.collision.get_into_node_path().parent point = self.collision.get_surface_point(nP) point = Vec3(point[0], point[2], point[1]) world_point = self.collision.get_surface_point(render) world_point = Vec3(world_point[0], world_point[2], world_point[1]) hit_dist = self.distance(self.world_position, world_point) if nP.name.endswith('.egg'): nP = nP.parent self.hit = Hit(hit=True) for e in scene.entities: if e == nP: # print('cast nP to Entity') self.hit.entity = e self.hit.point = point self.hit.world_point = world_point self.hit.distance = hit_dist normal = self.collision.get_surface_normal( self.collision.get_into_node_path().parent) self.hit.normal = (normal[0], normal[2], normal[1]) normal = self.collision.get_surface_normal(render) self.hit.world_normal = (normal[0], normal[2], normal[1]) return self.hit self.hit = Hit(hit=False) return self.hit def boxcast(self, origin, direction=(0, 0, 1), distance=math.inf, thickness=(1, 1), traverse_target=scene, ignore=list(), debug=False): if isinstance(thickness, (int, float, complex)): thickness = (thickness, thickness) resolution = 3 rays = list() debugs = list() for y in range(3): for x in range(3): pos = origin + Vec3( lerp(-(thickness[0] / 2), thickness[0] / 2, x / (3 - 1)), lerp(-(thickness[1] / 2), thickness[1] / 2, y / (3 - 1)), 0) ray = self.raycast(pos, direction, distance, traverse_target, ignore, False) rays.append(ray) if debug and ray.hit: d = Entity(model='cube', origin_z=-.5, position=pos, scale=(.02, .02, distance), ignore=True) d.look_at(pos + Vec3(direction)) debugs.append(d) # print(pos, hit.point) if ray.hit and ray.distance > 0: d.scale_z = ray.distance d.color = color.green from ursina import destroy # [destroy(e, 1/60) for e in debugs] rays.sort(key=lambda x: x.distance) closest = rays[0] return Hit( hit=sum([int(e.hit) for e in rays]) > 0, entity=closest.entity, point=closest.point, world_point=closest.world_point, distance=closest.distance, normal=closest.normal, world_normal=closest.world_normal, hits=[e.hit for e in rays], entities=list(set([e.entity for e in rays])), # get unique entities hit )
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 World(ShowBase): def skyBoxLoad(self): self.spaceSkyBox = load_model('skybox1.egg') self.spaceSkyBox.setScale(150) self.spaceSkyBox.setLightOff() self.spaceSkyBox.reparentTo(render) self.spaceSkyBox.setPos(0,0,-200) self.spaceSkyBox.setHpr(0,0,0) def loadEnviron(self): self.environ = load_model("secondWorld.egg") self.environ.reparentTo(render) self.environ.setPos(0,0,0) def Hooh(self): """ hooh """ self.hoohActor = Actor("anim2hooh.egg", {"wing":"anim-Anim0.egg"}) self.hoohActor.reparentTo(render) self.hoohActor.loop("wing") self.hoohActor.setPos(self.ralphStartPos[0], self.ralphStartPos[1]+100, self.ralphStartPos[2]+100) self.hoohActor.setPlayRate(4.0,"wing") self.hoohActor.setHpr(180,90,0) start = Point3(self.ralphStartPos[0], self.ralphStartPos[1]+95, self.ralphStartPos[2]+100) end = Point3(self.ralphStartPos[0], self.ralphStartPos[1]-100, self.ralphStartPos[2]+100) turnHpr1 = Point3(180,90,0) turnHpr2 = Point3(0,90,0) hoohPosInt1 = self.hoohActor.posInterval(5.0, start, startPos = end) hoohPosInt2 = self.hoohActor.posInterval(5.0, end, startPos = start) hoohHprInt1 = self.hoohActor.hprInterval(1.0, turnHpr2, startHpr=turnHpr1) hoohHprInt2 = self.hoohActor.hprInterval(1.0, turnHpr1, startHpr=turnHpr2) self.hoohFly = Sequence(hoohPosInt1, hoohHprInt1, hoohPosInt2, hoohHprInt2, name="hoohFly") self.hoohFly.loop() def gold(self, task): _GOLD_PARTICLES.setPos(self.hoohActor.getPos()) return task.cont def loadPokemon(self): """ Pikachu """ self.pikachu = load_model("pikachu.egg") self.pikachu.reparentTo(render) self.pikachu.setPos(_PIKACHU_POS) self.pikachu.setHpr(_PIKACHU_HPR) """ Groudon """ self.Groudon = load_model("Groudon.egg") self.Groudon.reparentTo(render) self.Groudon.setPos(_GROUDON_POS) self.Groudon.setHpr(_GROUDON_HPR) """ Bulbasaur """ self.bulbasaur = load_model("bulbasaur.egg") self.bulbasaur.reparentTo(render) self.bulbasaur.setPos(_BULBASAUR_POS) self.bulbasaur.setHpr(_BULBASAUR_HPR) """ hooh """ self.Hooh() """ Pichu """ self.pichu = load_model("pichu.egg") self.pichu.reparentTo(render) self.pichu.setPos(_PICHU_POS) self.pichu.setHpr(_PICHU_HPR) """ Charmander """ self.charmander = load_model("char.egg") self.charmander.reparentTo(render) self.charmander.setPos(_CHARMANDER_POS) self.charmander.setHpr(_CHARMANDER_HPR) """ charizard """ self.charizard = load_model("charizard.egg") self.charizard.reparentTo(render) self.charizard.setPos(_CHARIZARD_POS) self.charizard.setHpr(_CHARIZARD_HPR) """ blastoise """ self.blastoise = load_model("blastoise.egg") self.blastoise.reparentTo(render) self.blastoise.setPos(_BLASTOISE_POS) self.blastoise.setHpr(_BLASTOISE_HPR) """ Squirtle """ self.squirtle = load_model("squirtle.egg") self.squirtle.reparentTo(render) self.squirtle.setPos(_SQUIRTLE_POS) self.squirtle.setHpr(_SQUIRTLE_HPR) """ Dragonite """ self.dragonite = load_model("dragonite.egg") self.dragonite.reparentTo(render) self.dragonite.setPos(_DRAGONITE_POS) self.dragonite.setHpr(_DRAGONITE_HPR) _FLAME.setPos(_FLAME_POS) _FLAME.setScale(0.1) _FLAME.start(parent=render, renderParent=render) """ venusaur """ self.venusaur = load_model("venusaur.egg") self.venusaur.reparentTo(render) self.venusaur.setPos(_VENUSAUR_POS) self.venusaur.setHpr(_VENUSAUR_HPR) def loadRalph(self): # Create the main character, Ralph basePath = r"../google_drive/ball/data/models/" self.ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor(basePath+"ralph",{"run":basePath+"ralph-run", "walk":basePath+"ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(self.ralphStartPos) self.ralph.hide() def loadNextMusic(self, task): # random load background music if (self.music.status()!=self.music.PLAYING): # not playing self.musicCounter += 1 index = self.musicCounter % len(_BGMUSIC) self.music = load_bgmusic(_BGMUSIC[index]) self.music.play() return task.cont def keyControl(self): self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left",1]) self.accept("arrow_right", self.setKey, ["right",1]) self.accept("arrow_up", self.setKey, ["forward",1]) self.accept("arrow_left-up", self.setKey, ["left",0]) self.accept("arrow_right-up", self.setKey, ["right",0]) self.accept("arrow_up-up", self.setKey, ["forward",0]) self.accept("w",self.setKey,["upward",1]) self.accept("w-up",self.setKey,["upward",0]) self.accept("s",self.setKey,["downward",1]) self.accept("s-up",self.setKey,["downward",0]) self.accept("t", self.toggleMusic) self.accept("u", self.changeVolume, ['u']) self.accept("d", self.changeVolume, ['d']) self.accept("h", self.hideInstructions) def changeVolume(self, direction): if direction == 'u' and self.volume < 1: self.volume += 0.05 else: # direction == 'd' if self.volume > 0: self.volume -= 0.05 self.music.setVolume(self.volume) def toggleMusic(self): self.music.stop() self.musicCounter += 1 # increment the counter by index = self.musicCounter % len(_BGMUSIC) self.music = load_bgmusic(_BGMUSIC[index]) self.music.play() def displayInformation(self): self.title = addTitle("My Pokemon - Roam Mode") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[Arrow Keys]: Move") self.inst3 = addInstructions(0.85, "[w]: look up") self.inst4 = addInstructions(0.80, "[s]: look down") self.inst5 = addInstructions(0.75, "[t]: toggle next song") self.inst6 = addInstructions(0.70, "[u]: volume up") self.inst7 = addInstructions(0.65, "[d]: volume down") self.inst8 = addInstructions(0.60, "[h]: hide/show instructions") self.insts = [self.title, self.inst1, self.inst2, self.inst3, self.inst4, self.inst5, self.inst6, self.inst7, self.inst8] def hideInstructions(self): if self.instStatus == "show": self.instStatus = "hide" groupHide(self.insts) else: # instructions are hidden self.instStatus = "show" groupShow(self.insts) def __init__(self): base.enableParticles() self.keyMap = {"left":0, "right":0, "forward":0,"backward":0, "upward":0, "downward":0, "leftward":0,"rightward":0, "cam-left":0, "cam-right":0} _GOLD_PARTICLES.start(parent=render, renderParent=render) _GOLD_PARTICLES.setScale(200) self.instStatus = "show" self.musicCounter = 0 self.music = load_bgmusic(_BGMUSIC[0]) # self.music.play() self.volume = 0 self.music.setVolume(self.volume) base.win.setClearColor(Vec4(0,0,0,1)) self.above = 3.0 # load environment self.loadEnviron() # load ralph self.loadRalph() # load sky box self.skyBoxLoad() # load pokemon self.loadPokemon() self.displayInformation() self.keyControl() # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) taskMgr.add(self.move,"moveTask") taskMgr.add(self.setAbove,"setAbove") taskMgr.add(self.loadNextMusic, "loadRandomMusic") taskMgr.add(self.gold, "gold") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(),self.ralph.getY(),2) self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0,0,1000) self.ralphGroundRay.setDirection(0,0,-1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,1000) self.camGroundRay.setDirection(0,0,-1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays #self.ralphGroundColNp.show() #self.camGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring #self.cTrav.showCollisions(render) # Create some lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(-5, -5, -5)) directionalLight.setColor(Vec4(1, 1, 1, 1)) directionalLight.setSpecularColor(Vec4(1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) def setAbove(self,task): if self.keyMap["upward"] == 1: self.above += 0.1 if self.keyMap["downward"] == 1: self.above -= 0.1 return task.cont #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if (self.keyMap["left"]!=0): self.ralph.setH(self.ralph.getH() + 113 * globalClock.getDt()) base.camera.setX(base.camera, +20 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.ralph.setH(self.ralph.getH() - 113 * globalClock.getDt()) base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.ralph.setY(self.ralph, -75 * globalClock.getDt()) if (self.keyMap["backward"] != 0): pass #self.ralph.setY(self.ralph, 75 * globalClock.getDt()) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):# or (self.keyMap["backward"]!=0): if self.isMoving is False: #self.ralph.loop("run") self.isMoving = True else: if self.isMoving: #self.ralph.stop() #self.ralph.pose("walk",5) self.isMoving = False # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. camvec = self.ralph.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 10.0): base.camera.setPos(base.camera.getPos() + camvec*(camdist-10)) camdist = 10.0 if (camdist < 5.0): base.camera.setPos(base.camera.getPos() - camvec*(5-camdist)) camdist = 5.0 # Now check for collisions. self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.ralph.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.0) # The camera should look in ralph's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above ralph's head. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + self.above)#self.above) base.camera.lookAt(self.floater) return task.cont
class World(DirectObject): 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 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 RaceDrone(ShowBase): def __init__(self): ShowBase.__init__(self) # initalize the window base.disableMouse() self.win.setClearColor((0, 0, 0, 1)) props = WindowProperties() props.setCursorHidden(True) props.setSize(1700,1000) base.win.requestProperties(props) # store keys self.keyMap = { "left": 0, "right": 0, "forward": 0, "backward": 0, "drift-left": 0, "drift-right": 0, "up": 0, "down": 0, "restart": 0, "firstPerson": 0, "gravity": 0} #instructions self.ins2 = addInstructions(0.12, "[Left/Right Arrow]: Rotate Left/Right") self.ins3 = addInstructions(0.18, "[Up/Down Arrow]: Fly Forward/Backward") self.ins4 = addInstructions(0.24, "[A, D]: Move Camera") self.ins5 = addInstructions(0.30, "[W, S]: Lift / Descent") self.ins6 = addInstructions(0.36, "[F]: Toggle First Person/ Third Person") self.ins7 = addInstructions(0.42, "[G]: Toggle Gravity") self.ins8 = addInstructions(0.48, "[R]: Restart") # Set up the playground # other maps: # models/toon/phase_15/hood/toontown_central.bam # models/world # CS_Map/myCSMAP.egg # Race/RaceTrack/FullTrack.blend self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) self.mapScale = 1 """ self.environ = loader.loadModel("The City/The City.obj") self.environ.reparentTo(render) myTexture = loader.loadTexture("The City/Maps/cty1.jpg") self.environ.setTexture(myTexture) self.environ.setHpr(0,90,0) self.environ.setScale(.1) """ # Create drone and initalize drone position self.Drone = Actor("models/mydrone.egg") self.Drone.reparentTo(render) # resize and reposition the drone self.Drone.setScale(.1) self.Drone.setPos(5,5,8) self.Drone.setH(180) # initial position is saved for restarting the game self.DroneStartPos = self.Drone.getPos() # User Controls self.accept('escape', __import__('sys').exit, [0]) 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("a", self.setKey, ["drift-left", True]) self.accept("d", self.setKey, ["drift-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("arrow_down-up", self.setKey, ["backward", False]) self.accept("a-up", self.setKey, ["drift-left", False]) self.accept("d-up", self.setKey, ["drift-right", False]) self.accept("w", self.setKey, ["up", True]) self.accept("w-up", self.setKey, ["up", False]) self.accept("s", self.setKey, ["down", True]) self.accept("s-up", self.setKey, ["down", False]) self.accept("r", self.setKey, ["restart", True]) self.accept("r-up", self.setKey, ["restart", False]) self.accept("f", self.setKey, ["firstPerson", True]) self.accept("f-up", self.setKey, ["firstPerson", False]) self.accept("g", self.setKey, ["gravity", True]) self.accept("g-up", self.setKey, ["gravity", False]) taskMgr.add(self.move, "moveTask") # Disable Mouse self.disableMouse() # Camera settings self.cameraDistance = 5 self.cameraPitch = -10 # create the collision box for the drone # this collision box will be used for collision detection self.droneBox = CollisionBox((0,0,2.5), 3, 3, 0.7) self.cnodePath = self.Drone.attachNewNode(CollisionNode('cnode')) self.cnodePath.node().addSolid(self.droneBox) # collision detection set up self.cTrav = CollisionTraverser() self.queue = CollisionHandlerQueue() self.cTrav.addCollider(self.cnodePath, self.queue) self.cTrav.traverse(render) # Lighting portion are modified from an example provided by Panda3d – Roaming Ralph ambientLight = AmbientLight("ambientLight") ambientLight.setColor((1, 1, 1, 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)) # Crashed Text self.crashed = OnscreenText() self.firstPerson = False # HPR setting self.angle = 0 self.angleChange = 0.5 self.maxAngle = 15 # Speed Control self.FBSpeed = self.mapScale * 6 self.LRSpeed = self.mapScale * 4 self.turnSpeed = 80 self.liftSpeed = self.mapScale * 80 self.downSpeed = self.mapScale * 80 # AI set up self.AI = True if self.AI: self.droneAI = Actor("models/mydrone.egg") self.droneAI.reparentTo(render) self.droneAI.setScale(.1) self.droneAI.setPos(5,5,5) self.AI_actions = open("AI/RoamingRalph/AI_easy.txt", "r").readlines() ####################### # additional features # ####################### # acceleration self.FBacceleration = 0 self.LRacceleration = 0 self.accelMax = 40 self.accelIncrement = 2 # gravity self.gravity = True self.gravity_value = 15 * self.mapScale # Record user inputs def setKey(self, key, value): self.keyMap[key] = value # Main Function (Deal with user interface and collision detection) def move(self, task): #debug #print(self.queue.getEntries()) #print(self.drone.getPos()) #print(self.FBacceleration, self.LRacceleration) # crash message self.crashed.destroy() self.crashed = OnscreenText(text="Crashed!!!" if len(self.queue.getEntries()) != 0 else "", pos = (-0.5, 0.02), scale = 0.07, mayChange = True, fg = (255,255,255,1)) # Get the time that elapsed since last frame. dt = globalClock.getDt() # control the movement of AI if self.AI: if self.AI_actions != []: curAction = self.AI_actions[0].split(" ") self.droneAI.setX(float(curAction[0])) self.droneAI.setY(float(curAction[1])) self.droneAI.setZ(float(curAction[2])) self.droneAI.setH(float(curAction[3])) self.droneAI.setP(float(curAction[4])) self.droneAI.setR(float(curAction[5])) self.AI_actions.pop(0) # Drone is movable only when it's not crashed if len(self.queue.getEntries()) == 0: # initial height curHeight = self.Drone.getZ() # move by acceleration if self.FBacceleration != 0: self.Drone.setX(self.Drone, self.FBSpeed * self.FBacceleration * dt) self.FBacceleration += 1 if self.FBacceleration < 0 else -1 if self.LRacceleration != 0: self.Drone.setY(self.Drone, self.LRSpeed * self.LRacceleration * dt) self.LRacceleration += 1 if self.LRacceleration < 0 else -1 self.Drone.setZ(curHeight) # tilting while drift left and right if self.keyMap["drift-left"]: #self.Drone.setY(self.Drone, self.LRSpeed * dt) # tilt left when drift left if self. angle > -self.maxAngle: self.angle -= self.angleChange self.Drone.setP(self.angle) if self.LRacceleration < self.accelMax: self.LRacceleration += self.accelIncrement elif self.keyMap["drift-right"]: #self.Drone.setY(self.Drone, -self.LRSpeed * dt) # tilt right when drift right if self. angle < self.maxAngle: self.angle += self.angleChange self.Drone.setP(self.angle) if self.LRacceleration > -self.accelMax: self.LRacceleration -= self.accelIncrement # gradually stablize itself while drift-keys are not pressed else: if self.angle >=self.angleChange: self.angle -= self.angleChange elif self.angle <=-self.angleChange: self.angle +=self.angleChange self.Drone.setP(self.angle) # turn left if self.keyMap["left"]: self.Drone.setH(self.Drone.getH() + self.turnSpeed * dt) # turn right if self.keyMap["right"]: self.Drone.setH(self.Drone.getH() - self.turnSpeed * dt) # go forward if self.keyMap["forward"]: #self.Drone.setX(self.Drone, self.FBSpeed * dt) if self.FBacceleration < self.accelMax: self.FBacceleration += self.accelIncrement elif self.keyMap["backward"]: #self.Drone.setX(self.Drone, -self.FBSpeed * dt) if self.FBacceleration > -self.accelMax: self.FBacceleration -= self.accelIncrement # lift up if self.keyMap["up"]: self.Drone.setZ(self.Drone, self.liftSpeed * dt) # go down if self.keyMap["down"]: self.Drone.setZ(self.Drone, -self.downSpeed * dt) # gravity if self.gravity: self.Drone.setZ(self.Drone, -self.gravity_value * dt) # restart game / reset position if self.keyMap["restart"]: self.Drone.setPos(self.DroneStartPos + (0, 0, 5)) self.collisionCount = False self.crashed.destroy() self.Drone.setH(180) # First Person View / Third Person View Toggle if self.keyMap["firstPerson"]: self.firstPerson = not self.firstPerson # Gravity Toggle if self.keyMap["gravity"]: self.gravity = not self.gravity # uncomment the following code to see the collision box ######################## #self.cnodePath.show() # ######################## # set the position and HPR of the camera according to the position of the drone # First Person View if self.firstPerson: base.camera.setH(self.Drone.getH()-90) base.camera.setP(self.Drone.getR()) base.camera.setR(self.Drone.getP()) base.camera.setPos(self.Drone.getPos()) # Third Person View else: base.camera.setHpr(self.Drone.getHpr()+(180,0,0)) h,p,r = self.Drone.getHpr() base.camera.setPos(self.Drone.getPos() + (math.cos(math.pi * h / 180) * -self.cameraDistance, \ math.sin(math.pi * h / 180) * -self.cameraDistance, 0.5)) viewTarget = Point3(self.Drone.getPos() + (0,0,0)) # the look-at point can be changed base.camera.lookAt(viewTarget) return task.cont
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 Player(DirectObject): def __init__(self, _main): self.main = _main # Stats self.moveSpeed = 8 self.inventory = [] self.maxCarryWeight = 20.0 #kg ? self.currentInventoryWeight = 0.0 # Inventory GUI self.inventoryGui = Inventory() self.inventoryGui.hide() self.inventoryActive = False self.craftInventory = CraftInventory() self.craftInventory.hide() # enable movements through the level self.keyMap = {"left":0, "right":0, "forward":0, "backward":0} self.player = NodePath("Player")#loader.loadModel("smiley") self.player.setPos(149.032, 329.324, 11.3384) self.player.setH(180) self.player.reparentTo(render) self.accept("w", self.setKey, ["forward",1]) self.accept("w-up", self.setKey, ["forward",0]) self.accept("a", self.setKey, ["left",1]) self.accept("a-up", self.setKey, ["left",0]) self.accept("s", self.setKey, ["backward",1]) self.accept("s-up", self.setKey, ["backward",0]) self.accept("d", self.setKey, ["right",1]) self.accept("d-up", self.setKey, ["right",0]) self.accept("mouse1", self.handleLeftMouse) self.accept("i", self.toggleInventory) self.accept("c", self.toggleCraftInventory) # screen sizes self.winXhalf = base.win.getXSize() / 2 self.winYhalf = base.win.getYSize() / 2 self.mouseSpeedX = 0.1 self.mouseSpeedY = 0.1 camera.setH(180) camera.reparentTo(self.player) camera.setZ(self.player, 2) base.camLens.setFov(75) base.camLens.setNear(0.8) # Mouse controls self.mouseNode = CollisionNode('mouseRay') self.mouseNodeNP = camera.attachNewNode(self.mouseNode) self.mouseNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.mouseRay = CollisionRay() self.mouseNode.addSolid(self.mouseRay) self.mouseRayHandler = CollisionHandlerQueue() # Collision Traverser self.traverser = CollisionTraverser("Player Traverser") base.cTrav = self.traverser self.traverser.addCollider(self.mouseNodeNP, self.mouseRayHandler) def run(self): taskMgr.add(self.move, "moveTask", priority=-4) def pause(self): taskMgr.remove("moveTask") def setKey(self, key, value): self.keyMap[key] = value def move(self, task): if not base.mouseWatcherNode.hasMouse(): return task.cont pointer = base.win.getPointer(0) mouseX = pointer.getX() mouseY = pointer.getY() if base.win.movePointer(0, self.winXhalf, self.winYhalf): # calculate the looking up/down of the camera. # NOTE: for first person shooter, the camera here can be replaced # with a controlable joint of the player model p = camera.getP() - (mouseY - self.winYhalf) * self.mouseSpeedY if p <-80: p = -80 elif p > 90: p = 90 camera.setP(p) # rotate the player's heading according to the mouse x-axis movement h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX if h <-360: h = 360 elif h > 360: h = -360 self.player.setH(h) # basic movement of the player if self.keyMap["left"] != 0: self.player.setX(self.player, self.moveSpeed * globalClock.getDt()) if self.keyMap["right"] != 0: self.player.setX(self.player, -self.moveSpeed * globalClock.getDt()) if self.keyMap["forward"] != 0: self.player.setY(self.player, -self.moveSpeed * globalClock.getDt()) if self.keyMap["backward"] != 0: self.player.setY(self.player, self.moveSpeed * globalClock.getDt()) # keep the player on the ground elevation = self.main.t.terrain.getElevation(self.player.getX(), self.player.getY()) self.player.setZ(elevation*self.main.t.zScale) return task.cont def toggleInventory(self): if self.inventoryActive: self.inventoryGui.hide() self.inventoryActive = False self.run() else: self.inventoryGui.show() self.inventoryActive = True self.pause() def toggleCraftInventory(self): if self.inventoryActive: self.craftInventory.hide() self.inventoryActive = False self.run() else: self.craftInventory.updateList(self.inventory) self.craftInventory.show() self.inventoryActive = True self.pause() def handleLeftMouse(self): # Do the mining if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.mouseRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(render) # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue. if self.mouseRayHandler.getNumEntries() > 0: # This is so we get the closest object. self.mouseRayHandler.sortEntries() pickedObj = self.mouseRayHandler.getEntry(0).getIntoNodePath() # Range check if (self.player.getPos() - pickedObj.getPos(render)).length() <= 3.0: self.mine(pickedObj) else: print "You are to far, move closer!" def mine(self, _nodeNP): self.nodeNP = _nodeNP # get the object class for node in self.main.nodeGen.currentNodes: if self.main.nodeGen.currentNodes[node] in self.inventory: print "new Loot:", self.main.nodeGen.currentNodes[node].giveLoot() self.inventory.append(self.main.nodeGen.currentNodes[node]) if self.main.nodeGen.currentNodes[node].lootLeft == 0: self.main.nodeGen.currentNodes[node].removeModel() break break # if mining node else: if self.main.nodeGen.currentNodes[node].model and self.main.nodeGen.currentNodes[node].model.getPos() == self.nodeNP.getPos(render): #self.main.nodeGen.currentNodes[node].removeModel() self.inventory.append(self.main.nodeGen.currentNodes[node]) self.currentInventoryWeight += self.main.nodeGen.currentNodes[node].weight self.inventoryGui.updateList(self.inventory) print "You received:", self.main.nodeGen.currentNodes[node].giveLoot(), self.main.nodeGen.currentNodes[node].giveType(), "Ores" print "Inventory:", self.inventory print "Current Weight:", self.currentInventoryWeight break print self.player.getPos()
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 RoamingDroneDemo(ShowBase): def __init__(self): ShowBase.__init__(self) # initalize the window base.disableMouse() self.win.setClearColor((0, 0, 0, 1)) props = WindowProperties() props.setCursorHidden(True) props.setSize(1700,1000) base.win.requestProperties(props) # store keys self.keyMap = { "left": 0, "right": 0, "forward": 0, "drift-left": 0, "drift-right": 0, "up": 0, "down": 0, "restart": 0, "firstPerson": 0} #instructions self.instruction2 = addInstructions(0.12, "[Left Arrow]: Rotate Left") self.instruction3 = addInstructions(0.18, "[Right Arrow]: Rotate Right") self.instruction4 = addInstructions(0.24, "[Up Arrow]: Fly Forward") self.instruction5 = addInstructions(0.30, "[A, D]: Move Camera") self.instruction6 = addInstructions(0.36, "[W, S]: Fly Lift/ Descent") self.instruction7 = addInstructions(0.42, "[F]: Toggle First Person/ Third Person") self.instruction8 = addInstructions(0.48, "[R]: Restart") # Set up the playground # models/toon/phase_15/hood/toontown_central.bam # models/world # CS_Map/myCSMAP.egg self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) # Create drone and initalize drone position self.Drone = Actor("models/mydrone.egg") self.Drone.reparentTo(render) # resize and reposition the drone self.Drone.setScale(.1) self.Drone.setPos(5,5,5) # initial position is saved for restarting the game self.DroneStartPos = self.Drone.getPos() # User Controls self.accept('escape', __import__('sys').exit, [0]) 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, ["drift-left", True]) self.accept("d", self.setKey, ["drift-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, ["drift-left", False]) self.accept("d-up", self.setKey, ["drift-right", False]) self.accept("w", self.setKey, ["up", True]) self.accept("w-up", self.setKey, ["up", False]) self.accept("s", self.setKey, ["down", True]) self.accept("s-up", self.setKey, ["down", False]) self.accept("r", self.setKey, ["restart", True]) self.accept("r-up", self.setKey, ["restart", False]) self.accept("f", self.setKey, ["firstPerson", True]) self.accept("f-up", self.setKey, ["firstPerson", False]) taskMgr.add(self.move, "moveTask") # Disable Mouse self.disableMouse() # Camera settings self.cameraDistance = 5 self.cameraPitch = -10 # create the collision box for the drone # this collision box will be used for collision detection self.droneBox = CollisionBox((0,0,2.5), 3, 3, 0.7) self.cnodePath = self.Drone.attachNewNode(CollisionNode('cnode')) self.cnodePath.node().addSolid(self.droneBox) # collision detection set up self.cTrav = CollisionTraverser() self.queue = CollisionHandlerQueue() self.cTrav.addCollider(self.cnodePath, self.queue) self.cTrav.traverse(render) ################################## #self.cTrav.showCollisions(render) #self.DroneGroundColNp.show() #self.camGroundColNp.show() ################################## # Lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor((1, 1, 1, 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)) # Crashed Text self.crashed = OnscreenText() self.firstPerson = False # HPR setting self.angle = 0 self.angleChange = 0.8 self.maxAngle = 20 # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Deal with user interface and collision detection def move(self, task): self.crashed.destroy() self.crashed = OnscreenText(text="Crashed!!!" if len(self.queue.getEntries()) != 0 else "", pos = (-0.5, 0.02), scale = 0.07, mayChange = True, fg = (255,255,255,1)) # Get the time that elapsed since last frame. dt = globalClock.getDt() # Drone is movable only when it's not crashed if len(self.queue.getEntries()) == 0: # tilting while drift left and right if self.keyMap["drift-left"]: self.Drone.setY(self.Drone, 40 * dt) # tilt left when drift left if self. angle > -self.maxAngle: self.angle -= self.angleChange self.Drone.setP(self.angle) elif self.keyMap["drift-right"]: self.Drone.setY(self.Drone, -40 * dt) # tilt right when drift right if self. angle < self.maxAngle: self.angle += self.angleChange self.Drone.setP(self.angle) # gradually stablize itself while drift-keys are not pressed else: if self.angle >=self.angleChange: self.angle -= self.angleChange elif self.angle <=-self.angleChange: self.angle +=self.angleChange self.Drone.setP(self.angle) # turn left if self.keyMap["left"]: self.Drone.setH(self.Drone.getH() + 150 * dt) # turn right if self.keyMap["right"]: self.Drone.setH(self.Drone.getH() - 150 * dt) # go forward if self.keyMap["forward"]: self.Drone.setX(self.Drone, 200 * dt) # lift up if self.keyMap["up"]: self.Drone.setZ(self.Drone, 40 * dt) # go down if self.keyMap["down"]: self.Drone.setZ(self.Drone, -80 * dt) # restart game / reset position if self.keyMap["restart"]: self.Drone.setPos(self.DroneStartPos + (0, 0, 5)) self.collisionCount = False self.crashed.destroy() if self.keyMap["firstPerson"]: self.firstPerson = not self.firstPerson ###################### #self.cnodePath.show() ###################### # set the position and HPR of the camera according to the position of the drone if self.firstPerson: base.camera.setH(self.Drone.getH()-90) base.camera.setP(self.Drone.getR()) base.camera.setR(self.Drone.getP()) base.camera.setPos(self.Drone.getPos()) else: base.camera.setHpr(self.Drone.getHpr()+(180,0,0)) h,p,r = self.Drone.getHpr() base.camera.setPos(self.Drone.getPos() + (math.cos(math.pi * h / 180) * -self.cameraDistance, \ math.sin(math.pi * h / 180) * -self.cameraDistance, 0.5)) viewTarget = Point3(self.Drone.getPos() + (0,0,0)) base.camera.lookAt(viewTarget) #print(self.camera.getPos()) return task.cont
class World(DirectObject): mySound = base.loader.loadSfx("trial.mp3") #Used for adding a virus at a randomly generated position def random_vgen(self): print 'I am in random' for i in range(0,5): self.a[random.randint(0,7)][random.randint(0,7)] = 1 def initializer(self,level): self.turns = 0 ## Level Definition def levelone(): self.a[4][4] = 1 self.a[4][5] = 1 self.a[4][6] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[4][6] = 1 self.a[5][5] = 1 def leveltwo(): self.a[4][3] = 1 self.a[4][5] = 1 self.a[4][7] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[2][2] = 1 self.a[5][3] = 1 self.a[1][2] = 1 def levelthree(): self.a[4][4] = 1 self.a[4][5] = 1 self.a[4][6] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[4][6] = 1 self.a[5][5] = 1 self.a[4][3] = 1 self.a[4][5] = 1 self.a[4][7] = 1 self.a[5][2] = 1 self.a[3][5] = 1 self.a[2][2] = 1 self.a[5][3] = 1 options = {1: levelone, 2: leveltwo, 3: levelthree } options[level]() print self.a temp = [] count = 0 for element in reversed(self.a): for ele in element: #print 'cheking element is 1 : ' + str(ele) if ele == 1: temp.append(count) self.pieces[count] = Monster(count,WHITE) #self.squares[count].setColor(HIGHLIGHT) count = count + 1 self.list=temp def showscore(self): try: self.score.destroy() except: pass self.score = OnscreenText(text = 'Number of Turns : %s'%(self.turns), pos = (0.5, 0.95), scale = 0.07, mayChange = True) def menuscreen(self): # Callback function to set text def setText(): b.destroy() helptext.destroy() # Add button b = DirectButton(text = ("START", "START", "START", "disabled"), scale=0.15, command=setText, pos=(0,0,0.85)) helptext = OnscreenText(text =''' STORY: Hello Mad Scientist! You are so close to finding the cure to aids! You understood the behaviour and can finally manipulate the virus to kill itself! But time is running out! You have a red and white blood cell sample infected with AIDS Virus. INSTRUCTIONS: The AIDS Virus obeys the Conway's Game of Life. Who would have guessed? 1. If virus is surrounded by more than 3 viruses, it dies of suffocation 2. If virus is surrounded by less than 2 viruses, it dies of underpopulation 3. If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned due to breeding. AIM: To kill all the viruses, by moving one of them every turn. ''', pos = (-0.90,0.72),frame = (123,123,123,1), wordwrap = 25, align = TextNode.ALeft, bg = (0.23,0.243,0.13,0.9)) def endscreen(self): def restart(): taskMgr.remove(self.mouseTask) for i in range(64): self.squares[i].setColor(SquareColor(i)) scorecard.destroy() restartb.destroy() end.destroy() nextlevelb.destroy() self.reference.destroy() self.mySound.stop() try: self.score.destroy() except: pass print 'restarting' print self.a print self.list World() def quitgame(): sys.exit() def nextLevel(): self.currlevel = self.currlevel + 1 nextlevelb.destroy() scorecard.destroy() restartb.destroy() end.destroy() self.score.destroy() self.initializer(self.currlevel) # Add button scorecard = OnscreenText(text = 'You finished it in %s turns! '%(self.turns),frame = (123,123,123,0), wordwrap = 25, bg = (0.2,0,0.8,1)) nextlevelb = DirectButton(text = ("NEXT LEVEL", "NEXT LEVEL", "NEXT LEVEL", "disabled"), scale=0.15, command=nextLevel, pos=(0,0,-0.15)) restartb = DirectButton(text = ("RESTART", "RESTART", "RESTART", "disabled"), scale=0.15, command=restart, pos=(0,0,-0.35)) end = DirectButton(text = ("QUIT", "QUIT", "QUIT", "disabled"), scale=0.15, command=quitgame, pos=(0,0,-0.55)) if self.currlevel == self.maxlevel: nextlevelb.destroy() def __init__(self): #music self.mySound.play() print 'I am being initialized' self.menuscreen() self.list = [] self.turns = 0 self.maxlevel = 3 self.currlevel = 1 self.a =[[0 for x in range(8)] for y in range(8)] #This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Game of Life : Help in ending AIDS!", style=1, fg=(1,1,1,1), pos=(0,-0.95), scale = .07) self.escapeEvent = OnscreenText( text="ESC: Quit", style=1, fg=(1,1,1,1), pos=(-1.3, 0.95), align=TextNode.ALeft, scale = .05) ## self.mouse1Event = OnscreenText( ## text="Left-click and drag: Pick up virus and drag it to a new bloodcell", ## style=1, fg=(1,1,1,1), pos=(-1.3, 0.90), ## align=TextNode.ALeft, scale = .05) ## self.accept('escape', sys.exit) #Escape quits base.disableMouse() #Disble mouse camera control camera.setPosHpr(0, -13.75, 6, 0, -25, 0) #Set the camera self.setupLights() #Setup default lighting #Since we are using collision detection to do picking, we set it up like #any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() #Make a traverser self.pq = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') #Attach that node to the camera since the ray will need to be positioned #relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() #Make our ray self.pickerNode.addSolid(self.pickerRay) #Add it to the collision node #Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) #self.picker.showCollisions(render) #We will attach all of the squares to their own root. This way we can do the #collision pass just on the sqaures and save the time of checking the rest #of the scene self.squareRoot = render.attachNewNode("squareRoot") #For each square self.squares = [None for i in range(64)] self.pieces = [None for i in range(64)] for i in range(64): #Load, parent, color, and position the model (a single square polygon) self.squares[i] = loader.loadModel("models/square") self.squares[i].reparentTo(self.squareRoot) self.squares[i].setPos(SquarePos1(i)) self.squares[i].setColor(SquareColor(i)) #Set the model itself to be collideable with the ray. If this model was #any more complex than a single polygon, you should set up a collision #sphere around it instead. But for single polygons this works fine. self.squares[i].find("**/polygon").node().setIntoCollideMask( BitMask32.bit(1)) #Set a tag on the square's node so we can look up what square this is #later during the collision pass self.squares[i].find("**/polygon").node().setTag('square', str(i)) #We will use this variable as a pointer to whatever piece is currently #in this square self.initializer(self.currlevel) #This will represent the index of the currently highlited square self.hiSq = False #This wil represent the index of the square where currently dragged piece #was grabbed from self.dragging = False #Start the task that handles the picking self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') #self.trial = taskMgr.add(self.trial,'trial') self.accept("mouse1", self.grabPiece) #left-click grabs a piece self.accept("mouse1-up", self.releasePiece) #releasing places it #This function swaps the positions of two pieces def swapPieces(self, fr, to): temp = self.pieces[fr] self.pieces[fr] = self.pieces[to] self.pieces[to] = temp if self.pieces[fr]: print 'imma swapping' self.pieces[fr].square = fr print fr print SquarePos(fr) try: self.pieces[fr].obj.setPos(SquarePos(fr)) except: pass print 'done' if self.pieces[to]: self.pieces[to].square = to try: self.pieces[to].obj.setPos(SquarePos(to)) except: pass def trial(self): self.turns = self.turns + 1 try: self.reference.destroy() except: pass self.reference = OnscreenText( text=''' Reference: virus is surrounded by more than 3 viruses, it dies virus is surrounded by less than 2 viruses, it dies If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned. ''' , style=1, fg=(1,1,1,1), pos=(-1, 0.95), align=TextNode.ALeft, scale = .05) self.showscore() a = self.a while True: for i in self.list: #insert deletion code print 'imma deleting the sq : ' + str(i) self.pieces[i].obj.delete() self.squares[i].setColor(SquareColor(i)) count = 0 a=[[([[sum(b[y1][x1] for b in [[[((-1<x2+dx<len(a[0])) and (-1<y2+dy<len(a))) and a[y2+dy][x2+dx] or 0 for x2 in range(len(a[0]))] for y2 in range(len(a))] for (dx,dy) in [(dx,dy) for dx in [-1,0,1] for dy in [-1,0,1] if (dy!=0 or dx!=0)]]) for x1 in range(len(a[0]))] for y1 in range(len(a))][y][x]== 3 or ([[sum(c[y3][x3] for c in [[[((-1<x4+dx<len(a[0])) and (-1<y4+dy<len(a))) and a[y4+dy][x4+dx] or 0 for x4 in range(len(a[0]))] for y4 in range(len(a))] for (dx,dy) in [(dx,dy) for dx in [-1,0,1] for dy in [-1,0,1] if (dy!=0 or dx!=0)]]) for x3 in range(len(a[0]))] for y3 in range(len(a))][y][x] == 2 and a[y][x]==1)) and 1 or 0 for x in range(len(a[0]))] for y in range(len(a))] lis = [] #insert a random virus at a probability of 1/5 diceroll = random.randint(0,5) if diceroll == 2: self.random_vgen() for element in reversed(a): for ele in element: #print 'cheking element is 1 : ' + str(ele) if ele == 1: lis.append(count) count = count + 1 print lis self.list = lis self.a = a print self.list for i in self.list: self.pieces[i] = Monster(i,WHITE) #self.squares[i].setColor(HIGHLIGHT) print 'leaving trial' if len(self.list)==0: self.endscreen() break return def mouseTask(self, task): #This task deals with the highlighting and dragging based on the mouse #First, clear the current highlight if self.hiSq is not False: self.squares[self.hiSq].setColor(SquareColor(self.hiSq)) self.hiSq = False #Check to see if we can access the mouse. We need it to do anything else if base.mouseWatcherNode.hasMouse(): #get the mouse position mpos = base.mouseWatcherNode.getMouse() #Set the position of the ray based on the mouse position self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) #If we are dragging something, set the position of the object #to be at the appropriate point over the plane of the board if self.dragging is not False: #Gets the point described by pickerRay.getOrigin(), which is relative to #camera, relative instead to render nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin()) #Same thing with the direction of the ray nearVec = render.getRelativeVector(camera, self.pickerRay.getDirection()) try: self.pieces[self.dragging].obj.setPos(PointAtZ(.5, nearPoint, nearVec)) except: pass #Do the actual collision pass (Do it only on the squares for #efficiency purposes) self.picker.traverse(self.squareRoot) if self.pq.getNumEntries() > 0: #if we have hit something, sort the hits so that the closest #is first, and highlight that node self.pq.sortEntries() i = int(self.pq.getEntry(0).getIntoNode().getTag('square')) #Set the highlight on the picked square self.squares[i].setColor(HIGHLIGHT) self.hiSq = i #print 'selected is ' + str(i) return Task.cont def grabPiece(self): #If a square is highlighted and it has a piece, set it to dragging mode if (self.hiSq is not False and self.pieces[self.hiSq]): self.dragging = self.hiSq self.hiSq = False def releasePiece(self): #Letting go of a piece. If we are not on a square, return it to its original #position. Otherwise, swap it with the piece in the new square if self.dragging is not False: #Make sure we really are dragging something #We have let go of the piece, but we are not on a square if self.hiSq is False: try: self.pieces[self.dragging].obj.setPos(SquarePos(self.dragging)) except: pass else: #Otherwise, swap the pieces self.swapPieces(self.dragging, self.hiSq) #self.draggin is the from print self.list print 'you picked this, so Imma deleting this ' + str(self.dragging) #deletion of i after picking it up. try: self.list.remove(self.dragging) except: pass temp2 = [] temp2 = SquarePosTuple(self.dragging) self.a[temp2[0]][temp2[1]] = 0 i = self.hiSq print self.list print 'highlighted sq is ' + str(i) templis = [] templis = SquarePosTuple(i) print templis self.list.append(i) print self.list print templis self.a[templis[0]][templis[1]] = 1 for line in self.a: print line self.trial() #We are no longer dragging anything self.dragging = False def setupLights(self): #This function sets up some default lighting ambientLight = AmbientLight( "ambientLight" ) ambientLight.setColor( Vec4(.8, .8, .8, 1) ) directionalLight = DirectionalLight( "directionalLight" ) directionalLight.setDirection( Vec3( 0, 45, -45 ) ) directionalLight.setColor( Vec4( 0.2, 0.2, 0.2, 1 ) ) render.setLight(render.attachNewNode( directionalLight ) ) render.setLight(render.attachNewNode( ambientLight ) )
class World(DirectObject): def __init__(self): #This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Panda3D: Tutorial - Mouse Picking", style=1, fg=(1, 1, 1, 1), pos=(0.8, -0.95), scale=.07) self.escapeEvent = OnscreenText( text="ESC: Quit", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.95), align=TextNode.ALeft, scale=.05) self.mouse1Event = OnscreenText( text="Left-click and drag: Pick up and drag piece", style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.90), align=TextNode.ALeft, scale=.05) self.accept('escape', sys.exit) #Escape quits base.disableMouse() #Disble mouse camera control camera.setPosHpr(0, -13.75, 6, 0, -25, 0) #Set the camera self.setupLights() #Setup default lighting #Since we are using collision detection to do picking, we set it up like #any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() #Make a traverser self.pq = CollisionHandlerQueue() #Make a handler #Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') #Attach that node to the camera since the ray will need to be positioned #relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) #Everything to be picked will use bit 1. This way if we were doing other #collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() #Make our ray self.pickerNode.addSolid(self.pickerRay) #Add it to the collision node #Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) #self.picker.showCollisions(render) #Now we create the chess board and its pieces #We will attach all of the squares to their own root. This way we can do the #collision pass just on the sqaures and save the time of checking the rest #of the scene self.squareRoot = render.attachNewNode("squareRoot") #For each square self.squares = [None for i in range(64)] self.pieces = 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 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 p3dApp(ShowBase): def __init__(self): ShowBase.__init__(self); # setup the environment or model self.model = \ self.loader.loadModel("/Developer/Panda3D/models/box.egg.pz"); self.model.reparentTo(self.render); self.model.setTag('Model', '1'); self.model.setScale(1.5, 1.5, 1.5); # setup camera self.camera.setPos(5,5,5) self.camera.lookAt(0,0,0) # Disable mouse control self.disableMouse(); # Handle mouse events. self.accept('mouse1', self.mouse_down); # convert image from opencv to panda3d texture # self.taskMgr.add(self.read_image_cv, "cvImageTask"); # Setup collision handler self.handler = CollisionHandlerQueue() self.traverser = CollisionTraverser('ColTraverser') self.traverser.traverse(self.model) self.ray = CollisionRay() pickerNode = CollisionNode('MouseRay') pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) pickerNP = self.camera.attachNewNode(pickerNode) pickerNode.addSolid(self.ray) self.traverser.addCollider(pickerNP, self.handler) self.load_shader(); self.first_frame_loaded = False; def read_image_cv(self): """ Pulls the next frame from the opencv part, and converts to a panda3d texture and display it on the screen. """ cvim = self.cvapp.pull_frame() w = cvim.shape[1]; h = cvim.shape[0]; cvim = cv2.flip(cvim, 0); self.im = Texture("cvIm"); self.im.setCompression(Texture.CMOff); self.im.setup2dTexture(w, h, Texture.TUnsignedByte, Texture.FLuminance); self.im.setRamImage(cvim); self.screen_im = OnscreenImage(parent=self.render2d, image=self.im, scale=(1, 1, 1), pos=(0, 0, 0)); self.cam2d.node().getDisplayRegion(0).setSort(-20); def load_shader(self): """ The function loads the vertex and fragment shader. It provides an example of sending the model-view-projection matrix to the shader program when it's calculated. """ self.shader = Shader.load(Shader.SL_GLSL, "vertex.glsl", "fragment.glsl"); self.model.set_shader(self.shader) self.model.set_shader_input("my_ModelViewProjectionMatrix", LMatrix4f()) def mouse_down(self): """ This function is called as a result of a mouse click. It gets the vertex that was clicked by the mouse. It sends the mouse position and the vertex position to the cv app. """ if (self.first_frame_loaded == False): self.first_frame_loaded = True self.read_image_cv() return; xPos = self.mouseWatcherNode.getMouseX() yPos = self.mouseWatcherNode.getMouseY() self.ray.setFromLens(self.camNode, xPos, yPos) self.traverser.traverse(self.model) self.handler.sortEntries() if (self.handler.getNumEntries() > 0): entry = self.handler.getEntry(0) # CollisionEntry vpos = entry.getSurfacePoint(self.model) res = self.cvapp.mouse_clicked(LPoint3f(xPos, yPos), vpos) if (res == 1): self.read_image_cv() def set_cv_app(self, cvapp): self.cvapp = cvapp;
class 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 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 HexGrid(object): def __init__(self, w, h, show): self.width = w self.height = h self.loader = show.loader self.root = show.render.attachNewNode("hexgrid_root") self.base_tile = 'hex' self.diameter = 20 self.inscribed = self.diameter * sqrt(3) / 2 self.nodes = None self.show = show # Since we are using collision detection to do picking, we set it up like # any other collision detection system with a traverser and a handler self.picker = CollisionTraverser() # Make a traverser self.picker_queue = CollisionHandlerQueue() # Make a handler # Make a collision node for our picker ray self.pickerNode = CollisionNode('mouseRay') # Attach that node to the camera since the ray will need to be positioned # relative to it self.pickerNP = show.camera.attachNewNode(self.pickerNode) # Everything to be picked will use bit 1. This way if we were doing other # collision we could seperate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() # Make our ray # Add it to the collision node self.pickerNode.addSolid(self.pickerRay) # Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.picker_queue) self.assemble() self.onclick_fn = None # self.mouseTask = self.taskMgr.add(self.mouseTask, 'mouseTask') # self.accept("mouse1", self.grabPiece) # left-click grabs a piece show.accept("mouse1-up", self.mouse_up) # releasing places it def mouse_up(self): # This task deals with the highlighting and dragging based on the mouse # Check to see if we can access the mouse. We need it to do anything # else if self.onclick_fn and self.show.mouseWatcherNode.hasMouse(): # get the mouse position mpos = self.show.mouseWatcherNode.getMouse() # Set the position of the ray based on the mouse position self.pickerRay.setFromLens(self.show.camNode, mpos.getX(), mpos.getY()) # Do the actual collision pass self.picker.traverse(self.root) if self.picker_queue.getNumEntries() > 0: # if we have hit something, sort the hits so that the closest # is first, and highlight that node self.picker_queue.sortEntries() i = int(self.picker_queue.getEntry(0).getIntoNode().getTag('hexmesh_i')) self.onclick_fn(self.nodes[i]) return Task.cont def onclick(self, fn): self.onclick_fn = fn def index_of(self, x, y): return x + y * self.width def xyi_iter(self, fn): for x in range(self.height): for y in range(self.width): fn(x, y, self.index_of(x, y)) def node_iter(self, fn): for node in self.nodes: fn(node) def assemble(self): random.seed(3141592) def make_node(x, y, i): row_offset = self.inscribed / 2. if y % 2 == 0 else 0 pos = Point3(x * self.inscribed + row_offset, y * self.diameter * 0.75, 0) self.nodes[i] = HexNode(self.base_tile, pos, self.root, i) self.nodes = [None for _ in range(self.width * self.height)] self.xyi_iter(make_node)
class 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 World(ShowBase): def __init__(self): # Load the default configuration.prc. This is recommended, as it # contains some important panda options loadPrcFile("../../Config/configuration.prc") ShowBase.__init__(self) # Create a new pipeline instance self.renderPipeline = RenderingPipeline(self) # Set the base path for the pipeline. This is required as we are in # a subdirectory self.renderPipeline.getMountManager().setBasePath("../../") # Also set the write path self.renderPipeline.getMountManager().setWritePath("../../Temp/") # Load the default settings self.renderPipeline.loadSettings("../../Config/pipeline.ini") # Now create the pipeline self.renderPipeline.create() # Add a directional light dPos = Vec3(40, 40, 15) dirLight = DirectionalLight() dirLight.setPos(dPos * 1000000.0) dirLight.setShadowMapResolution(1024) dirLight.setCastsShadows(True) dirLight.setColor(Vec3(8)) self.renderPipeline.addLight(dirLight) self.renderPipeline.setScatteringSource(dirLight) self.dirLight = dirLight self.keyMap = { "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0} base.win.setClearColor(Vec4(0, 0, 0, 1)) # Post the instructions self.title = addTitle( "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left") self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right") self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward") self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left") self.inst7 = addInstructions(0.65, "[S]: Rotate Camera Right") # Set up the environment # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) self.environ.setPos(0, 0, 0) self.environ.find("**/wall").removeNode() # Create the main character, Ralph ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor("models/ralph", {"run": "models/ralph-run", "walk": "models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos) self.renderPipeline.setEffect(self.ralph, "Effects/Default/Default.effect", { "dynamic": True }) # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_up", self.setKey, ["forward", 1]) self.accept("a", self.setKey, ["cam-left", 1]) self.accept("s", self.setKey, ["cam-right", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_up-up", self.setKey, ["forward", 0]) self.accept("a-up", self.setKey, ["cam-left", 0]) self.accept("s-up", self.setKey, ["cam-right", 0]) # NOTICE: It is important that your update tasks have a lower priority # than -10000 taskMgr.add(self.move, "moveTask", priority=-20000) self.accept("r", self.reloadShader) # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 1.2) # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above ralph's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 1000) self.ralphGroundRay.setDirection(0, 0, -1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0, 0, 1000) self.camGroundRay.setDirection(0, 0, -1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays # self.ralphGroundColNp.show() # self.camGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring # self.cTrav.showCollisions(render) # Create some ocean self.water = ProjectedWaterGrid(self.renderPipeline) self.water.setWaterLevel(-4.0) # Create the skybox self.skybox = self.renderPipeline.getDefaultSkybox() self.skybox.reparentTo(render) self.prepareSRGB(render) self.reloadShader() self.renderPipeline.onSceneInitialized() # Add demo slider to move the sun position if self.renderPipeline.settings.displayOnscreenDebugger: self.renderPipeline.guiManager.demoSlider.node[ "command"] = self.setSunPos self.renderPipeline.guiManager.demoSlider.node[ "value"] = 50 def setSunPos(self): rawValue = self.renderPipeline.guiManager.demoSlider.node["value"] dPos = Vec3(100, 100, rawValue - 20) self.dirLight.setPos(dPos * 100000000.0) def reloadShader(self): self.renderPipeline.reloadShaders() # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value def prepareSRGB(self, np): """ Sets the correct texture format for all textures found in <np> """ for tex in np.findAllTextures(): baseFormat = tex.getFormat() if baseFormat == Texture.FRgb: tex.setFormat(Texture.FSrgb) elif baseFormat == Texture.FRgba: tex.setFormat(Texture.FSrgbAlpha) else: print "Unkown texture format:", baseFormat print "\tTexture:", tex # tex.setMinfilter(Texture.FTLinearMipmapLinear) # tex.setMagfilter(Texture.FTLinear) tex.setAnisotropicDegree(16) # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. base.camera.lookAt(self.ralph) if (self.keyMap["cam-left"] != 0): base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["cam-right"] != 0): base.camera.setX(base.camera, +20 * globalClock.getDt()) # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if (self.keyMap["left"] != 0): self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt()) if (self.keyMap["right"] != 0): self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt()) if (self.keyMap["forward"] != 0): self.ralph.setY(self.ralph, -25 * globalClock.getDt()) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0) or (self.keyMap["right"] != 0): if self.isMoving is False: self.ralph.loop("run") self.isMoving = True else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. camvec = self.ralph.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 7.0): base.camera.setPos(base.camera.getPos() + camvec * (camdist - 7)) camdist = 7.0 if (camdist < 5.0): base.camera.setPos(base.camera.getPos() - camvec * (5 - camdist)) camdist = 5.0 # Now check for collisions. self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"): self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.ralph.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0) if (base.camera.getZ() < self.ralph.getZ() + 2.5): base.camera.setZ(self.ralph.getZ() + 2.5) # The camera should look in ralph's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above ralph's head. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + 2.0) base.camera.lookAt(self.floater) return task.cont
class World(DirectObject): def __init__(self): self.keyMap = {"left":0, "right":0, "forward":0, "back":0, "cam-left":0, "cam-right":0} self.flag1=0 self.flag2=0 self.flag3=0 self.flag4=0 self.count=0 self.health = 100 self.points = -5 self.flagd=1 self.player_points = 0 base.win.setClearColor(Vec4(0,0,0,1)) self.mySound=base.loader.loadSfx("sounds/trial.mp3") self.mySound.play() self.title = addTitle("Bumping Cars") #Full Screen props = WindowProperties.getDefault() w=base.pipe.getDisplayWidth() h=base.pipe.getDisplayHeight() props.setSize(w,h) props.setFullscreen(True) props.setCursorHidden(True) base.win.requestProperties(props) # Load World self.environ = loader.loadModel("models/world.egg") self.environ.reparentTo(render) self.environ.setPos(0,0,0) #Load Sky self.sky = loader.loadModel("models/clouds.egg") self.sky.reparentTo(render) self.sky.setPos(60,0,-450) # Create Player Car carStartPos = self.environ.find("**/start_point").getPos() self.car = Actor("models/carnsx") self.car.reparentTo(render) self.car.setScale(0.25) #self.car.place() self.car.setPos(carStartPos) # Create Enemy Car 1 enemyCarStartPos1 = (-108,-1,-.5) self.car1 = Actor("models/enemy_cars/monstercar/carmonster") self.car1.reparentTo(render) self.car1.setScale(0.25) #self.car1.place() self.car1.setPos(enemyCarStartPos1) # Create Enemy Car 2 enemyCarStartPos2 = (-104,-26,-.02) self.car2 = Actor("models/enemy_cars/yugo/yugo") self.car2.reparentTo(render) self.car2.setScale(0.15) #self.car2.place() self.car2.setPos(enemyCarStartPos2) # Create Enemy Car 3 enemyCarStartPos3 = (-111,-26,0) self.car3 = Actor("models/enemy_cars/truck/cartruck") self.car3.reparentTo(render) self.car3.setScale(0.25) #self.car3.place() self.car3.setPos(enemyCarStartPos3) # Create Enemy Car 4 enemyCarStartPos4 = (-111,-2,-.5) self.car4 = Actor("models/enemy_cars/truck/cartruck-purple") self.car4.reparentTo(render) self.car4.setScale(0.25) #self.car4.place() self.car4.setPos(enemyCarStartPos4) # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("a", self.setKey, ["cam-left",1]) self.accept("s", self.setKey, ["cam-right",1]) self.accept("arrow_up",self.setKey, ["forward",1]) self.accept("arrow_left",self.setKey, ["left",1]) self.accept("arrow_down",self.setKey, ["back",1]) self.accept("arrow_right",self.setKey, ["right",1]) self.accept("a-up", self.setKey, ["cam-left",0]) self.accept("s-up", self.setKey, ["cam-right",0]) self.accept("arrow_up-up",self.setKey, ["forward",0]) self.accept("arrow_left-up",self.setKey, ["left",0]) self.accept("arrow_right-up",self.setKey, ["right",0]) self.accept("arrow_down-up",self.setKey, ["back",0]) taskMgr.add(self.move,"moveTask") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.car.getX(),self.car.getY()+10,2) # 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)) # AI self.AIworld = AIWorld(render) # AI Car 1 self.AIchar1 = AICharacter("car1",self.car1, 70, 0.1, 3) self.AIworld.addAiChar(self.AIchar1) self.AIbehaviors1 = self.AIchar1.getAiBehaviors() self.AIbehaviors1.pursue(self.car) # AI Car 2 self.AIchar2 = AICharacter("car2",self.car2, 180, 0.1, 1) self.AIworld.addAiChar(self.AIchar2) self.AIbehaviors2 = self.AIchar2.getAiBehaviors() self.AIbehaviors2.pursue(self.car4) # AI Car 3 self.AIchar3 = AICharacter("car3",self.car3, 70, 0.1, 3) self.AIworld.addAiChar(self.AIchar3) self.AIbehaviors3 = self.AIchar3.getAiBehaviors() self.AIbehaviors3.pursue(self.car) # AI Car 4 self.AIchar4 = AICharacter("car4",self.car4, 200, 0.5, 2) self.AIworld.addAiChar(self.AIchar4) self.AIbehaviors4 = self.AIchar4.getAiBehaviors() self.AIbehaviors4.pursue(self.car3) # Obstacle avoidance self.AIbehaviors1.obstacleAvoidance(1.0) self.AIworld.addObstacle(self.car2) self.AIworld.addObstacle(self.car3) self.AIworld.addObstacle(self.car4) self.AIbehaviors2.obstacleAvoidance(1.0) self.AIbehaviors3.obstacleAvoidance(1.0) self.AIbehaviors4.obstacleAvoidance(1.0) #AI World update taskMgr.add(self.AIUpdate,"AIUpdate") self.cTrav = CollisionTraverser() #self.cTrav.showCollisions(render) 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.carGroundColNp = self.car.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.carGroundColNp, self.ralphGroundHandler) #car1 self.car1Ray = CollisionSphere(0,0,0,4) self.car1GroundCol = CollisionNode('car1Ray') self.car1GroundCol.addSolid(self.car1Ray) self.car1GroundCol.setFromCollideMask(BitMask32.bit(0)) self.car1GroundCol.setIntoCollideMask(BitMask32.allOff()) self.car1GroundColNp = self.car.attachNewNode(self.car1GroundCol) self.car1GroundHandler = CollisionHandlerQueue() #self.car1GroundColNp.show() self.cTrav.addCollider(self.car1GroundColNp, self.car1GroundHandler) cnodePath = self.car1.attachNewNode(CollisionNode('cnode1')) cnodePath.node().addSolid(self.car1Ray) #cnodePath.show() #car2 self.car2Ray = CollisionSphere(0,0,0,4) self.car2GroundCol = CollisionNode('car2Ray') self.car2GroundCol.addSolid(self.car2Ray) self.car2GroundCol.setFromCollideMask(BitMask32.bit(0)) self.car2GroundCol.setIntoCollideMask(BitMask32.allOff()) self.car2GroundColNp = self.car.attachNewNode(self.car2GroundCol) self.car2GroundHandler = CollisionHandlerQueue() #self.car2GroundColNp.show() self.cTrav.addCollider(self.car2GroundColNp, self.car2GroundHandler) cnodePath = self.car2.attachNewNode(CollisionNode('cnode2')) cnodePath.node().addSolid(self.car2Ray) #cnodePath.show() #car3 self.car3Ray = CollisionSphere(0,0,0,4) self.car3GroundCol = CollisionNode('car3Ray') self.car3GroundCol.addSolid(self.car3Ray) self.car3GroundCol.setFromCollideMask(BitMask32.bit(0)) self.car3GroundCol.setIntoCollideMask(BitMask32.allOff()) self.car3GroundColNp = self.car.attachNewNode(self.car3GroundCol) self.car3GroundHandler = CollisionHandlerQueue() #self.car3GroundColNp.show() self.cTrav.addCollider(self.car3GroundColNp, self.car3GroundHandler) cnodePath = self.car3.attachNewNode(CollisionNode('cnode3')) cnodePath.node().addSolid(self.car3Ray) #cnodePath.show() #car4 self.car4Ray = CollisionSphere(0,0,0,4) self.car4GroundCol = CollisionNode('car4Ray') self.car4GroundCol.addSolid(self.car4Ray) self.car4GroundCol.setFromCollideMask(BitMask32.bit(0)) self.car4GroundCol.setIntoCollideMask(BitMask32.allOff()) self.car4GroundColNp = self.car.attachNewNode(self.car4GroundCol) self.car4GroundHandler = CollisionHandlerQueue() #self.car4GroundColNp.show() self.cTrav.addCollider(self.car4GroundColNp, self.car4GroundHandler) cnodePath = self.car4.attachNewNode(CollisionNode('cnode4')) cnodePath.node().addSolid(self.car4Ray) #cnodePath.show() #camera self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,1000) self.camGroundRay.setDirection(0,0,-1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) def onCollision(self, entry): print("123") def displayHealth(self): healthBar['scale'] = (self.health*0.01*BAR_WIDTH,0.2,0.2) #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value def makezero4(self,task): self.flag4=0 def makezero3(self,task): self.flag3=0 #to update the AIWorld def AIUpdate(self,task): self.AIworld.update() return task.cont def makezero1(self,task): self.flag1=0 def makezero2(self,task): self.flag2=0 def move(self, task): if (self.flagd==1): self.points = self.points + globalClock.getDt() self.player_points = int(self.points) printPointObj(self.player_points) #print int(self.points) base.camera.lookAt(self.car) 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 car's initial position so that we can restore it, # in case he falls off the map or runs into something. startposcar = self.car.getPos() # If a move-key is pressed, move the car in the specified direction. if (self.keyMap["left"]!=0): self.car.setH(self.car.getH() + 100 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.car.setH(self.car.getH() - 100 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.car.setY(self.car, -40 * globalClock.getDt()) if (self.keyMap["back"]!=0): self.car.setY(self.car, 40 * globalClock.getDt()) if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0) or (self.keyMap["back"]!=0): if self.isMoving is False: self.isMoving = True else: if self.isMoving: self.car.stop() self.isMoving = False # If the camera is too far from the car, move it closer. # If the camera is too close to the car, move it farther. camvec = self.car.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) 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.car.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.car.setPos(startposcar) entries=[] for i in range(self.car1GroundHandler.getNumEntries()): entry = self.car1GroundHandler.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() == "cnode1") and (self.flag1==0): #print "car1" self.flag1=1 self.health=self.health - 10 printHealthObj(self.health) print "car1" taskMgr.doMethodLater(5,self.makezero1,"flag1") entries=[] for i in range(self.car2GroundHandler.getNumEntries()): entry = self.car2GroundHandler.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() == "cnode2") and (self.flag2==0): #print "car2" self.flag2=1 self.health=self.health - 10 printHealthObj(self.health) print "car2" taskMgr.doMethodLater(5,self.makezero2,"flag2") entries=[] for i in range(self.car3GroundHandler.getNumEntries()): entry = self.car3GroundHandler.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() == "cnode3") and (self.flag3==0): #print "car3" self.flag3=1 self.health=self.health - 10 printHealthObj(self.health) print "car3" taskMgr.doMethodLater(5,self.makezero3,"flag3") entries=[] for i in range(self.car4GroundHandler.getNumEntries()): entry = self.car4GroundHandler.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() == "cnode4") and (self.flag4==0): #print "car4" self.flag4=1 self.health=self.health - 10 printHealthObj(self.health) print "car4" taskMgr.doMethodLater(5,self.makezero4,"flag4") 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.car.getZ() + 2.0): base.camera.setZ(self.car.getZ() + 2.0) if self.health <= 0: self.flagd=0 frame=DirectFrame(image=r"end.jpg",frameSize=(-3, 3, -3, 3)) textObject1 = OnscreenText(text = 'You Died!', pos = (0, 0.7), scale = 0.22) textObject2 = OnscreenText(text = 'Press ESC to Exit', pos = (0,0.9), scale=0.1) b = DirectButton(text="Exit Game",scale=0.1,command = sys.exit) textObject3 = OnscreenText(text = 'Your Score: ' + str(self.player_points), pos = (-0.2, -0.9), scale = 0.22) self.floater.setPos(self.car.getPos()) self.floater.setZ(self.car.getZ() + 2.0) base.camera.lookAt(self.floater) self.displayHealth() return task.cont
class Physics: def __init__(self): self.rayCTrav = CollisionTraverser("collision traverser for ray tests") #self.pusher = PhysicsCollisionHandler() self.pusher = CollisionHandlerPusher() self.pusher.addInPattern('%fn-in-%in') self.pusher.addOutPattern('%fn-out-%in') self.pusher.addInPattern('%fn-in') self.pusher.addOutPattern('%fn-out') def startPhysics(self): #self.actorNode = ActorNode("playerPhysicsControler") #base.physicsMgr.attachPhysicalNode(self.actorNode) #self.actorNode.getPhysicsObject().setMass(self.player_mass) #self.mainNode = render.attachNewNode(self.actorNode) self.mainNode = render.attachNewNode("CharacterColliders") self.reparentTo(self.mainNode) charCollisions = self.mainNode.attachNewNode(CollisionNode(self.char_collision_name)) #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0, self.player_height/4.0)) #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0*3.05, self.player_height/4.0)) charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/2.0, self.player_height/4.0)) charCollisions.node().setIntoCollideMask(BitMask32(0x80)) # 1000 0000 if self.show_collisions: charCollisions.show() self.pusher.addCollider(charCollisions, self.mainNode) base.cTrav.addCollider(charCollisions, self.pusher) charFFootCollisions = self.attachNewNode(CollisionNode("floor_ray")) charFFootCollisions.node().addSolid(CollisionRay(0, 0, 0.5, 0, 0, -1)) #charFFootCollisions.node().addSolid(CollisionSegment((0, 0, 0.2), (0, 0, -1))) charFFootCollisions.node().setIntoCollideMask(BitMask32.allOff()) charFFootCollisions.node().setFromCollideMask(BitMask32(0x7f)) # 0111 1111 if self.show_collisions: charFFootCollisions.show() self.floor_handler = CollisionHandlerFloor() self.floor_handler.addCollider(charFFootCollisions, self.mainNode) #self.floor_handler.setOffset(0) self.floor_handler.setMaxVelocity(5) base.cTrav.addCollider(charFFootCollisions, self.floor_handler) self.accept("{}-in".format(self.char_collision_name), self.checkCharCollisions) self.raytest_segment = CollisionSegment(0, 1) self.raytest_np = render.attachNewNode(CollisionNode("testRay")) self.raytest_np.node().addSolid(self.raytest_segment) self.raytest_np.node().setIntoCollideMask(BitMask32.allOff()) self.raytest_np.node().setFromCollideMask(BitMask32(0x7f)) # 0111 1111 if self.show_collisions: self.raytest_np.show() self.raytest_queue = CollisionHandlerQueue() self.rayCTrav.addCollider(self.raytest_np, self.raytest_queue) def stopPhysics(self): self.raytest_segment.removeNode() self.pusher.clearColliders() self.floor_handler.clearColliders() self.rayCTrav.clearColliders() def updatePlayerPos(self, speed, heading, dt): if heading is not None: self.mainNode.setH(camera, heading) self.mainNode.setP(0) self.mainNode.setR(0) self.mainNode.setFluidPos(self.mainNode, speed) self.doStep() def checkCharCollisions(self, args): self.doStep() def doStep(self): # do the step height check tmpNP = self.mainNode.attachNewNode("temporary") tmpNP.setPos(self.mainNode, 0, 0, -self.stepheight) pointA = self.mainNode.getPos(render) pointA.setZ(pointA.getZ() + self.player_height/1.8) pointB = tmpNP.getPos(render) if pointA == pointB: return char_step_collision = self.getFirstCollisionInLine(pointA, pointB) tmpNP.removeNode() if char_step_collision is not None: self.mainNode.setFluidZ(char_step_collision.getZ()) return True return False def getFirstCollisionInLine(self, pointA, pointB): """A simple raycast check which will return the first collision point as seen from point A towards pointB""" self.raytest_segment.setPointA(pointA) self.raytest_segment.setPointB(pointB) self.rayCTrav.traverse(render) self.raytest_queue.sortEntries() pos = None if self.raytest_queue.getNumEntries() > 0: pos = self.raytest_queue.getEntry(0).getSurfacePoint(render) return pos
class World(DirectObject): def __init__(self): #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 GamingCam(object,DirectObject): yshift,zshift=5,5 ymin,ymax=10,70 zmin,zmax=10,70 zoom_speed=.1 move_speed=.5 def __init__(self,gmap,gaming_zone): DirectObject.__init__(self) #gaming zone (used for mouse movement), as a tools.Rectangle self.gaming_zone=gaming_zone #actual camera node self.p3dcam=base.camera #what the cam is oriented to self._target=base.render.attachNewNode('GaminCam.target') #range=[0,1] between min and max closeness to ground self.level=.7 # #keys_down acts as a pool containing keys (+mouse buttons) currently down self.keys_down=[] update_list.append(self.update) #setup for mouse picking picker_node=CollisionNode('gcam_to_mouse_ray')#general collision node picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.picker_ray=CollisionRay()#solid ray to attach to coll node picker_node.addSolid(self.picker_ray) self.picker_np=self.p3dcam.attachNewNode(picker_node)#attach this node to gcam self.collision_queue=CollisionHandlerQueue()#stores collisions self.collision_traverser=CollisionTraverser('gcam_traverser')#actual computer self.collision_traverser.addCollider(self.picker_np,self.collision_queue) base.cTrav=self.collision_traverser self.gmap=gmap #stack of states (state=pos+zoom) self.states_stack=[] #enable the cam to move according to keyboard and mouse self.move_enabled=True def __del__(self): update_list.remove(self.update) self.ignoreAll() def center(self): self._target.setPos(0,0,0) def disable_move(self): self.move_enabled=False def enable_move(self): self.move_enabled=True def get_level(self): return self._level def get_picked_tile(self): ''' returns ''' if base.mouseWatcherNode.hasMouse(): #get the mouse position mpos = base.mouseWatcherNode.getMouse() #Set the position of the ray based on the mouse position # self.picker_ray.setFromLens(self.p3dcam.node().getLens(), mpos.getX(), mpos.getY()) self.picker_ray.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.collision_traverser.traverse(self.gmap.tile_matrix_node) if self.collision_queue.getNumEntries()>0: #useless since collision test is done against a single object self.collision_queue.sortEntries() entry=self.collision_queue.getEntry(0) x,y,_=entry.getSurfacePoint(self.gmap.tile_matrix_node) x=(x+self.gmap.resx)/2. y=(y+self.gmap.resy)/2. x=max(x,0) x=min(x,self.gmap.resx) y=max(y,0) y=min(y,self.gmap.resy) x=int(x) y=int(y) #out(pos=(x,y,z)) return self.gmap.tile_matrix[x][y] return None def get_picked_unit(self): if base.mouseWatcherNode.hasMouse(): #get the mouse position mpos = base.mouseWatcherNode.getMouse() #Set the position of the ray based on the mouse position # self.picker_ray.setFromLens(self.p3dcam.node().getLens(), mpos.getX(), mpos.getY()) self.picker_ray.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.collision_traverser.traverse(self.gmap.units_node) if self.collision_queue.getNumEntries()>0: #useless since collision test is done against a single object self.collision_queue.sortEntries() entry=self.collision_queue.getEntry(0) return entry.getIntoNodePath().findNetTag('GUnit-pickable') return None def get_target(self): return self._target def mouse_up(self,btn): if btn=='left': target=self.get_picked_tile() #out(target) #print NodePath(self.gmap.tile_matrix_node).ls() #print render.analyze() if target: network.serverproxy.send({network.cts_dbg_dump_entity:{'eid':target.eid}}) elif btn=='middle': self.set_level(.7) self.set_target(Vec3(0,-9,0)) def move(self,dx=0,dy=0): self._target.setPos(self._target,dx,dy,0) self.update_cam() def push_state(self): out('GCam.push_state()') pos,zoom=self._target.getPos(),self.level self.states_stack.append((pos,zoom)) def pop_state(self): out('GCam.pop_state()') pos,zoom=self.states_stack.pop(-1) self._target.setPos(*pos) self.level=zoom self.update_cam() def set_level(self,level): self._level=level self.update_cam() def set_target(self,target): ''' make the cam look at the given target. target can be a set of coordinates, or a node/nodepath. ''' if isinstance(target,PandaNode) or isinstance(target,NodePath): self._target.setPos(target,0,0,0) if isinstance(target,tuple): self._target.setPos(Vec3(*target)) else: self._target.setPos(target) self.update_cam() def start_accepting(self): ''' the gaming cam is created at gmap creation, so it has to wait until all data structures are created before accepting events. ''' self.accept(ConfigVariableString('key-cam-zoom-in').getValue()+'-up',self.zoom,extraArgs=[-GamingCam.zoom_speed]) self.accept(ConfigVariableString('key-cam-zoom-out').getValue()+'-up',self.zoom,extraArgs=[GamingCam.zoom_speed]) self.accept(ConfigVariableString('key-cam-right').getValue(),self.keys_down.append,extraArgs=['r']) self.accept(ConfigVariableString('key-cam-right').getValue()+'-up',self.keys_down.remove,extraArgs=['r']) self.accept(ConfigVariableString('key-cam-up').getValue(),self.keys_down.append,extraArgs=['u']) self.accept(ConfigVariableString('key-cam-up').getValue()+'-up',self.keys_down.remove,extraArgs=['u']) self.accept(ConfigVariableString('key-cam-left').getValue(),self.keys_down.append,extraArgs=['l']) self.accept(ConfigVariableString('key-cam-left').getValue()+'-up',self.keys_down.remove,extraArgs=['l']) self.accept(ConfigVariableString('key-cam-down').getValue(),self.keys_down.append,extraArgs=['d']) self.accept(ConfigVariableString('key-cam-down').getValue()+'-up',self.keys_down.remove,extraArgs=['d']) self.accept('mouse1-up',self.mouse_up,extraArgs=['left']) self.accept('mouse2-up',self.mouse_up,extraArgs=['middle']) def update(self): dx,dy=0,0 for k in self.keys_down: if k=='r':dx+=GamingCam.move_speed if k=='l':dx-=GamingCam.move_speed if k=='u':dy+=GamingCam.move_speed if k=='d':dy-=GamingCam.move_speed if k=='m': pass #dx+=mouse.getMouseX() #dy+=mouse.getMouseY() if self.move_enabled: self.move(dx,dy) def update_cam(self): self.p3dcam.setPos( self._target, 0, -(GamingCam.ymin+GamingCam.yshift+self._level*GamingCam.ymax), GamingCam.zmin+GamingCam.zshift+self._level*GamingCam.zmax ) self.p3dcam.lookAt(self._target) def zoom(self,delta): #TODO: smoothen the zoom with a task (interpolation) if 0<self._level+delta<1.: self.level+=delta level=property(get_level,set_level) target=property(get_target,set_target)
class World(DirectObject): def skyBoxLoad(self): self.spaceSkyBox = load_model('skybox1.egg') self.spaceSkyBox.setScale(150) self.spaceSkyBox.setLightOff() self.spaceSkyBox.reparentTo(render) self.spaceSkyBox.setPos(0,0,-200) self.spaceSkyBox.setHpr(0,0,0) def loadEnviron(self): self.environ = load_model("secondWorld.egg") self.environ.reparentTo(render) self.environ.setPos(0,0,0) def loadPokemon(self): self.pikachu = load_model("pikachu.egg") self.pikachu.reparentTo(render) self.pikachu.setScale(1) # self.pikachu.setPos(0,0,1) # self.pikachu.place() self.Groudon = load_model("Groudon.egg") self.Groudon.reparentTo(render) self.Groudon.setPos(-50,0,0) # self.Groudon.place() def loadRalph(self): # Create the main character, Ralph basePath = r"../google_drive/ball/data/models/" ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor(basePath+"ralph",{"run":basePath+"ralph-run", "walk":basePath+"ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos) self.ralph.hide() def loadMusic(self, name="palette.mp3"): bgmusic = load_bgmusic(name) bgmusic.play() def keyControl(self): self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left",1]) self.accept("arrow_right", self.setKey, ["right",1]) self.accept("arrow_up", self.setKey, ["forward",1]) self.accept("arrow_left-up", self.setKey, ["left",0]) self.accept("arrow_right-up", self.setKey, ["right",0]) self.accept("arrow_up-up", self.setKey, ["forward",0]) self.accept("w",self.setKey,["upward",1]) self.accept("w-up",self.setKey,["upward",0]) self.accept("s",self.setKey,["downward",1]) self.accept("s-up",self.setKey,["downward",0]) def displayInformation(self): self.title = addTitle("My Pokemon - Roam Mode") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[Arrow Keys]: Move") self.inst4 = addInstructions(0.85, "[w]: look up") self.inst4 = addInstructions(0.80, "[s]: look down") def __init__(self): self.keyMap = {"left":0, "right":0, "forward":0,"backward":0, "upward":0, "downward":0, "leftward":0,"rightward":0, "cam-left":0, "cam-right":0} # base.win.setClearColor(Vec4(0,0,0,1)) self.above = 3.0 # load sky box self.skyBoxLoad() # load environment self.loadEnviron() # load pokemon self.loadPokemon() # load ralph self.loadRalph() # load music self.loadMusic() self.displayInformation() self.keyControl() # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) taskMgr.add(self.move,"moveTask") taskMgr.add(self.setAbove,"setAbove") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(),self.ralph.getY(),2) self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0,0,1000) self.ralphGroundRay.setDirection(0,0,-1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,1000) self.camGroundRay.setDirection(0,0,-1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays #self.ralphGroundColNp.show() #self.camGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring #self.cTrav.showCollisions(render) # Create some lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(-5, -5, -5)) directionalLight.setColor(Vec4(1, 1, 1, 1)) directionalLight.setSpecularColor(Vec4(1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) def setAbove(self,task): if self.keyMap["upward"] == 1: self.above += 0.1 if self.keyMap["downward"] == 1: self.above -= 0.1 return task.cont #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if (self.keyMap["left"]!=0): self.ralph.setH(self.ralph.getH() + 113 * globalClock.getDt()) base.camera.setX(base.camera, +20 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.ralph.setH(self.ralph.getH() - 113 * globalClock.getDt()) base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.ralph.setY(self.ralph, -75 * globalClock.getDt()) if (self.keyMap["backward"] != 0): pass #self.ralph.setY(self.ralph, 75 * globalClock.getDt()) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):# or (self.keyMap["backward"]!=0): if self.isMoving is False: #self.ralph.loop("run") self.isMoving = True else: if self.isMoving: #self.ralph.stop() #self.ralph.pose("walk",5) self.isMoving = False # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. camvec = self.ralph.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 10.0): base.camera.setPos(base.camera.getPos() + camvec*(camdist-10)) camdist = 10.0 if (camdist < 5.0): base.camera.setPos(base.camera.getPos() - camvec*(5-camdist)) camdist = 5.0 # Now check for collisions. self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.ralph.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.0) # The camera should look in ralph's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above ralph's head. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + self.above)#self.above) base.camera.lookAt(self.floater) return task.cont
class World(DirectObject): def __init__(self): 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): 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 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 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 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 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 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 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 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 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 Cursor(DirectObject): """Cursor object for the UI.""" parent: NodePath mouse_np: NodePath actor: Actor last_position: Point moved: bool pointed_at: Optional[NodePath] def __init__(self, parent: NodePath): super().__init__() self.parent = parent self.mouse_np = p3d.camera.attach_new_node(PandaNode('mouse')) self.mouse_np.set_y(p3d.lens.get_near()) picker_node = CollisionNode('mouse_ray') picker_np = p3d.camera.attach_new_node(picker_node) self._picker_ray = CollisionRay() picker_node.add_solid(self._picker_ray) self._collision_handler = CollisionHandlerQueue() self._traverser = CollisionTraverser('mouse_traverser') self._traverser.add_collider(picker_np, self._collision_handler) self.actor = Actor( resource_filename('tsim', 'data/models/cursor'), {'spin': resource_filename('tsim', 'data/models/cursor-spin')}) self.actor.loop('spin') self.actor.reparent_to(parent) self.actor.set_pos(0.0, 0.0, 0.0) self.actor.set_shader_off() self._position = Point(0.0, 0.0) self.last_position = self._position self.moved = False self.pointed_at = None self._tool: Optional[Tool] = None self._register_events() @property def position(self) -> Point: """Get the cursor position.""" return self._position @position.setter def position(self, value: Union[Point, Iterable]): if not isinstance(value, Point): value = Point(*islice(value, 2)) self.actor.set_x(value.x) self.actor.set_y(value.y) self._position = value @property def tool(self) -> Optional[Tool]: """Get current tool.""" return self._tool @tool.setter def tool(self, value: Tool): if self._tool is not None: self._tool.cleanup() self.ignore_all() self._register_events() self._tool = value if value is not None: for key in INPUT.keys_for('tool_1'): self.accept(key, self._tool.on_button1_press) self.accept(f'{key}-up', self._tool.on_button1_release) for key in INPUT.keys_for('tool_2'): self.accept(key, self._tool.on_button2_press) self.accept(f'{key}-up', self._tool.on_button2_release) for key in INPUT.keys_for('tool_3'): self.accept(key, self._tool.on_button3_press) self.accept(f'{key}-up', self._tool.on_button3_release) self.accept('cursor_move', self._tool.on_cursor_move) def update(self): """Update callback.""" self.actor.set_scale(p3d.camera.get_z()**0.6 / 10) self.moved = False if p3d.mouse_watcher.has_mouse(): mouse_x, mouse_y = p3d.mouse_watcher.get_mouse() self._picker_ray.set_from_lens(p3d.cam_node, mouse_x, mouse_y) self._traverser.traverse(p3d.render) if self._collision_handler.get_num_entries(): self._collision_handler.sort_entries() node_path = ( self._collision_handler.get_entry(0).get_into_node_path()) self.position = node_path.get_pos(p3d.render) self.actor.set_z(2.0) self.pointed_at = node_path else: self.pointed_at = None film = p3d.lens.get_film_size() * 0.5 self.mouse_np.set_x(mouse_x * film.x) self.mouse_np.set_y(p3d.lens.get_focal_length()) self.mouse_np.set_z(mouse_y * film.y) self.last_position = self._position mouse_pos = self.mouse_np.get_pos(self.parent) cam_pos = p3d.camera.get_pos(self.parent) mouse_vec = mouse_pos - cam_pos if mouse_vec.z < 0.0: scale = -mouse_pos.z / mouse_vec.z self.actor.set_pos(mouse_pos + mouse_vec * scale) self.position = self.actor.get_pos() if self._position != self.last_position: self.moved = True p3d.messenger.send('cursor_move') if self._tool is not None: self._tool.on_update() def _on_simulation_step(self, dt: Duration): if self._tool is not None: self._tool.on_simulation_step(dt) def _register_events(self): def set_tool(tool: Type[Tool]): self.tool = tool(self) log.info('[%s] Changing tool to %s', __name__, tool.__name__) for tool in TOOLS: try: self.accept(tool.KEY, partial(set_tool, tool)) except AttributeError: log.warning('[%s] No KEY set for tool %s', __name__, tool.__name__) self.accept('simulation_step', self._on_simulation_step)