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 SmartCar(ShowBase): def __init__(self): ShowBase.__init__(self) # Override defaults self.disableMouse() self.setBackgroundColor(0.7, 0.7, 0.7) self.setFrameRateMeter(True) # Lights dlight = DirectionalLight("dlight") dlnp = self.render.attachNewNode(dlight) dlnp.setHpr(180.0, -70.0, 0) self.render.setLight(dlnp) alight = AmbientLight("alight") alnp = self.render.attachNewNode(alight) alight.setColor(VBase4(0.4, 0.4, 0.4, 1)) self.render.setLight(alnp) # Collisions self.cTrav = CollisionTraverser("collisionTraverser") self.cTrav.showCollisions(self.render) # Camera controls self.cameraController = CameraController(self, 200, math.pi / 4.0, math.pi / 4.0) #self.cameraController = CameraController(self, 200, -math.pi, math.pi / 4.0) # Load the track self.track = self.loader.loadModel("models/trackMotegi") self.track.reparentTo(self.render) # Load the car self.car = KeyboardController(self)
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 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 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 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 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
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 RoamingRalphDemo(ShowBase): def __init__(self): # Set up the window, camera, etc. ShowBase.__init__(self) self.orbCollisionHandler = CollisionHandlerQueue() self.cTrav = CollisionTraverser() #hbPath = NodePath() utils3.setUpKeys(self) utils3.loadModels(self) utils3.setUpLighting(self) utils3.setUpFloatingSpheres(self) utils3.setUpRalphsShot(self) utils3.setUpCamera(self) self.healthTxt = utils3.addInstructions(.06,"Health: 100") self.orbTxt = utils3.addInstructions(.18,"Orbs: 0") self.vec = LVector3(0,1,0)#vector for pawns shot # Create a frame #frame = DirectFrame(text = "main", scale = 0.001) # Add button #bar = DirectWaitBar(text = "", value = 50, pos = (0,.4,.4)) #bar.reparent(render) # Game state variables self.isMoving = False self.jumping = False self.vz = 0 self.numOrbs = 0 self.healthCount = 100 #self.shotList = [] taskMgr.add(self.move, "moveTask") #taskMgr.add(utils2.moveChris,"moveChrisTask") self.sphere = CollisionSphere(0,0,4,2) self.sphere2 = CollisionSphere(0,0,2,2) self.cnodePath = self.ralph.attachNewNode((CollisionNode('ralphColNode'))) self.cnodePath.node().addSolid(self.sphere) self.cnodePath.node().addSolid(self.sphere2) #self.cnodePath.show() self.pusher = CollisionHandlerPusher() self.pusher.addCollider(self.cnodePath, self.ralph) #self.cTrav.addCollider(self.cnodePath, self.ralphCollisionHandler) self.cTrav.addCollider(self.cnodePath, self.pusher) ca = CollisionSphere(0,0,0,20) cb = self.chik.attachNewNode(CollisionNode('chikCollisionNode')) cb.node().addSolid(ca) cb.show() cc = CollisionSphere(3,5,12,25) cd = self.gianteye.attachNewNode(CollisionNode('gianteyeCollisionNode')) cd.node().addSolid(cc) cd.show() ci = CollisionSphere(0,0,0,2) coi = self.catidol.attachNewNode(CollisionNode('catidolCollisionNode')) coi.node().addSolid(ci) coi.show() chi = CollisionSphere(-1,3,3,3) chco = self.chris.attachNewNode(CollisionNode('chrisColPath')) chco.node().addSolid(chi) self.cTrav.addCollider(chco, self.orbCollisionHandler) #chco.show() self.chris.setH(90) self.chris.setR(-90) self.chris.setZ(2) #cbox = CollisionBox((-50,30,20),10,85,20) #cboxPath = self.room.attachNewNode(CollisionNode('roomSide1')) #cboxPath.node().addSolid(cbox) #cboxPath.show() #cbox2 = CollisionBox((200,30,20),10,85,20) #cboxPath2 = self.room.attachNewNode(CollisionNode('roomSide1')) #cboxPath2.node().addSolid(cbox2) #cboxPath2.show() #cbox3 = CollisionBox((80,-60,20),120,20,20) #cboxPath3 = self.room.attachNewNode(CollisionNode('roomSide1')) #cboxPath3.node().addSolid(cbox3) #cboxPath3.show() ct = CollisionSphere(0,0,0,1) cn = self.pawn.attachNewNode(CollisionNode('pawnCollisionNode')) cn.node().addSolid(ct) cn.show() cs2 = CollisionSphere(0,0,0,.2) cs2path = self.plnp.attachNewNode((CollisionNode('orbColPath'))) cs2path.node().addSolid(cs2) cs2path.show() self.cTrav.addCollider(cs2path, self.orbCollisionHandler) #cs3 = CollisionSphere(0,0,0,1) cs3path = self.plnp2.attachNewNode((CollisionNode('orbColPath'))) cs3path.node().addSolid(cs2) cs3path.show() chrisShotNp = self.chrisShot.attachNewNode((CollisionNode("enemyOrbColPath"))) chrisShotNp.node().addSolid(cs2) chrisShotNp.show() self.cTrav.addCollider(cs3path, self.orbCollisionHandler) self.cTrav.addCollider(chrisShotNp, self.orbCollisionHandler) # Uncomment this line to show a visual representation of the # collisions occuring self.cTrav.showCollisions(render) self.chrisLastShotTime = globalClock.getFrameTime() self.chrisTimer = globalClock.getDt() # 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() utils3.moveChris(self,dt) # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. if self.keyMap["cam-left"]: self.camera.setZ(self.camera, -20 * dt) if self.keyMap["cam-right"]: self.camera.setZ(self.camera, +20 * dt) # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if self.keyMap["left"]: self.ralph.setH(self.ralph.getH() + 150 * dt) #self.camera.setX(self.camera, +15.5 * dt) if self.keyMap["right"]: self.ralph.setH(self.ralph.getH() - 150 * dt) #self.camera.setX(self.camera, -15.5 * dt) if self.keyMap["forward"]: self.ralph.setY(self.ralph, -35 * dt) #self.camera.setY(self.camera, -35 * dt) if self.keyMap["back"]: self.ralph.setY(self.ralph, +35 * dt) #self.camera.setY(self.camera, 35 * dt) if self.keyMap["c"]: if self.jumping is False: #self.ralph.setZ(self.ralph.getZ() + 100 * dt) self.jumping = True self.vz = 7 if self.keyMap["space"]: self.keyMap["space"] = False self.shotList[self.shotCount].lpivot.setPos(self.ralph.getPos()) self.shotList[self.shotCount].lpivot.setZ(self.ralph.getZ() + .5) self.shotList[self.shotCount].lpivot.setX(self.ralph.getX() - .25) #self.shotList.append(rShot) #self.lightpivot3.setPos(self.ralph.getPos()) #self.lightpivot3.setZ(self.ralph.getZ() + .5) #self.lightpivot3.setX(self.ralph.getX() - .25) #self.myShot.setHpr(self.ralph.getHpr()) #parent to ralph #node = NodePath("tmp") #node.setHpr(self.ralph.getHpr()) #vec = render.getRelativeVector(node,(0,-1,0)) #self.myShotVec = vec node = NodePath("tmp") node.setHpr(self.ralph.getHpr()) vec = render.getRelativeVector(node,(0,-1,0)) self.shotList[self.shotCount].vec = vec self.shotCount = (self.shotCount + 1) % 5 for rs in self.shotList: rs.lpivot.setPos(rs.lpivot.getPos() + rs.vec * dt * 15 ) #if shot is too far stop updating if self.jumping is True: self.vz = self.vz - 16* dt self.ralph.setZ(self.ralph.getZ() + self.vz * dt ) if self.ralph.getZ() < 0: self.ralph.setZ(0) self.jumping = False else: if self.ralph.getZ() < 0: self.ralph.setZ(0) elif self.ralph.getZ() > 0: self.ralph.setZ(self.ralph.getZ() -7 * dt) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"] or self.keyMap["c"] or self.keyMap["forward"] or self.keyMap["back"]: if self.isMoving is False: self.ralph.loop("run") self.isMoving = True else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False # update pawns shot or set up new shot after it reaches a certain distance node = NodePath("tmp") node.setHpr(self.pawn.getHpr()) vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0)) self.shot.setPos(self.shot.getPos() + self.vec * dt * 10 ) if self.shot.getY() < -15 or self.shot.getY() > 30 or self.shot.getX() < 5 or self.shot.getX() > 15: self.shot.setPos(self.pawn.getPos() + (0,0,0)) self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0)) self.vec = render.getRelativeVector(node,(random.random() * random.randrange(-1,2),random.random() + 1,0)) # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. #self.camera.lookAt(self.floater) camvec = self.ralph.getPos() - self.camera.getPos() #camvec = Vec3(0,camvec.getY(),0) camdist = camvec.length() x = self.camera.getZ() camvec.normalize() #if camdist > 6.0: # self.camera.setPos(self.camera.getPos() + camvec * (camdist - 6)) #if camdist < 6.0: # self.camera.setPos(self.camera.getPos() - camvec * (6 - camdist)) # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. #self.cTrav.traverse(render) # Adjust camera so it stays at same height if self.camera.getZ() < self.ralph.getZ() + 1 or self.camera.getZ() > self.ralph.getZ() + 1: self.camera.setZ(self.ralph.getZ() + 1) # The camera should look in ralph's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above ralph's head. self.camera.lookAt(self.floater) entries = list(self.orbCollisionHandler.getEntries()) if(len(entries) > 0): #self.lightpivot.reparentTo(NodePath()) for entry in self.orbCollisionHandler.getEntries(): #print(entry) fromColNp = entry.getFromNodePath() toColNp = entry.getIntoNodePath() if fromColNp.getName() == "orbColPath" and toColNp.getName() == "ralphColNode": fromColNp.getParent().reparentTo(NodePath()) self.orbTxt.destroy() self.numOrbs += 1 str1 = "Orbs: " + str(self.numOrbs) self.orbTxt = utils3.addInstructions(.18, str1) elif toColNp.getName() == "orbColPath" and fromColNp.getName() == "ralphColNode": toColNp.getParent().reparentTo(NodePath()) self.orbTxt.destroy() self.numOrbs += 1 str1 = "Orbs: " + str(self.numOrbs) self.orbTxt = utils3.addInstructions(.18, str1) elif toColNp.getName() == "ralphOrbColPath" and fromColNp.getName() == "chrisColPath": toColNp.getParent().setPos(-50,0,2) self.chrisHealth = self.chrisHealth - 1 self.chris.setColor(1,0,0,1) self.chrisHit = True self.chrisRedTime = globalClock.getFrameTime() #print self.chrisRedTime if self.chrisHealth < 0: fromColNp.getParent().removeNode() self.chrisAlive = False elif toColNp.getName() == "chrisColPath" and fromColNp.getName() == "ralphOrbColPath": fromColNp.getParent().setPos(-50,0,2) self.chrisHealth = self.chrisHealth - 1 self.chris.setColor(1,0,0,1) self.chrisHit = True self.chrisRedTime = globalClock.getFrameTime() #print self.chrisRedTime if self.chrisHealth < 0: fromColNp.getParent().removeNode() self.chrisAlive = False self.chrisShot.setZ(26) elif toColNp.getName() == "enemyOrbColPath" and fromColNp.getName() == "ralphColNode": toColNp.getParent().setZ(26) self.healthTxt.destroy() self.healthCount -= 3 str1 = "Health: " + str(self.healthCount) self.healthTxt = utils3.addInstructions(.06, str1) elif toColNp.getName() == "ralphColNode" and fromColNp.getName() == "enemyOrbColPath": fromColNp.getParent().setZ(26) self.healthTxt.destroy() self.healthCount -= 3 str1 = "Health: " + str(self.healthCount) self.healthTxt = utils3.addInstructions(.06, str1) return task.cont
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.seeNode = self.render.attachNewNode("see") self.cam.reparentTo(self.seeNode) self.cam.setPos(0, 0, 5) self.fpscamera = fpscontroller.FpsController(self, self.seeNode) self.fpscamera.setFlyMode(True) self.prevPos = self.fpscamera.getPos() self.prevInto = None self.info = self.genLabelText("Position: <unknown>", 4) self.makeInstructions() self.initCollisions() self.leftColor = LVecBase4i(224, 224, 64, 255) self.rightColor = LVecBase4i(64, 224, 224, 255) self.isDrawing = False self.toggleDrawing() self.accept("escape", sys.exit) # Escape quits self.accept("enter", self.toggleDrawing) def initCollisions(self): # Initialize the collision traverser. self.cTrav = CollisionTraverser() self.cTrav.showCollisions(self.render) # self.cQueue = CollisionHandlerQueue() # Initialize the Pusher collision handler. # self.pusher = CollisionHandlerPusher() self.pusher = CollisionHandlerFloor() ### player print DirectNotifyGlobal.directNotify.getCategories() # Create a collsion node for this object. playerNode = CollisionNode("player") playerNode.addSolid(CollisionSphere(0, 0, 0, 1)) # playerNode.setFromCollideMask(BitMask32.bit(0)) # playerNode.setIntoCollideMask(BitMask32.allOn()) # Attach the collision node to the object's model. self.playerC = self.fpscamera.player.attachNewNode(playerNode) # Set the object's collision node to render as visible. self.playerC.show() # Add the 'player' collision node to the Pusher collision handler. # self.pusher.addCollider(self.playerC, self.fpscamera.player) # self.pusher.addCollider(playerC, self.fpscamera.player) # self.cTrav.addCollider(self.playerC, self.cQueue) def toggleDrawing(self): self.isDrawing = not self.isDrawing if self.isDrawing: self.drawText.setText("Enter: Turn off drawing") self.fpscamera.setFlyMode(True) self.prevPos = None self.cTrav.removeCollider(self.playerC) self.pusher.removeCollider(self.playerC) self.removeTask("updatePhysics") self.addTask(self.drawHere, "drawHere") self.geomNode = GeomNode("geomNode") self.geomNodePath = self.render.attachNewNode(self.geomNode) self.geomNodePath.setTwoSided(True) # apparently p3tinydisplay needs this self.geomNodePath.setColorOff() # Create a collision node for this object. self.floorCollNode = CollisionNode("geom") # self.floorCollNode.setFromCollideMask(BitMask32.bit(0)) # self.floorCollNode.setIntoCollideMask(BitMask32.allOn()) # Attach the collision node to the object's model. floorC = self.geomNodePath.attachNewNode(self.floorCollNode) # Set the object's collision node to render as visible. floorC.show() # self.pusher.addCollider(floorC, self.geomNodePath) self.newVertexData() self.newGeom() else: self.drawText.setText("Enter: Turn on drawing") self.removeTask("drawHere") if self.prevPos: self.completePath() self.fpscamera.setFlyMode(True) self.drive.setPos(self.fpscamera.getPos()) self.cTrav.addCollider(self.playerC, self.pusher) self.pusher.addCollider(self.playerC, self.fpscamera.player) self.taskMgr.add(self.updatePhysics, "updatePhysics") def newVertexData(self): fmt = GeomVertexFormat.getV3c4() # fmt = GeomVertexFormat.getV3n3c4() self.vertexData = GeomVertexData("path", fmt, Geom.UHStatic) self.vertexWriter = GeomVertexWriter(self.vertexData, "vertex") # self.normalWriter = GeomVertexWriter(self.vertexData, 'normal') self.colorWriter = GeomVertexWriter(self.vertexData, "color") def newGeom(self): self.triStrips = GeomTristrips(Geom.UHDynamic) self.geom = Geom(self.vertexData) self.geom.addPrimitive(self.triStrips) def makeInstructions(self): OnscreenText(text="Draw Path by Walking", style=1, fg=(1, 1, 0, 1), pos=(0.5, -0.95), scale=0.07) self.drawText = self.genLabelText("", 0) self.genLabelText("Walk (W/S/A/D), Jump=Space, Look=PgUp/PgDn", 1) self.genLabelText(" (hint, go backwards with S to see your path immediately)", 2) self.genLabelText("ESC: Quit", 3) def genLabelText(self, text, i): return OnscreenText(text=text, pos=(-1.3, 0.95 - 0.05 * i), fg=(1, 1, 0, 1), align=TextNode.ALeft, scale=0.05) def drawHere(self, task): pos = self.fpscamera.getPos() self.info.setText( "Position: {0}, {1}, {2} at {3} by {4}".format( int(pos.x * 100) / 100.0, int(pos.y * 100) / 100.0, int(pos.z) / 100.0, self.fpscamera.getHeading(), self.fpscamera.getLookAngle(), ) ) prevPos = self.prevPos if not prevPos: self.prevPos = pos elif (pos - prevPos).length() > 1: self.drawQuadTo(prevPos, pos, 2) row = self.vertexWriter.getWriteRow() numPrims = self.triStrips.getNumPrimitives() if numPrims == 0: primVerts = row else: primVerts = row - self.triStrips.getPrimitiveEnd(numPrims - 1) if primVerts >= 4: self.triStrips.closePrimitive() if row >= 256: print "Packing and starting anew" newGeom = True self.geom.unifyInPlace(row, False) else: newGeom = False self.completePath() if newGeom: self.newVertexData() self.newGeom() if not newGeom: self.triStrips.addConsecutiveVertices(row - 2, 2) else: self.drawQuadTo(prevPos, pos, 2) self.leftColor[1] += 63 self.rightColor[2] += 37 self.prevPos = pos return task.cont def drawLineTo(self, pos, color): self.vertexWriter.addData3f(pos.x, pos.y, pos.z) # self.normalWriter.addData3f(0, 0, 1) self.colorWriter.addData4i(color) self.triStrips.addNextVertices(1) def drawQuadTo(self, a, b, width): """ a (to) b are vectors defining a line bisecting a new quad. """ into = b - a if abs(into.x) + abs(into.y) < 1: if not self.prevInto: return into = self.prevInto print into else: into.normalize() # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space if self.vertexWriter.getWriteRow() == 0: self.drawQuadRow(a, into, width) self.drawQuadRow(b, into, width) self.prevInto = into def drawQuadRow(self, a, into, width): """ a defines a point, with 'into' being the normalized direction. """ # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space aLeft = Vec3(a.x - into.y * width, a.y + into.x * width, a.z) aRight = Vec3(a.x + into.y * width, a.y - into.x * width, a.z) row = self.vertexWriter.getWriteRow() self.vertexWriter.addData3f(aLeft) self.vertexWriter.addData3f(aRight) # self.normalWriter.addData3f(Vec3(0, 0, 1)) # self.normalWriter.addData3f(Vec3(0, 0, 1)) self.colorWriter.addData4i(self.leftColor) self.colorWriter.addData4i(self.rightColor) self.triStrips.addConsecutiveVertices(row, 2) def completePath(self): self.geomNode.addGeom(self.geom) if self.triStrips.getNumPrimitives() == 0: return floorMesh = CollisionFloorMesh() tris = self.triStrips.decompose() p = 0 vertexReader = GeomVertexReader(self.vertexData, "vertex") for i in range(tris.getNumPrimitives()): v0 = tris.getPrimitiveStart(i) ve = tris.getPrimitiveEnd(i) if v0 < ve: vertexReader.setRow(tris.getVertex(v0)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(tris.getVertex(v0 + 1)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(tris.getVertex(v0 + 2)) floorMesh.addVertex(Point3(vertexReader.getData3f())) floorMesh.addTriangle(p, p + 1, p + 2) p += 3 self.floorCollNode.addSolid(floorMesh) def updatePhysics(self, task): pos = self.fpscamera.getPos() self.info.setText( "Position: {0}, {1}, {2}".format(int(pos.x * 100) / 100.0, int(pos.y * 100) / 100.0, int(pos.z) / 100.0) ) return task.cont
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.ralph = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(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() 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 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 Character(DirectObject, XMLExportable, PropertiesTableAbstract, GameEntity): def __init__(self, attributes, showCollisions, grid_currentx, grid_currenty, grid_playable_pos, parent): GameEntity.__init__(self, parent) #running parent constructor self.movtask = 0 self.showCollisions = showCollisions self.grid_currentx = grid_currentx self.grid_currenty = grid_currenty self.grid_playable_pos = grid_playable_pos self.attributes = attributes self.onPicked = '' self.onWalked = '' self.typeName = 'character' self.properties = { 'url': '', 'onWalked': '', 'onPicked': '', 'id': '', 'inclination': '', 'scale': '', 'hitboxscale': '', 'speed': '', 'playable': '', 'direction': '' } if attributes.has_key('url'): self.properties['url'] = attributes['url'].value else: print "WARNING: url not defined, loading placeholder" self.properties['url'] = 'misc/placeholder' if attributes.has_key('id'): self.properties['id'] = attributes['id'].value else: self.properties['id'] = 'all' if attributes.has_key('inclination'): self.properties['inclination'] = float( attributes['inclination'].value) else: self.properties['inclination'] = 30.0 if attributes.has_key('scale'): self.properties['scale'] = float(attributes['scale'].value) else: self.properties['scale'] = 1.0 if attributes.has_key('hitboxscale'): self.properties['hitboxscale'] = float( attributes['hitboxscale'].value) else: self.properties['hitboxscale'] = 1.0 if attributes.has_key('speed'): self.properties['speed'] = float(attributes['speed'].value) else: self.properties['speed'] = 1.0 #self.isNPC remains true while isPlayable is changable if attributes.has_key('playable'): self.playable = playable = attributes['playable'].value if self.playable == 'false': self.isNPC = False #print "setting ", self.properties['id'], " to ", self.isNPC else: self.isNPC = True #print "setting ", self.properties['id'], " to ", self.isNPC else: self.playable = playable = 'false' self.isNPC = True self.properties['playable'] = self.playable if attributes.has_key('direction'): self.properties['direction'] = attributes['direction'].value else: self.properties['direction'] = "down" if attributes.has_key('onWalked'): self.properties['onWalked'] = self.onWalked = attributes[ 'onWalked'].value else: self.properties['onWalked'] = self.onWalked = "" if attributes.has_key('onPicked'): self.properties['onPicked'] = self.onPicked = attributes[ 'onPicked'].value self.generateNode(showCollisions) def generateNode(self, showCollisions): self.destroy() #setting local variable attributes = self.attributes #defaulted to None self.pickCTrav = None #movement self.state = "still" self.showCollisions = showCollisions self.movtask = 0 self.currentlydown = [] self.currentlyfollowed = 0 self.pickRequest = False #public props self.node = NodePath("characternode") self.node.setTwoSided(True) self.wtop = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/wtop.egg')) self.wdown = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/wdown.egg')) self.wleft = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/wleft.egg')) self.wright = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/wright.egg')) self.stop = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/stop.egg')) self.sdown = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/sdown.egg')) self.sleft = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/sleft.egg')) self.sright = self.applyNearestFilter( loader.loadModel( resourceManager.getResource(self.properties['url']) + '/sright.egg')) #Texture.FTNearest self.wtop.reparentTo(self.node) self.wdown.reparentTo(self.node) self.wleft.reparentTo(self.node) self.wright.reparentTo(self.node) self.stop.reparentTo(self.node) self.sdown.reparentTo(self.node) self.sleft.reparentTo(self.node) self.sright.reparentTo(self.node) self.leftdown = False self.rightdown = False self.downdown = False self.topdown = False if self.playable == "true": self.setPlayable( False) #seems nonsense, triggered on grid.changeMap event self.node.setTag( "playable", "true" ) #setting this to make it recognizable from grid changeMap api self.setCollisions(True) self.setPickCollisions(True) else: self.setPlayable(False) self.node.setTag("playable", "false") self.setCollisions(False) self.setPickCollisions(False) #self.node.setX((-32/2)+0.5) self.node.setP(-(360 - int(self.properties['inclination']))) self.node.setScale(float(self.properties['scale'])) self.node.setTransparency(TransparencyAttrib.MAlpha) self.lastpos = self.node.getPos() self.showAllSubnodes() #taskMgr.doMethodLater(4, self.face, 'charload'+self.properties['id'], [self.properties['direction']]) self.face(self.properties['direction']) #set unique id self.node.setTag("id", self.properties['id']) #setting scripting part self.node.setTag("onWalked", self.onWalked) self.node.setTag("onPicked", self.onPicked) #storing a pointer of the gamenode self.node.setPythonTag("gamenode", self) self.npc_walk_stack = [] self.npc_walk_happening = False self.globalLock = False self.setX(self.grid_currentx) self.setY(self.grid_currenty) if self.isNPC != True: print "attempting creation of NPC in ", self.grid_currentx, "-", self.grid_currenty if attributes.has_key('playable'): if self.isNPC != False: if ((self.grid_playable_pos.getX() != 0) and (self.grid_playable_pos.getY() != 0)): print 'GRID: moving player to ' + str( self.grid_playable_pos) self.setX(self.grid_playable_pos.getX()) self.setY(self.grid_playable_pos.getY()) #automatic reparenting (and showing) when (re)generating node self.node.wrtReparentTo(self.parent.node) def getName(self): return 'Character: ' + self.properties['id'] def xmlAttributes(self): return self.properties def xmlTypeName(self): return self.typeName ''' Sanitize properties data to be of correct type from string ''' def sanitizeProperties(self): #sanitizing data self.properties['inclination'] = float(self.properties['inclination']) self.properties['hitboxscale'] = float(self.properties['hitboxscale']) self.properties['speed'] = float(self.properties['speed']) self.properties['scale'] = float(self.properties['scale']) self.updateTilePosition() #interface needed by PropertiesTable # regenerates the node at every change def onPropertiesUpdated(self): self.sanitizeProperties() self.generateNode(self.showCollisions) #interface needed by PropertiesTable #TODO: implement as real interface? def getPropertyList(self): return self.properties #interface needed by PropertiesTable def setProperty(self, key, value): self.properties[key] = value def setSpeed(self, s): self.properties['speed'] = s def applyNearestFilter(self, model): for tex in model.findAllTextures(): tex.setMinfilter(Texture.FT_nearest) tex.setMagfilter(Texture.FT_nearest) return model ''' make the npc walk in direction for units ''' def npc_push_walk(self, direction, units): #locking script execution self.globalLock = True script.addOneCustomLock(self) #start the walking self.npc_walk_stack.append([direction, units]) self.npc_walk_helper() #apicall def npc_walk_helper(self): x = self.node.getX() y = self.node.getZ() #concurrent protection if self.npc_walk_happening == True: return #returning if no movement has to be performed if len(self.npc_walk_stack) < 0: return movement = self.npc_walk_stack.pop(0) direction = movement[0] units = movement[1] self.npc_targetx = x self.npc_targety = y self.npc_direction = direction if (direction == "down"): self.npc_targety = self.npc_targety - units elif (direction == "up"): self.npc_targety = self.npc_targety + units elif (direction == "left"): self.npc_targetx = self.npc_targetx - units elif (direction == "right"): self.npc_targetx = self.npc_targetx + units self.setAnim(direction) self.npc_walk_happening = True self.npc_movtask = taskMgr.add(self.npc_walk_task, "npc_moveCharacterTask" + self.properties['id'], uponDeath=self.npc_walk_callback) def npc_walk_task(self, task): dt = globalClock.getDt() if (self.npc_direction == 'left'): self.node.setX(self.node.getX() - 1 * dt * self.properties['speed']) currentx = self.node.getX() if currentx <= self.npc_targetx: return task.done if (self.npc_direction == 'right'): self.node.setX(self.node.getX() + 1 * dt * self.properties['speed']) currentx = self.node.getX() if currentx >= self.npc_targetx: return task.done if (self.npc_direction == 'up'): self.node.setZ(self.node.getZ() + 1 * dt * self.properties['speed']) currenty = self.node.getZ() if currenty >= self.npc_targety: return task.done if (self.npc_direction == 'down'): self.node.setZ(self.node.getZ() - 1 * dt * self.properties['speed']) currenty = self.node.getZ() if currenty <= self.npc_targety: return task.done return task.cont def npc_walk_callback(self, task): self.face(self.npc_direction) #unlocking concurrent movement protection self.npc_walk_happening = False if len(self.npc_walk_stack) > 0: self.npc_walk_helper() else: #character ended walking, unlock self.globalLock = False ''' write destroyfunction ''' def destroy(self): #not accepting events self.ignoreAll() #destroying everything down if self.node != None: self.node.remove_node() #removing all tasks if self.movtask != 0: taskMgr.remove(self.movtask) self.movtask = 0 def face(self, direction): if direction == "left": self.hideAllSubnodes() self.sleft.show() if direction == "right": self.hideAllSubnodes() self.sright.show() if direction == "top" or direction == "up": #let's keep retrocompatibility self.hideAllSubnodes() self.stop.show() if direction == "down": self.hideAllSubnodes() self.sdown.show() def setCollisions(self, value): if value == True: b = self.node.getBounds().getRadius() self.cTrav = CollisionTraverser() self.collisionTube = CollisionSphere( b / 2, 0, b / 2, 0.035 * self.properties['hitboxscale']) self.collisionNode = CollisionNode('characterTube') self.collisionNode.addSolid(self.collisionTube) self.collisionNodeNp = self.node.attachNewNode(self.collisionNode) self.collisionHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.collisionNodeNp, self.collisionHandler) if self.showCollisions == True or main.editormode: # Uncomment this line to see the collision rays self.collisionNodeNp.show() # Uncomment this line to show a visual representation of the # collisions occuring self.cTrav.showCollisions(render) else: b = self.node.getBounds().getRadius() self.collisionTube = CollisionSphere( b / 2, 0, b / 2, 0.035 * self.properties['hitboxscale']) #allowing playables to collide with npcs if self.isNPC == True: #TODO: fix because it's completely f****d up self.collisionNode = CollisionNode('characterTube') else: self.collisionNode = CollisionNode('characterNPCTube') self.collisionNode.addSolid(self.collisionTube) self.collisionNodeNp = self.node.attachNewNode(self.collisionNode) #set if camera has to effectively follow the character #while it moves def setFollowedByCamera(self, value): #camera follow if value: if self.currentlyfollowed != True: customCamera.follow(self) self.currentlyfollowed = True else: if self.currentlyfollowed != False: customCamera.dontFollow() self.currentlyfollowed = False def setPickCollisions(self, value): if value: print "setting pick collisions" b = self.node.getBounds().getRadius() self.pickCTrav = CollisionTraverser() self.pickCollisionTube = CollisionSphere( b / 2, 0, b / 2, 0.035 * self.properties['hitboxscale'] + 0.01) self.pickCollisionNode = CollisionNode('characterPickTube') self.pickCollisionNode.addSolid(self.pickCollisionTube) self.pickCollisionNodeNp = NodePath(self.pickCollisionNode) self.pickCollisionNodeNp.reparentTo(self.node) self.pickCollisionHandler = CollisionHandlerQueue() self.pickCTrav.addCollider(self.pickCollisionNodeNp, self.pickCollisionHandler) if self.showCollisions == True: # Uncomment this line to see the collision rays self.pickCollisionNodeNp.show() # Uncomment this line to show a visual representation of the # collisions occuring self.pickCTrav.showCollisions(render) else: #dereferincing all pick colliders (must be done in order not to collide onto NPCs) self.pickCTrav = None self.pickCollisionTube = None self.pickCollisionNode = None self.pickCollisionNodeNp = None self.pickCollisionHandler = None #used to set playability in real time #useful when we want to switch context/scripted scenes def setPlayable(self, value): if self.isNPC != False: if value == True: #down events self.accept("arrow_left", self.arrowLeftDown) self.accept("arrow_right", self.arrowRightDown) self.accept("arrow_up", self.arrowUpDown) self.accept("arrow_down", self.arrowDownDown) #up events self.accept("arrow_left-up", self.arrowLeftUp) self.accept("arrow_right-up", self.arrowRightUp) self.accept("arrow_up-up", self.arrowUpUp) self.accept("arrow_down-up", self.arrowDownUp) self.accept("space", self.spaceDown) self.node.setTag("playable", "true") self.setFollowedByCamera(True) self.accept("pauseGameplay", self.setPlayable, [False]) #can pause play else: self.ignoreAll() self.node.setTag("playable", "false") self.setFollowedByCamera(False) self.resetMovement() #reset every movement happening self.accept("resumeGameplay", self.setPlayable, [True]) #can resume play if not NPC #estimate loading time 4 seconds... lol... UPDATE: seems fixed in newer panda versions, inspect def showAllSubnodes(self): self.wtop.show() self.wdown.show() self.wleft.show() self.wright.show() self.stop.show() self.sdown.show() self.sleft.show() self.sright.show() def hideAllSubnodes(self): self.wtop.hide() self.wdown.hide() self.wleft.hide() self.wright.hide() self.stop.hide() self.sdown.hide() self.sleft.hide() self.sright.hide() def setMovement(self, value): if value == True: if self.movtask == 0: self.movtask = taskMgr.add(self.moveCharacter, "moveCharacterTask") if value == False: if self.movtask != 0: if len(self.currentlydown) == 0: taskMgr.remove(self.movtask) self.movtask = 0 ''' reset every movement actually happening ''' def resetMovement(self): if self.leftdown == True: self.face("left") if self.rightdown == True: self.face("right") if self.downdown == True: self.face("down") if self.topdown == True: self.face("top") self.leftdown = False self.rightdown = False self.downdown = False self.topdown = False self.currentlydown = [] self.setMovement(False) def setAnim(self, direction=''): self.hideAllSubnodes() if direction == '': if len(self.currentlydown) > 0: if self.currentlydown[-1] == 'left': self.wleft.show() if self.currentlydown[-1] == 'right': self.wright.show() if self.currentlydown[-1] == 'top': self.wtop.show() if self.currentlydown[-1] == 'down': self.wdown.show() else: if direction == 'left': self.wleft.show() if direction == 'right': self.wright.show() if direction == 'up': self.wtop.show() if direction == 'down': self.wdown.show() #pick request function def spaceDown(self): self.pickRequest = True #movement related functions def arrowLeftDown(self): #track key down self.leftdown = True self.setMovement(True) #show changes to screen self.currentlydown.append("left") self.setAnim() def arrowLeftUp(self): self.leftdown = False self.setMovement(False) #show changes to screen if len(self.currentlydown) == 1: self.hideAllSubnodes() self.sleft.show() if "left" in self.currentlydown: self.currentlydown.remove("left") if len(self.currentlydown) > 0: self.setAnim() def arrowRightDown(self): #track key down self.rightdown = True self.setMovement(True) #show changes to screen self.currentlydown.append("right") self.setAnim() def arrowRightUp(self): self.setMovement(False) self.rightdown = False #show changes to screen if len(self.currentlydown) == 1: self.hideAllSubnodes() self.sright.show() if "right" in self.currentlydown: self.currentlydown.remove("right") if len(self.currentlydown) > 0: self.setAnim() def arrowDownDown(self): #track key down self.downdown = True self.setMovement(True) #show changes to screen self.currentlydown.append("down") self.setAnim() def arrowDownUp(self): self.downdown = False self.setMovement(False) #show changes to screen if len(self.currentlydown) == 1: self.hideAllSubnodes() self.sdown.show() if "down" in self.currentlydown: self.currentlydown.remove("down") if len(self.currentlydown) > 0: self.setAnim() def arrowUpDown(self): #track key down self.topdown = True self.setMovement(True) #show changes to screen self.currentlydown.append("top") self.setAnim() def arrowUpUp(self): self.topdown = False self.setMovement(False) #show changes to screen if len(self.currentlydown) == 1: self.hideAllSubnodes() self.stop.show() if "top" in self.currentlydown: self.currentlydown.remove("top") if len(self.currentlydown) > 0: self.setAnim() def moveCharacter(self, task): dt = globalClock.getDt() if len(self.currentlydown) > 0: if self.currentlydown[-1] == 'left': self.node.setX(self.node.getX() - 1 * dt * self.properties['speed']) if self.currentlydown[-1] == 'right': self.node.setX(self.node.getX() + 1 * dt * self.properties['speed']) if self.currentlydown[-1] == 'top': self.node.setZ(self.node.getZ() + 1 * dt * self.properties['speed']) if self.currentlydown[-1] == 'down': self.node.setZ(self.node.getZ() - 1 * dt * self.properties['speed']) #check collisions if self.cTrav != None: self.cTrav.traverse(render) if self.pickCTrav != None: self.pickCTrav.traverse(render) #entries python list entries = list(self.collisionHandler.getEntries()) pickentries = list(self.pickCollisionHandler.getEntries()) for e in entries[:]: if e.getIntoNodePath().getName() == "characterPickTube": entries.remove(e) for e in pickentries[:]: if e.getIntoNodePath().getName() == "characterTube": pickentries.remove(e) if len(entries) == 0: self.lastpos = self.node.getPos() else: sp = entries[0].getSurfacePoint(self.node) #surface point objectNode = entries[0].getIntoNodePath().getParent( ) #into object node groundNode = entries[0].getIntoNodePath() #into object node if objectNode.hasTag("collideandwalk"): if objectNode.getTag("collideandwalk") != "yes": self.node.setPos(self.lastpos) else: self.node.setPos(self.lastpos) #if node is a real object (not a wall) if objectNode.hasTag("avoidable"): if objectNode.getTag( "avoidable" ) == "true": #see if object is intelligently avoidable if objectNode.hasTag("xscaled") and objectNode.hasTag( "yscaled"): if len( self.currentlydown ) > 0: #at least 1, avoids list index out of range exception if self.currentlydown[ -1] == 'left' or self.currentlydown[ -1] == 'right': #TODO: fix the shiet, not always working bottomObjPos = objectNode.getZ() - ( float(objectNode.getTag("yscaled")) / 2) topObjPos = objectNode.getZ() + ( float(objectNode.getTag("yscaled")) / 2) if self.node.getZ() < bottomObjPos: self.node.setZ(self.node.getZ() - 1 * dt * self.properties['speed']) if self.node.getZ() > topObjPos: self.node.setZ(self.node.getZ() + 1 * dt * self.properties['speed']) pass if self.currentlydown[ -1] == 'top' or self.currentlydown[ -1] == 'down': leftObjPos = objectNode.getX() - ( float(objectNode.getTag("xscaled")) / 2) rightObjPos = objectNode.getX() + ( float(objectNode.getTag("xscaled")) / 2) if self.node.getX() < leftObjPos: self.node.setX(self.node.getX() - 1 * dt * self.properties['speed']) if self.node.getX() > rightObjPos: self.node.setX(self.node.getX() + 1 * dt * self.properties['speed']) self.lastpos = self.node.getPos() for entry in entries: objectNode = entry.getIntoNodePath().getParent() onWalked = objectNode.getTag("onWalked") if len(onWalked) > 0: eval(onWalked) #oh lol, danger detected here evaluatedOnce = False if self.pickRequest == True: for entry in pickentries: objectNode = entry.getIntoNodePath().getParent() onPicked = objectNode.getTag("onPicked") if len(onPicked) > 0 and evaluatedOnce == False: eval(onPicked) #oh lol, danger detected again here evaluatedOnce = True else: if hasattr(objectNode.getPythonTag('gamenode'), 'name'): print "WARNING: picking on this object is not defined: ", objectNode.getPythonTag( 'gamenode').name print "X: ", objectNode.getX() print "Y: ", objectNode.getZ() self.pickRequest = False #resetting request #this is needed for empty pick if self.pickRequest == True: self.pickRequest = False #resetting request return Task.cont def getWorldPos(self): return self.node.getPos(render) def setX(self, x): self.node.setX(x) self.lastpos.setX(x) def setY(self, y): self.node.setZ(y) self.lastpos.setZ(y) #here for polymorph def getTileX(self): return self.parent.getX() #here for polymorph def getTileY(self): return self.parent.getY()
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) # relevant for DEBUG self.debug = True self.debugLabel = self.makeStatusLabel(0) if (self.debug): self.debugLabel.setText("Debug Mode ON") else: self.debugLabel.setText("Debug Mode OFF") self.statusLabel = self.makeStatusLabel(1) self.collisionLabel = self.makeStatusLabel(2) self.world = self.loader.loadModel("world.bam") self.world.reparentTo(self.render) # relevant for world boundaries self.worldsize = 1024 self.maxspeed = 100.0 self.startPos = Vec3(200, 200, 1) self.startHpr = Vec3(225, 0, 0) self.player = self.loader.loadModel("alliedflanker") self.player.setScale(.2, .2, .2) self.player.reparentTo(self.render) self.resetPlayer() self.startPosPartner = Vec3(200, 200, 1) self.startHprPartner = Vec3(225, 0, 0) self.partner = self.loader.loadModel("alliedflanker") self.partner.setScale(.2, .2, .2) self.partner.reparentTo(self.render) self.resetPartner() # A task to run every frame self.taskMgr.add(self.updateTask, "update") self.keyboardSetup() #performance (to be masked later by fog) and view: self.maxdistance = 400 self.camLens.setFar(self.maxdistance) self.camLens.setFov(60) self.createEnviroment() # relevant for collision and DEBUG self.setupCollisions() self.textCounter = 0 # explosion self.explosionModel = loader.loadModel('explosion') self.explosionModel.reparentTo(self.render) self.explosionModel.setScale(0.0) self.explosionModel.setLightOff() # only one explosion at a time: self.exploding = False self.radar # relevant for DEBUG def makeStatusLabel(self, i): return OnscreenText(style=2, fg=(.5,1,.5,1), pos=(-1.3,0.92-(.08*i)),\ align=TextNode.ALeft, scale = .08, mayChange = 1) # relevant for collision and DEBUG def setupCollisions(self): self.collTrav = CollisionTraverser() self.playerGroundSphere = CollisionSphere(0, 1.5, 56, 1) self.playerGroundCol = CollisionNode('playerSphere') self.playerGroundCol.addSolid(self.playerGroundSphere) # bitmask self.playerGroundCol.setFromCollideMask(BitMask32.bit(0)) self.playerGroundCol.setIntoCollideMask(BitMask32.allOff()) self.world.setCollideMask(BitMask32.bit(0)) # and done self.playerGroundColNp = self.player.attachNewNode( self.playerGroundCol) self.playerGroundHandler = CollisionHandlerQueue() self.collTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler) # DEBUG if (self.debug == True): self.playerGroundColNp.show() self.collTrav.showCollisions(self.render) def keyboardSetup(self): self.keyMap = { "left": 0, "right": 0, "climb": 0, "fall": 0, "accelerate": 0, "decelerate": 0, "fire": 0 } self.accept("escape", sys.exit) self.accept("a", self.setKey, ["accelerate", 1]) self.accept("a-up", self.setKey, ["accelerate", 0]) self.accept("z", self.setKey, ["decelerate", 1]) self.accept("z-up", self.setKey, ["decelerate", 0]) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_down", self.setKey, ["climb", 1]) self.accept("arrow_down-up", self.setKey, ["climb", 0]) self.accept("arrow_up", self.setKey, ["fall", 1]) self.accept("arrow_up-up", self.setKey, ["fall", 0]) self.accept("space", self.setKey, ["fire", 1]) self.accept("space-up", self.setKey, ["fire", 0]) base.disableMouse() # or updateCamera will fail def createEnviroment(self): # Fog to hide performance tweak: colour = (0.5, 0.5, 0.5) expfog = Fog("scene-wide-fog") expfog.setColor(*colour) expfog.setExpDensity(0.002) self.render.setFog(expfog) base.setBackgroundColor(*colour) # Our sky skydome = self.loader.loadModel('blue-sky-sphere') skydome.setEffect(CompassEffect.make(self.render)) skydome.setScale(0.08) # bit less than "far" # NOT render - you`ll fly through the sky!: skydome.reparentTo(self.camera) # Our lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.6, .6, .6, 1)) render.setLight(render.attachNewNode(ambientLight)) directionalLight = DirectionalLight("directionalLight") directionalLight.setColor(Vec4(0.8, 0.8, 0.5, 1)) dlnp = self.render.attachNewNode(directionalLight) dlnp.setPos(0, 0, 260) dlnp.lookAt(self.player) self.render.setLight(dlnp) self.render2d = render2d # image scale of 1 fills screen, position defaults to central Scale = 1.0 / 2.5 # decimal point is VITAL self.radar = OnscreenImage(image='radar.png', scale=Scale, \ parent=self.render2d, pos=(-0.95,0,-0.95)) self.radar.setTransparency(TransparencyAttrib.MAlpha) # note the image itself and how it is centered hud = OnscreenImage(image='hud1.png', scale=1, \ parent=self.render2d, pos=(0,0,0)) hud.setTransparency(TransparencyAttrib.MAlpha) self.dots = list() self.playerobj = OnscreenImage(image='playerdot.png', \ scale=1.0/20.0,parent=self.radar) self.playerobj.setTransparency(TransparencyAttrib.MAlpha) def setKey(self, key, value): self.keyMap[key] = value def updateTask(self, task): self.updatePlayer() self.updateCamera() self.updateGUI(self.worldsize) #relevant for collision and DEBUG self.collTrav.traverse(self.render) for i in range(self.playerGroundHandler.getNumEntries()): entry = self.playerGroundHandler.getEntry(i) if (self.debug == True): self.collisionLabel.setText("HIT:" + str(globalClock.getFrameTime())) if (self.exploding == False): self.player.setZ(entry.getSurfacePoint(self.render).getZ() + 5) self.explosionSequence() return Task.cont def updatePlayer(self): if self.exploding == False: #Global Clock #by default, panda runs as fast as it can frame to frame scalefactor = (globalClock.getDt() * self.speed) climbfactor = scalefactor * 0.5 bankfactor = scalefactor speedfactor = scalefactor * 2.9 gravityfactor = ((self.maxspeed - self.speed) / 100.0) * 2.0 #Climb and Fall if (self.keyMap["climb"] != 0 and self.speed > 0.00): #faster you go, quicker you climb self.player.setZ(self.player.getZ() + climbfactor) self.player.setR(self.player.getR() + climbfactor) #quickest return: (:avoids uncoil/unwind) if (self.player.getR() >= 180): self.player.setR(-180) elif (self.keyMap["fall"] != 0 and self.speed > 0.00): self.player.setZ(self.player.getZ() - climbfactor) self.player.setR(self.player.getR() - climbfactor) #quickest return if (self.player.getR() <= -180): self.player.setR( 180 ) #autoreturn - add a bit regardless to make sure it happens elif (self.player.getR() > 0): self.player.setR(self.player.getR() - (climbfactor + 0.1)) if (self.player.getR() < 0): self.player.setR(0) #avoid jitter elif (self.player.getR() < 0): self.player.setR(self.player.getR() + (climbfactor + 0.1)) if (self.player.getR() > 0): self.player.setR(0) #Left and Right if (self.keyMap["left"] != 0 and self.speed > 0.0): self.player.setH(self.player.getH() + bankfactor) self.player.setP(self.player.getP() + bankfactor) #quickest return: if (self.player.getP() >= 180): self.player.setP(-180) elif (self.keyMap["right"] != 0 and self.speed > 0.0): self.player.setH(self.player.getH() - bankfactor) self.player.setP(self.player.getP() - bankfactor) if (self.player.getP() <= -180): self.player.setP(180) #autoreturn elif (self.player.getP() > 0): self.player.setP(self.player.getP() - (bankfactor + 0.1)) if (self.player.getP() < 0): self.player.setP(0) elif (self.player.getP() < 0): self.player.setP(self.player.getP() + (bankfactor + 0.1)) if (self.player.getP() > 0): self.player.setP(0) #throttle control if (self.keyMap["accelerate"] != 0): self.speed += 1 if (self.speed > self.maxspeed): self.speed = self.maxspeed elif (self.keyMap["decelerate"] != 0): self.speed -= 1 if (self.speed < 0.0): self.speed = 0.0 #move forwards - our X/Y is inverted, see the issue self.player.setX( self.player, -speedfactor ) #respect max camera distance else you cannot see the floor post loop the loop! self.applyBoundaries() self.player.setZ(self.player, -gravityfactor) def updateGUI(self, boundingBox): boundingBox = boundingBox * 2 offsetX = 0.0 offsetZ = 0.0 # would be fine for minimap self.playerobj.setX(self.player.getX() / boundingBox) self.playerobj.setZ(self.player.getY() / boundingBox) # player center if (self.playerobj.getX() > 0.5): offsetX = -(self.playerobj.getX() - 0.5) elif (self.playerobj.getX() < 0.5): offsetX = 0.5 - self.playerobj.getX() # else stays zero if (self.playerobj.getZ() > 0.5): offsetZ = -(self.playerobj.getZ() - 0.5) elif (self.playerobj.getZ() < 0.5): offsetZ = 0.5 - self.playerobj.getZ() self.playerobj.setX(self.playerobj.getX() + offsetX) self.playerobj.setZ(self.playerobj.getZ() + offsetZ) for dot in self.dots: dot.removeNode() # correct way to remove from scene graph del self.dots[:] self.playerobj.setR(-self.player.getH() - 90) newobj = OnscreenImage(image='reddot.png',scale=1.0/60.0, \ parent=self.radar) newobj.setTransparency(TransparencyAttrib.MAlpha) newobj.setX(self.partner.getX() / boundingBox) newobj.setZ(self.partner.getY() / boundingBox) newobj.setX(newobj.getX() + offsetX) newobj.setZ(newobj.getZ() + offsetZ) self.dots.append(newobj) # so can destroy, see call above def applyBoundaries(self): if (self.player.getZ() > self.maxdistance): self.player.setZ(self.maxdistance) # should never happen once we add collision, but in case: elif (self.player.getZ() < 0): self.player.setZ(0) # and now the X/Y world boundaries: boundary = False if (self.player.getX() < 0): self.player.setX(0) boundary = True elif (self.player.getX() > self.worldsize): self.player.setX(self.worldsize) boundary = True if (self.player.getY() < 0): self.player.setY(0) boundary = True elif (self.player.getY() > self.worldsize): self.player.setY(self.worldsize) boundary = True # lets not be doing this every frame... if boundary == True and self.textCounter > 30: self.statusLabel.setText("STATUS: MAP END; TURN AROUND") elif self.textCounter > 30: self.statusLabel.setText("STATUS: OK") if self.textCounter > 30: self.textCounter = 0 else: self.textCounter = self.textCounter + 1 def updateCamera(self): #see issue content for how we calculated these: percent = (self.speed / self.maxspeed) self.camera.setPos(self.player, 19.6226 + (10 * percent), 3.8807, 10.2779) self.camera.setHpr(self.player, 94.8996, -12.6549, 1.55508) def resetPlayer(self): self.player.show() self.player.setPos(self.world, self.startPos) self.player.setHpr(self.world, self.startHpr) self.speed = self.maxspeed / 2 def resetPartner(self): self.partner.show() self.partner.setPos(self.world, self.startPosPartner) self.partner.setHpr(self.world, self.startHprPartner) def explosionSequence(self): self.exploding = True self.explosionModel.setPosHpr( Vec3(self.player.getX(), self.player.getY(), self.player.getZ()), Vec3(self.player.getH(), 0, 0)) self.player.hide() taskMgr.add(self.expandExplosion, 'expandExplosion') def expandExplosion(self, Task): # expand the explosion rign each frame until a certain size if self.explosionModel.getScale() < VBase3(60.0, 60.0, 60.0): factor = globalClock.getDt() scale = self.explosionModel.getScale() scale = scale + VBase3(factor * 40, factor * 40, factor * 40) self.explosionModel.setScale(scale) return Task.cont else: self.explosionModel.setScale(0) self.exploding = False self.resetPlayer()
class 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 SpaceFlight(ShowBase): def __init__(self): ShowBase.__init__(self) self.text = OnscreenText \ ( parent = base.a2dBottomCenter, align=TextNode.ARight, fg=(1, 1, 1, 1), pos=(0.2, 1.), scale=0.1, shadow=(0, 0, 0, 0.5) ) self.setBackgroundColor(0, 0, 0) self.disableMouse() self.fog = Fog('distanceFog') self.fog.setColor(0, 0, 0) self.fog.setExpDensity(.002) # self.queue = CollisionHandlerQueue() self.trav = CollisionTraverser('traverser') base.cTrav = self.trav self.loadSky() self.reloadGame() self.keyMap = {'left' : 0, 'right' : 0, 'up' : 0, 'down' : 0} self.gamePause = False # self.accept('escape', sys.exit) self.accept('p', self.pause) self.accept('r', self.reloadGame) self.accept('arrow_left', self.setKey, ['left', True]) self.accept('arrow_right', self.setKey, ['right', True]) self.accept('arrow_up', self.setKey, ['up', True]) self.accept('arrow_down', self.setKey, ['down', 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, ['up', False]) self.accept('arrow_down-up', self.setKey, ['down', False]) # taskMgr.add(self.moveShip, 'moveShip') taskMgr.add(self.moveAsteroids, 'moveAsteroids') taskMgr.add(self.handleCollisions, 'handleCollisions') # if DEBUG: self.trav.showCollisions(render) render.find('**/ship_collision').show() for asteroid in render.findAllMatches('**/asteroid_collision*'): asteroid.show() def loadSky(self): self.sky = loader.loadModel('models/solar_sky_sphere.egg.pz') self.sky_tex = loader.loadTexture('models/stars_1k_tex.jpg') self.sky.setTexture(self.sky_tex, 1) self.sky.reparentTo(render) self.sky.setScale(500) def loadShip(self): self.ship = loader.loadModel('models/alice-scifi--fighter/fighter.egg') self.ship.reparentTo(render) self.ship.setPos(START_X, START_Y, START_Z) self.ship.setScale(0.25) # add some physics ship_col = self.ship.attachNewNode(CollisionNode('ship_collision')) col_sphere = CollisionSphere(START_X, START_Y, 0, SHIP_SPHERE_RADIUS) ship_col.node().addSolid(col_sphere) self.trav.addCollider(ship_col, self.queue) def spawnAsteroid(self): asteroid = loader.loadModel(choice(ASTEROID_SHAPES)) asteroid_tex = loader.loadTexture('models/rock03.jpg') asteroid.setTexture(asteroid_tex, 1) asteroid.reparentTo(render) asteroid.setFog(self.fog) self.asteroids.append(asteroid) self.asteroids_rotation.append(randint(ASTEROID_ROTATE_MIN, ASTEROID_ROTATE_MAX)) # num = len(self.asteroids) - 1 asteroid_col = asteroid.attachNewNode(CollisionNode('asteroid_collision_%d' % num)) col_sphere = CollisionSphere(0, 0, 0, ASTEROID_SPHERE_RADIUS) asteroid_col.node().addSolid(col_sphere) # asteroid.setX(randint(MIN_X, MAX_X)) asteroid.setY(randint(ASTEROID_SPAWN_MIN_Y, ASTEROID_SPAWN_MAX_Y)) asteroid.setZ(randint(MIN_Z, MAX_Z)) def setKey(self, key, value): self.keyMap[key] = value if key in ['left', 'right'] and value == False: self.ship.setH(0) if key in ['up', 'down'] and value == False: self.ship.setP(0) def updateCamera(self): x, y, z = self.ship.getPos() self.camera.setPos(x, y - 40, z + 25) self.camera.lookAt(x, y, z + 10) def moveAsteroids(self, task): dt = globalClock.getDt() if not self.gamePause: for num, asteroid in enumerate(self.asteroids): asteroid.setY(asteroid.getY() - ASTEROID_SPEED * dt) rotation = self.asteroids_rotation[num] asteroid.setH(asteroid.getH() - rotation * ASTEROID_SPEED * dt) if asteroid.getY() < self.camera.getY() + 10: asteroid.setX(randint(MIN_X, MAX_X)) asteroid.setY(randint(ASTEROID_SPAWN_MIN_Y, ASTEROID_SPAWN_MAX_Y)) asteroid.setZ(randint(MIN_Z, MAX_Z)) return task.cont def rollbackOnBoard(self, minPos, maxPos, getFunc, setFunc): if getFunc() < minPos: setFunc(minPos) if getFunc() > maxPos: setFunc(maxPos) def applyBound(self): self.rollbackOnBoard(MIN_X, MAX_X, self.ship.getX, self.ship.setX) self.rollbackOnBoard(MIN_Z, MAX_Z, self.ship.getZ, self.ship.setZ) def moveShip(self, task): dt = globalClock.getDt() if not self.gamePause: if self.keyMap['left']: self.ship.setX(self.ship.getX() - SHIP_SPEED * dt) self.ship.setH(TURN_SPEED) elif self.keyMap['right']: self.ship.setX(self.ship.getX() + SHIP_SPEED * dt) self.ship.setH(-TURN_SPEED) elif self.keyMap['up']: self.ship.setZ(self.ship.getZ() + SHIP_SPEED * dt) self.ship.setP(TURN_SPEED) elif self.keyMap['down']: self.ship.setZ(self.ship.getZ() - 5 * SHIP_SPEED * dt) self.ship.setP(-TURN_SPEED) self.sky.setP(self.sky.getP() - dt * 10) self.applyBound() self.updateCamera() return task.cont def handleCollisions(self, task): if not self.gamePause: for entry in self.queue.getEntries(): node = entry.getFromNodePath() if node.getName() == 'ship_collision': self.gamePause = True self.text.setText('You lose :(') return task.cont def pause(self): self.gamePause = not self.gamePause def reloadGame(self): self.gamePause = False self.text.clearText() if hasattr(self, 'asteroids'): for asteroid in self.asteroids: asteroid.removeNode() self.asteroids = [] self.asteroids_rotation = [] if hasattr(self, 'ship'): self.ship.removeNode() self.loadShip() for _ in xrange(ASTEROID_MAX_CNT): self.spawnAsteroid()
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.seeNode = self.render.attachNewNode('see') self.cam.reparentTo(self.seeNode) self.cam.setPos(0, 0, 5) self.fpscamera = fpscontroller.FpsController(self, self.seeNode) self.fpscamera.setFlyMode(True) self.fpscamera.setMouseLook(True) self.prevPos = self.fpscamera.getPos() self.prevInto = None self.makeInstructions() self.info = self.genLabelText("Position: <unknown>", 2) self.initCollisions() self.leftColor = LVecBase4i(224, 224, 64, 255) self.rightColor = LVecBase4i(64, 224, 224, 255) self.isDrawing = False self.toggleDrawing() self.accept("escape", sys.exit) #Escape quits self.accept("enter", self.toggleDrawing) def initCollisions(self): # Initialize the collision traverser. self.cTrav = CollisionTraverser() self.cTrav.showCollisions(self.render) # Initialize the Pusher collision handler. self.pusher = CollisionHandlerFloor() ### player # Create a collsion node for this object. playerNode = CollisionNode('player') playerNode.addSolid(CollisionSphere(0, 0, 0, 1)) # Attach the collision node to the object's model. self.playerC = self.fpscamera.player.attachNewNode(playerNode) # Set the object's collision node to render as visible. self.playerC.show() def toggleDrawing(self): self.isDrawing = not self.isDrawing if self.isDrawing: self.instructionText.setText( 'Enter: Generate Tunnel from Movement') self.fpscamera.setFlyMode(True) self.prevPos = None # self.cTrav.remosveCollider(self.playerC) self.removeTask('updatePhysics') self.addTask(self.drawHere, 'drawHere') self.geomNode = GeomNode('geomNode') self.geomNodePath = self.render.attachNewNode(self.geomNode) self.geomNodePath.setTwoSided(True) # apparently p3tinydisplay needs this self.geomNodePath.setColorOff() # Create a collision node for this object. self.floorCollNode = CollisionNode('geom') # Attach the collision node to the object's model. floorC = self.geomNodePath.attachNewNode(self.floorCollNode) # Set the object's collision node to render as visible. floorC.show() self.newVertexData() self.newGeom() else: self.instructionText.setText('Enter: Record Movement for Tunnel') self.removeTask('drawHere') if self.prevPos: #self.completePath() self.completeTunnelPath() self.fpscamera.setFlyMode(True) self.drive.setPos(self.fpscamera.getPos()) self.cTrav.addCollider(self.playerC, self.pusher) self.pusher.addCollider(self.playerC, self.fpscamera.player) self.taskMgr.add(self.updatePhysics, 'updatePhysics') def newVertexData(self): fmt = GeomVertexFormat.getV3c4() # fmt = GeomVertexFormat.getV3n3c4() self.vertexData = GeomVertexData("path", fmt, Geom.UHStatic) self.vertexWriter = GeomVertexWriter(self.vertexData, 'vertex') # self.normalWriter = GeomVertexWriter(self.vertexData, 'normal') self.colorWriter = GeomVertexWriter(self.vertexData, 'color') def newGeom(self): self.triStrips = GeomTristrips(Geom.UHDynamic) self.geom = Geom(self.vertexData) self.geom.addPrimitive(self.triStrips) def makeInstructions(self): OnscreenText(text="Draw Path by Walking (WSAD/space/mouselook)", style=1, fg=(1, 1, 0, 1), pos=(0.5, -0.95), scale=.07) self.genLabelText("ESC: Quit", 0) self.instructionText = self.genLabelText("", 1) def genLabelText(self, text, i): return OnscreenText(text=text, pos=(-1.3, .95 - .05 * i), fg=(1, 1, 0, 1), align=TextNode.ALeft, scale=.05) def drawHere(self, task): pos = self.fpscamera.getPos() self.info.setText("Position: {0}, {1}, {2} at {3} by {4}".format( int(pos.x * 100) / 100., int(pos.y * 100) / 100., int(pos.z) / 100., self.fpscamera.getHeading(), self.fpscamera.getLookAngle())) prevPos = self.prevPos if not prevPos: self.prevPos = pos elif (pos - prevPos).length() >= 1: # self.extendPathQuad(prevPos, pos, 2) self.extendPathTunnel(prevPos, pos, 3) self.leftColor[1] += 63 self.rightColor[2] += 37 self.prevPos = pos return task.cont def extendPathQuad(self, prevPos, pos, width): self.drawQuadTo(prevPos, pos, width) row = self.vertexWriter.getWriteRow() numPrims = self.triStrips.getNumPrimitives() if numPrims == 0: primVerts = row else: primVerts = row - self.triStrips.getPrimitiveEnd(numPrims - 1) if primVerts >= 4: self.triStrips.closePrimitive() if row >= 256: print "Packing and starting anew" newGeom = True self.geom.unifyInPlace(row, False) else: newGeom = False self.completeQuadPath() if newGeom: self.newVertexData() self.newGeom() if newGeom: self.drawQuadTo(prevPos, pos, width) else: self.triStrips.addConsecutiveVertices(row - 2, 2) def extendPathTunnel(self, prevPos, pos, width): self.drawTunnelTo(prevPos, pos, width) def drawLineTo(self, pos, color): self.vertexWriter.addData3f(pos.x, pos.y, pos.z) # self.normalWriter.addData3f(0, 0, 1) self.colorWriter.addData4i(color) self.triStrips.addNextVertices(1) return 1 def drawQuadTo(self, a, b, width): """ a (to) b are vectors defining a line bisecting a new quad. """ into = (b - a) if abs(into.x) + abs(into.y) < 1: # ensure that if we jump in place, we don't get a thin segment if not self.prevInto: return into = self.prevInto else: into.normalize() # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space if self.vertexWriter.getWriteRow() == 0: self.drawQuadRow(a, into, width) verts = self.drawQuadRow(b, into, width) self.prevInto = into return verts def drawQuadRow(self, a, into, width): """ a defines a point, with 'into' being the normalized direction. """ # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space aLeft = Vec3(a.x - into.y * width, a.y + into.x * width, a.z) aRight = Vec3(a.x + into.y * width, a.y - into.x * width, a.z) row = self.vertexWriter.getWriteRow() self.vertexWriter.addData3f(aLeft) self.vertexWriter.addData3f(aRight) # self.normalWriter.addData3f(Vec3(0, 0, 1)) # self.normalWriter.addData3f(Vec3(0, 0, 1)) self.colorWriter.addData4i(self.leftColor) self.colorWriter.addData4i(self.rightColor) self.triStrips.addConsecutiveVertices(row, 2) return 2 def drawTunnelTo(self, a, b, width): """ a (to) b are vectors defining a line bisecting a new tunnel segment. """ into = (b - a) if abs(into.x) + abs(into.y) < 1: # ensure that if we jump in place, we don't get a thin segment if not self.prevInto: return into = self.prevInto else: into.normalize() # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space if self.vertexWriter.getWriteRow() == 0: self.drawTunnelBoundary(a, into, width) row = self.vertexWriter.getWriteRow() verts = self.drawTunnelBoundary(b, into, width) totalVerts = self.drawTunnelRow(row, verts) self.prevInto = into return totalVerts def drawTunnelBoundary(self, a, into, width): """ a defines a point, with 'into' being the normalized direction. """ aLowLeft = Vec3(a.x - into.y * width, a.y + into.x * width, a.z) aLowRight = Vec3(a.x + into.y * width, a.y - into.x * width, a.z) aHighRight = Vec3(a.x + into.y * width, a.y - into.x * width, a.z + width * 3) aHighLeft = Vec3(a.x - into.y * width, a.y + into.x * width, a.z + width * 3) self.vertexWriter.addData3f(aLowLeft) self.vertexWriter.addData3f(aLowRight) self.vertexWriter.addData3f(aHighRight) self.vertexWriter.addData3f(aHighLeft) self.colorWriter.addData4i(self.leftColor) self.colorWriter.addData4i(self.rightColor) self.colorWriter.addData4i(self.leftColor) self.colorWriter.addData4i(self.rightColor) return 4 def drawTunnelRowX(self, row, verts): # BOTTOM: bottom-left, new-bottom-left, bottom-right, new-bottom-right self.triStrips.addConsecutiveVertices(row - verts + 0, 1) self.triStrips.addConsecutiveVertices(row + 0, 1) self.triStrips.addConsecutiveVertices(row - verts + 1, 1) self.triStrips.addConsecutiveVertices(row + 1, 1) self.triStrips.closePrimitive() # RIGHT: (new-bottom-right) bottom-right, new-top-right, top-right self.triStrips.addConsecutiveVertices(row + 1, 1) self.triStrips.addConsecutiveVertices(row - verts + 1, 1) self.triStrips.addConsecutiveVertices(row + 2, 1) self.triStrips.addConsecutiveVertices(row - verts + 2, 1) self.triStrips.closePrimitive() # TOP: top-left, new top-right, new top-left self.triStrips.addConsecutiveVertices(row - verts + 2, 1) self.triStrips.addConsecutiveVertices(row - verts + 3, 1) self.triStrips.addConsecutiveVertices(row + 2, 1) self.triStrips.addConsecutiveVertices(row + 3, 1) self.triStrips.closePrimitive() # LEFT: (new top-left) new bottom-left, top-left, bottom-left, new-bottom-left self.triStrips.addConsecutiveVertices(row + 3, 1) self.triStrips.addConsecutiveVertices(row + 0, 1) self.triStrips.addConsecutiveVertices(row - verts + 3, 1) self.triStrips.addConsecutiveVertices(row - verts + 0, 1) self.triStrips.closePrimitive() return verts * 4 def drawTunnelRow(self, row, verts): # # clockwise for the inside of the tunnel # # TOP: new-top-left, top-left, new-top-right, top-right # self.triStrips.addConsecutiveVertices(row + 3, 1) # self.triStrips.addConsecutiveVertices(row - verts + 3, 1) # self.triStrips.addConsecutiveVertices(row + 2, 1) # self.triStrips.addConsecutiveVertices(row - verts + 2, 1) # # RIGHT: new-bottom-right, bottom-right # self.triStrips.addConsecutiveVertices(row + 1, 1) # self.triStrips.addConsecutiveVertices(row - verts + 1, 1) # # BOTTOM: new-bottom-left, bottom-left # self.triStrips.addConsecutiveVertices(row, 1) # self.triStrips.addConsecutiveVertices(row - verts, 1) # # LEFT: new top-left, top-left # self.triStrips.addConsecutiveVertices(row + 3, 1) # self.triStrips.addConsecutiveVertices(row - verts + 3, 1) # TOP: new-top-left, top-left, new-top-right, top-right self.triStrips.addConsecutiveVertices(row - verts + 3, 1) self.triStrips.addConsecutiveVertices(row + 3, 1) self.triStrips.addConsecutiveVertices(row - verts + 2, 1) self.triStrips.addConsecutiveVertices(row + 2, 1) # RIGHT: new-bottom-right, bottom-right self.triStrips.addConsecutiveVertices(row - verts + 1, 1) self.triStrips.addConsecutiveVertices(row + 1, 1) # BOTTOM: new-bottom-left, bottom-left self.triStrips.addConsecutiveVertices(row - verts, 1) self.triStrips.addConsecutiveVertices(row, 1) # LEFT: new top-left, top-left self.triStrips.addConsecutiveVertices(row - verts + 3, 1) self.triStrips.addConsecutiveVertices(row + 3, 1) self.triStrips.closePrimitive() return verts * 4 def completeQuadPath(self): self.geomNode.addGeom(self.geom) if self.triStrips.getNumPrimitives() == 0: return floorMesh = CollisionFloorMesh() vertexReader = GeomVertexReader(self.vertexData, 'vertex') tris = self.triStrips.decompose() print "Decomposed prims:", tris.getNumPrimitives() p = 0 for i in range(tris.getNumPrimitives()): v0 = tris.getPrimitiveStart(i) ve = tris.getPrimitiveEnd(i) if v0 < ve: vertexReader.setRow(tris.getVertex(v0)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(tris.getVertex(v0 + 1)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(tris.getVertex(v0 + 2)) floorMesh.addVertex(Point3(vertexReader.getData3f())) floorMesh.addTriangle(p, p + 1, p + 2) p += 3 self.floorCollNode.addSolid(floorMesh) def completeTunnelPath(self): self.geomNode.addGeom(self.geom) if self.triStrips.getNumPrimitives() == 0: return floorMesh = CollisionFloorMesh() vertexReader = GeomVertexReader(self.vertexData, 'vertex') print "Original prims:", self.triStrips.getNumPrimitives() p = 0 for i in range(self.triStrips.getNumPrimitives()): v0 = self.triStrips.getPrimitiveStart(i) ve = self.triStrips.getPrimitiveEnd(i) j = v0 + 4 # add the bottom triangles vertexReader.setRow(self.triStrips.getVertex(j)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(self.triStrips.getVertex(j + 1)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(self.triStrips.getVertex(j + 2)) floorMesh.addVertex(Point3(vertexReader.getData3f())) floorMesh.addTriangle(p, p + 1, p + 2) vertexReader.setRow(self.triStrips.getVertex(j + 3)) floorMesh.addVertex(Point3(vertexReader.getData3f())) floorMesh.addTriangle(p + 1, p + 3, p + 2) p += 4 # this adds every triangle, but is not appropriate for a closed path # tris = self.triStrips.decompose() # print "Decomposed prims:",tris.getNumPrimitives() # p = 0 # for i in range(tris.getNumPrimitives()): # v0 = tris.getPrimitiveStart(i) # ve = tris.getPrimitiveEnd(i) # if v0 < ve: # vertexReader.setRow(tris.getVertex(v0)) # floorMesh.addVertex(Point3(vertexReader.getData3f())) # vertexReader.setRow(tris.getVertex(v0+1)) # floorMesh.addVertex(Point3(vertexReader.getData3f())) # vertexReader.setRow(tris.getVertex(v0+2)) # floorMesh.addVertex(Point3(vertexReader.getData3f())) # floorMesh.addTriangle(p, p+1, p+2) # p += 3 self.floorCollNode.addSolid(floorMesh) def updatePhysics(self, task): pos = self.fpscamera.getPos() self.info.setText("Position: {0}, {1}, {2}".format( int(pos.x * 100) / 100., int(pos.y * 100) / 100., int(pos.z) / 100.)) return task.cont
class RoamingRalphDemo(ShowBase): def __init__(self): # Set up the window, camera, etc. ShowBase.__init__(self) #self.setupCD() # Set the background color to black # self.win.setClearColor((0.6, 0.6, 1.0, 1.0)) # self.fog = Fog('myFog') # self.fog.setColor(0, 0, 0) # self.fog.setExpDensity(.05) # render.setFog(self.fog) # This is used to store which keys are currently pressed. self.keyMap = { "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0, "c":0, "back":0, "space":0} # Post the instructions #self.title = addTitle( # "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)") self.inst1 = addInstructions(0.06, "[ESC]: Quit") self.inst2 = addInstructions(0.12, "[Left Arrow]: Rotate Ralph Left") self.inst3 = addInstructions(0.18, "[Right Arrow]: Rotate Ralph Right") self.inst4 = addInstructions(0.24, "[Up Arrow]: Run Ralph Forward") #self.inst6 = addInstructions(0.30, "[A]: Rotate Camera Left") #self.inst7 = addInstructions(0.36, "[S]: Rotate Camera Right") # Set up the environment # # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("models/world") #self.environ.reparentTo(render) self.room = loader.loadModel("models/room2.egg") self.room.reparentTo(render) #self.room.setScale(.1) self.room.setPos(0,0,-5) self.room.setShaderAuto() #self.room.writeBamFile("myRoom1.bam") #self.room.setColor(1,.3,.3,1) self.room2 = loader.loadModel("models/abstractroom2") self.room2.reparentTo(render) self.room2.setScale(.1) self.room2.setPos(-12,0,0) # Create the main character, Ralph #ralphStartPos = LVecBase3F(0,0,0) #self.room.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(0,0,0) #cs = CollisionSphere(0, 0, 0, 1) #cnodePath = self.ralph.attachNewNode(CollisionNode('cnode')) #cnodePath.node().addSolid(cs) #cnodePath.node().setPos(0,0,0) #cnodePath.show() self.gianteye = loader.loadModel("models/gianteye") self.gianteye.reparentTo(render) self.gianteye.setScale(.1) self.gianteye.setPos(10,10,0) #self.bluefinal = loader.loadModel("models/chrysalis") #self.bluefinal.reparentTo(render) #self.bluefinal.setScale(.1) #self.bluefinal.setPos(7,7,0) #self.blue = loader.loadModel("models/blue1") #self.blue.reparentTo(render) #self.blue.setScale(.1) #self.blue.setPos(10,5,0) self.chik = loader.loadModel("models/chik") self.chik.reparentTo(render) self.chik.setScale(.1) self.chik.setPos(3,13,0) self.pawn = loader.loadModel("pawn") self.pawn.reparentTo(render) self.pawn.setPos(0,0,0) self.shot = loader.loadModel("models/icosphere.egg") self.shot.reparentTo(render) self.shot.setScale(.5) self.shot.setPos(0,0,1) self.shot.setColor(1,.3,.3,1) self.myShot = loader.loadModel("models/icosphere.egg") #self.myShot.reparentTo(render) self.myShot.setScale(.1) self.myShot.setPos(0,0,1) self.myShotVec = LVector3(0,0,0) self.lightpivot3 = render.attachNewNode("lightpivot3") self.lightpivot3.setPos(0, 0, 0) self.lightpivot3.hprInterval(10, LPoint3(0, 0, 0)).loop() plight3 = PointLight('plight2') plight3.setColor((0, .3,0, 1)) plight3.setAttenuation(LVector3(0.7, 0.05, 0)) plnp3 = self.lightpivot3.attachNewNode(plight3) plnp3.setPos(0, 0, 0) self.room2.setLight(plnp3) self.room.setLight(plnp3) sphere3 = loader.loadModel("models/icosphere") sphere3.reparentTo(plnp3) sphere3.setScale(0.1) sphere3.setColor((0,1,0,1)) # 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(8.0) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left", True]) self.accept("arrow_right", self.setKey, ["right", True]) self.accept("arrow_up", self.setKey, ["forward", True]) self.accept("arrow_down", self.setKey, ["back", True]) self.accept("a", self.setKey, ["cam-left", True]) self.accept("s", self.setKey, ["cam-right", True]) self.accept("arrow_left-up", self.setKey, ["left", False]) self.accept("arrow_right-up", self.setKey, ["right", False]) self.accept("arrow_up-up", self.setKey, ["forward", False]) self.accept("arrow_down-up", self.setKey, ["back", False]) self.accept("a-up", self.setKey, ["cam-left", False]) self.accept("s-up", self.setKey, ["cam-right", False]) self.accept("space", self.setKey, ["space", True]) self.accept("space-up", self.setKey, ["space", False]) self.accept("c",self.setKey,["c",True]) self.accept("c-up",self.setKey,["c",False]) taskMgr.add(self.move, "moveTask") # Game state variables self.isMoving = False self.jumping = False self.vz = 0 # Set up the camera self.disableMouse() self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 7, 3) self.camLens.setFov(60) # 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. def setupCollision(self): cs = CollisionSphere(0,0,2,1) cnodePath = self.ralph.attachNewNode(CollisionNode('cnode')) cnodePath.node().addSolid(cs) cnodePath.show() #for o in self.OBS: #ct = CollisionTube(0,0,0, 0,0,1, 0.5) #cn = o.attachNewNode(CollisionNode('ocnode')) #cn.node().addSolid(ct) #cn.show() eyecs = CollisionSphere(0,0,4,5) cnodePath = self.gianteye.attachNewNode(CollisionNode('cnode')) cnodePath.node().addSolid(eyecs) cnodePath.show() eyecs = CollisionSphere(0,0,4,2) cnodePath = self.chik.attachNewNode(CollisionNode('cnode')) cnodePath.node().addSolid(eyecs) cnodePath.show() pusher = CollisionHandlerPusher() pusher.addCollider(cnodePath, self.player) self.cTrav = CollisionTraverser() self.cTrav.add_collider(cnodePath,pusher) self.cTrav.showCollisions(render) self.walls = self.room2.find("**/wall_collide") #self.walls.node().setIntoCollideMask(BitMask32.bit(0)) self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 9) self.ralphGroundRay.setDirection(0, 0, -1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(CollideMask.bit(0)) self.ralphGroundCol.setIntoCollideMask(CollideMask.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0, 0, 9) self.camGroundRay.setDirection(0, 0, -1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(CollideMask.bit(0)) self.camGroundCol.setIntoCollideMask(CollideMask.allOff()) self.camGroundColNp = self.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) self.sphere = CollisionSphere(0,0,4,2) self.sphere2 = CollisionSphere(0,0,2,2) self.cnodePath = self.ralph.attachNewNode((CollisionNode('cnode'))) self.cnodePath.node().addSolid(self.sphere) self.cnodePath.node().addSolid(self.sphere2) self.cnodePath.show() self.pusher = CollisionHandlerPusher() self.pusher.addCollider(self.cnodePath, self.ralph) self.cTrav.add_collider(self.cnodePath, self.pusher) self.eyecs = CollisionSphere(0,0,22,25) self.cnodePath1 = self.gianteye.attachNewNode(CollisionNode('cnode')) self.cnodePath1.node().addSolid(self.eyecs) self.cnodePath1.show() self.pusher1 = CollisionHandlerPusher() self.pusher1.addCollider(self.cnodePath1, self.gianteye) self.cTrav.add_collider(self.cnodePath1, self.pusher1) self.cTrav.showCollisions(render) self.eyeGroundRay = CollisionRay() self.eyeGroundRay.setOrigin(0, 0, 9) self.eyeGroundRay.setDirection(0, 0, -1) self.eyeGroundCol = CollisionNode('eyeRay') self.eyeGroundCol.addSolid(self.eyeGroundRay) self.eyeGroundCol.setFromCollideMask(CollideMask.bit(0)) self.eyeGroundCol.setIntoCollideMask(CollideMask.allOff()) self.eyeGroundColNp = self.gianteye.attachNewNode(self.eyeGroundCol) self.eyeGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.eyeGroundColNp, self.eyeGroundHandler) self.chikcs = CollisionSphere(0,0,11,20) self.cnodePath2 = self.chik.attachNewNode(CollisionNode('cnode')) self.cnodePath2.node().addSolid(self.chikcs) self.cnodePath2.show() self.pusher2 = CollisionHandlerPusher() self.pusher2.addCollider(self.cnodePath, self.chik) self.cTrav.add_collider(self.cnodePath, self.pusher2) self.cTrav.showCollisions(render) self.chikGroundRay = CollisionRay() self.chikGroundRay.setOrigin(0, 0, 9) self.chikGroundRay.setDirection(0, 0, -1) self.chikGroundCol = CollisionNode('chikRay') self.chikGroundCol.addSolid(self.chikGroundRay) self.chikGroundCol.setFromCollideMask(CollideMask.bit(0)) self.chikGroundCol.setIntoCollideMask(CollideMask.allOff()) self.chikGroundColNp = self.chik.attachNewNode(self.chikGroundCol) self.chikGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.chikGroundColNp, self.chikGroundHandler) # Uncomment this line to see the collision rays self.ralphGroundColNp.show() self.camGroundColNp.show() #self.ralphroom1ColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring #self.cTrav.showCollisions(render) # Create some lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.3, .3, .3, .4)) ambientLight2 = AmbientLight("ambientLight2") ambientLight2.setColor((1, 1, 1, 10)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection((0, 0, -2)) directionalLight.setColor((1, 1, 1, 1)) directionalLight.setSpecularColor((1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) #self.environ.setLight(self.environ.attachNewNode(ambientLight2)) render.setLight(render.attachNewNode(directionalLight)) # Add a light to the scene. self.lightpivot = render.attachNewNode("lightpivot") self.lightpivot.setPos(0, 0, 1.6) self.lightpivot.hprInterval(20, LPoint3(360, 0, 0)).loop() plight = PointLight('plight') plight.setColor((.7, .3, 0, 1)) plight.setAttenuation(LVector3(0.7, 0.05, 0)) plnp = self.lightpivot.attachNewNode(plight) plnp.setPos(5, 0, 0) self.room.setLight(plnp) sphere = loader.loadModel("models/icosphere") sphere.reparentTo(plnp) sphere.setScale(0.1) sphere.setColor((1,1,0,1)) self.lightpivot2 = render.attachNewNode("lightpivot") self.lightpivot2.setPos(-16, 0, 1.6) self.lightpivot2.hprInterval(20, LPoint3(360, 0, 0)).loop() plight2 = PointLight('plight2') plight2.setColor((0, .4,.8, 1)) plight2.setAttenuation(LVector3(0.7, 0.05, 0)) plnp2 = self.lightpivot2.attachNewNode(plight2) plnp2.setPos(5, 0, 0) self.room2.setLight(plnp2) sphere2 = loader.loadModel("models/icosphere") sphere2.reparentTo(plnp2) sphere2.setScale(0.2) sphere2.setColor((0,0,1,1)) self.vec = LVector3(0,1,0) # 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.setZ(self.camera, -20 * dt) if self.keyMap["cam-right"]: self.camera.setZ(self.camera, +20 * dt) # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if self.keyMap["left"]: self.ralph.setH(self.ralph.getH() + 150 * dt) #self.floater.setH(self.floater.getH() + 300 * dt) self.camera.setX(self.camera, +15.5 * dt) if self.keyMap["right"]: self.ralph.setH(self.ralph.getH() - 150 * dt) self.camera.setX(self.camera, -15.5 * dt) if self.keyMap["forward"]: self.ralph.setY(self.ralph, -35 * dt) if self.keyMap["back"]: self.ralph.setY(self.ralph, +35 * dt) if self.keyMap["c"]: if self.jumping is False: #self.ralph.setH(self.ralph.getH() + 300 * dt) #self.ralph.setZ(self.ralph.getZ() + 100 * dt) self.jumping = True self.vz = 7 if self.keyMap["space"]: self.lightpivot3.setPos(self.ralph.getPos()) self.lightpivot3.setZ(self.ralph.getZ() + .5) self.lightpivot3.setX(self.ralph.getX() - .25) #self.myShot.setHpr(self.ralph.getHpr()) #parent node = NodePath("tmp") node.setHpr(self.ralph.getHpr()) vec = render.getRelativeVector(node,(0,-1,0)) self.myShotVec = vec self.lightpivot3.setPos(self.lightpivot3.getPos() + self.myShotVec * dt * 15 ) if self.jumping is True: self.vz = self.vz - 16* dt self.ralph.setZ(self.ralph.getZ() + self.vz * dt ) entries = list(self.ralphGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0 : if self.ralph.getZ() < 0:#entries[0].getSurfacePoint(render).getZ(): #self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) self.ralph.setZ(0) self.jumping = False # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if self.keyMap["forward"] or self.keyMap["left"] or self.keyMap["right"] or self.keyMap["c"] or self.keyMap["forward"] or self.keyMap["back"]: if self.isMoving is False: self.ralph.loop("run") self.isMoving = True else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False node = NodePath("tmp") node.setHpr(self.ralph.getHpr()) vec = render.getRelativeVector(node,(1,0,0)) #self.ralph.setPos(self.ralph.getPos() + vec * dt * 20) node = NodePath("tmp") #self.pawn.getH() node.setHpr(self.pawn.getHpr()) vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0)) self.shot.setPos(self.shot.getPos() + self.vec * dt * 10 ) if self.shot.getY() < -15 or self.shot.getY() > 15 or self.shot.getX() < -15 or self.shot.getX() > 15: self.shot.setPos(self.pawn.getPos() + (0,0,0)) self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0)) self.vec = render.getRelativeVector(node,(random.random() * -0.8,random.random() + 1,0)) # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. camvec = self.ralph.getPos() - self.camera.getPos() #camvec.setZ(self.camera.getZ()) camdist = camvec.length() x = self.camera.getZ() camvec.normalize() if camdist > 6.0: self.camera.setPos(self.camera.getPos() + camvec * (camdist - 6)) camdist = 10.0 #self.camera.setZ(self.camera, x) if camdist < 6.0: self.camera.setPos(self.camera.getPos() - camvec * (6 - camdist)) camdist = 5.0 #self.camera.setZ(self.camera, x) # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. #self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = list(self.ralphGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if self.jumping == False: if len(entries) > 0:# and entries[0].getIntoNode().getName() == "terrain": #self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) pass else: self.ralph.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. entries = list(self.camGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) #if len(entries) > 0 and entries[0].getIntoNode().getName() == "ground": #self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.5) if self.camera.getZ() < self.ralph.getZ() + 1 or self.camera.getZ() > self.ralph.getZ() + 1: self.camera.setZ(self.ralph.getZ() + 1) #self.camera.setZ(self.ralph.getZ() + 1.5) #self.camera.setP(self.camera, 130) # The camera should look in ralph's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above ralph's head. self.camera.lookAt(self.floater) return task.cont
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.disableMouse() camera.setPosHpr(0, -12, 8, 0, -35, 0) """ self.environ = self.loader.loadModel("models/environment") # Reparent the model to render. self.environ.reparentTo(self.render) # Apply scale and position transforms on the model. self.environ.setScale(0.25, 0.25, 0.25) self.environ.setPos(-8, 42, 0) self.torus = loader.loadModel("torus.egg") self.torus.reparentTo(self.render) self.torus.setPos(circPos(0,1)) self.torus.setColor(BLACK) self.torus.setScale(0.5,0.5,0.5) """ self.setupLights() self.ended = False self.currentB = False self.firstTurn = True # 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 # Add it to the collision node self.pickerNode.addSolid(self.pickerRay) # Register the ray as something that can cause collisions self.picker.addCollider(self.pickerNP, self.pq) self.picker.showCollisions(render) self.whiteTurn = True # 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.batonsRoot = render.attachNewNode("batonsRoot") self.batons = [None for i in range(9)] self.torus = [[None for j in range(3)] for i in range(9)] self.org = [[[None for j in range(3)] for i in range(3)] for i in range(3)] for i in range(9): # Load, parent, color, and position the model (a single square # polygon) self.batons[i] = loader.loadModel("bois.egg") self.batons[i].reparentTo(self.batonsRoot) self.batons[i].setPos(circPos(i,0)) self.batons[i].setColor(0.75,0.5,0) self.batons[i].setScale(0.75,0.75,0.5) # 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.batons[i].find("**/Cylinder").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.batons[i].find("**/Cylinder").setTag('baton', str(i)) # We will use this variable as a pointer to whatever piece is currently # in this square self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask') self.accept("mouse1", self.click) self.accept("w", self.bestPossibleMove) def setupLights(self): # This function sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.8, .8, .8, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(LVector3(0, 45, -45)) directionalLight.setColor((0.2, 0.2, 0.2, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight)) def mouseTask(self, task): # 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.mouseWatcherNode.hasMouse(): # get the mouse position mpos = self.mouseWatcherNode.getMouse() # Set the position of the ray based on the mouse position self.pickerRay.setFromLens(self.camNode, mpos.getX(), mpos.getY()) if self.currentB is not False: self.batons[self.currentB].setColor(0.75,0.5,0) self.currentB = False # Do the actual collision pass (Do it only on the squares for # efficiency purposes) self.picker.traverse(self.batonsRoot) 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() self.currentB = int(self.pq.getEntry(0).getIntoNode().getTag('baton')) # Set the highlight on the picked square self.batons[self.currentB].setColor(HIGHLIGHT) self.currentB return Task.cont def click(self): if self.currentB is not False and not self.ended: self.addTorus(self.currentB) def testMorp(self, z, y, x): print(z,y,x) print([j for j in [self.org[w][y][w]for w in range(3)]if j == None]) print([j for j in [self.org[w][y][w]for w in range(3)]if j == False]) print(len([j for j in [self.org[w][y][w]for w in range(3)]if j == False])) if len([j for j in self.org[z][y] if j == None]) == 0: if len([j for j in self.org[z][y] if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in self.org[z][y] if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[z][w][x]for w in range(3)] if j == None]) == 0: if len([j for j in [self.org[z][w][x]for w in range(3)] if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[z][w][x]for w in range(3)] if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[w][y][x]for w in range(3)] if j==None]) == 0: if len([j for j in [self.org[w][y][x]for w in range(3)] if j==False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[w][y][x]for w in range(3)] if j==True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[z][w][w]for w in range(3)]if j == None]) == 0: if len([j for j in [self.org[z][w][w]for w in range(3)]if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[z][w][w]for w in range(3)]if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[z][w][2 - w]for w in range(3)]if j == None]) == 0: if len([j for j in [self.org[z][w][2 - w]for w in range(3)]if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[z][w][2 - w]for w in range(3)]if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[w][w][x]for w in range(3)]if j == None]) == 0: if len([j for j in [self.org[w][w][x]for w in range(3)]if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[w][w][x]for w in range(3)]if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[w][2-w][x]for w in range(3)]if j == None]) == 0: if len([j for j in [self.org[w][2-w][x]for w in range(3)]if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[w][2-w][x]for w in range(3)]if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[w][y][w]for w in range(3)]if j == None]) == 0: print("wyw") if len([j for j in [self.org[w][y][w]for w in range(3)]if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[w][y][w]for w in range(3)]if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[2-w][y][w]for w in range(3)]if j == None]) == 0: if len([j for j in [self.org[2-w][y][w]for w in range(3)]if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[2-w][y][w]for w in range(3)]if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[w][w][w]for w in range(3)]if j == None]) == 0: if len([j for j in [self.org[w][w][w]for w in range(3)]if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[w][w][w]for w in range(3)]if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[2-w][w][w]for w in range(3)]if j == None]) == 0: if len([j for j in [self.org[2-w][w][w]for w in range(3)]if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[2-w][w][w]for w in range(3)]if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[w][w][2-w]for w in range(3)]if j == None]) == 0: if len([j for j in [self.org[w][w][2-w]for w in range(3)]if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[w][w][2-w]for w in range(3)]if j == True]) == 0: self.ended = True return "blackWin" if len([j for j in [self.org[2-w][w][2-w]for w in range(3)]if j == None]) == 0: if len([j for j in [self.org[2-w][w][2-w]for w in range(3)]if j == False]) == 0: self.ended = True return "whiteWin" elif len([j for j in [self.org[2-w][w][2-w]for w in range(3)]if j == True]) == 0: self.ended = True return "blackWin" return "launched" def addTorus(self, i): minim = False for j,x in enumerate(self.torus[i]): if x is None: minim = j break if minim is not False: print(minim) print(self.whiteTurn) print() if (self.whiteTurn and not self.firstTurn) or (self.firstTurn and not (minim == 0 and i//3 == 1 and i%3 == 1)): self.torus[i][minim] = loader.loadModel("torus.egg") self.torus[i][minim].reparentTo(self.render) self.torus[i][minim].setPos(circPos(i,j-1)) self.torus[i][minim].setColor(WHITE) self.torus[i][minim].setScale(0.75,0.75,1.5) self.org[minim][i//3][i%3] = self.whiteTurn self.whiteTurn = not self.whiteTurn if self.firstTurn: self.firstTurn = False elif not self.firstTurn: self.torus[i][minim] = loader.loadModel("torus.egg") self.torus[i][minim].reparentTo(self.render) self.torus[i][minim].setPos(circPos(i,j-1)) self.torus[i][minim].setColor(BLACK) self.torus[i][minim].setScale(0.75,0.75,1.5) self.org[minim][i//3][i%3] = self.whiteTurn self.whiteTurn = not self.whiteTurn print(self.testMorp(minim, i//3, i%3)) def possibleMoves(self, state, first): possibilities = [] for r in range(9): if (((r is not 4) and first) or (not first)) and state[2][r//3][r%3] == None: possibilities.append(r) return possibilities def bestPossibleMove(self): temp = state for p in possibleMoves(self, state, first): p = 0 def valeurBranche(self, state, first, Wturn, n): vblancs = 0 vnoirs = 0 pos = [None for p in possibleMoves(self, state, first) ] depth = pos for i,p in enumerate(possibleMoves(self, state, first)): tempEtat = addTorustemp(p, WTurn, state) temp = testMorptemp(tempEtat) if temp == 1 and Wturn: pos[i] = 1 depth[i] = n + 1 elif temp ==0 and Wturn: if first: temp2 = valeurBranche(self, temp,not first, not Wturn,n+1) if not (temp2[0] == 0): pos[i] = -temp2[0] depth[i] = temp2[1] else: pos[i] = 0 depth[i] = temp2[1] else: temp2 = valeurBranche(self, temp, first, not Wturn,n+1) if not (temp2[0] == 0): pos[i] = -temp2[0] depth[i] = temp2[1] else : pos[i] = 0 depth[i] = temp2[1] elif temp == 2 and (not Wturn): pos[i] = 1 elif temp ==0 and (not Wturn): if first: temp2 = valeurBranche(self, temp,not first, not Wturn,n+1) if not (temp2[0] == 0): pos[i] = -temp2[0] depth[i] = temp2[1] else: pos[i] = 0 depth[i] = temp2[1] else: temp2 = valeurBranche(self, temp, first, not Wturn,n+1) if not (temp2[0] == 0): pos[i] = -temp2[0] depth[i] = temp2[1] else : pos[i] = 0 depth[i] = temp2[1] else: print("tu sais pas coder guillaume") if pos == []: return (0, n) else: vic = [] zero = [] for i,j in enumerate(pos): if j == 1: vic.append(i) elif j == 0: zero.append(i) if vic is not []: return 1, n elif zero is not []: dmax = 0 for i in zero: if depth[i] > dmax: dmax = depth[i] return 0, dmax else: return -1, n def addTorustemp(self, i, whiteTurn, state): minim = False temp = state for j,x in enumerate([state[w][i//3][i%3] for w in range(3)]): if x is None: minim = j break if minim is not False: print(minim) print(whiteTurn) temp[minim][i//3][i%3] = whiteTurn return temp def testMorptemp(self, torg): for m in range(27): z = m//9 y = m//3 x = m%3 if len([j for j in torg[z][y] if j == None]) == 0: if len([j for j in torg[z][y] if j == False]) == 0: return 1 elif len([j for j in torg[z][y] if j == True]) == 0: return 2 if len([j for j in [torg[z][w][x]for w in range(3)] if j == None]) == 0: if len([j for j in [torg[z][w][x]for w in range(3)] if j == False]) == 0: return 1 elif len([j for j in [torg[z][w][x]for w in range(3)] if j == True]) == 0: return 2 if len([j for j in [torg[w][y][x]for w in range(3)] if j==None]) == 0: if len([j for j in [torg[w][y][x]for w in range(3)] if j==False]) == 0: return 1 elif len([j for j in [torg[w][y][x]for w in range(3)] if j==True]) == 0: return 2 if len([j for j in [torg[z][w][w]for w in range(3)]if j == None]) == 0: if len([j for j in [torg[z][w][w]for w in range(3)]if j == False]) == 0: return 1 elif len([j for j in [torg[z][w][w]for w in range(3)]if j == True]) == 0: return 2 if len([j for j in [torg[z][w][2 - w]for w in range(3)]if j == None]) == 0: if len([j for j in [torg[z][w][2 - w]for w in range(3)]if j == False]) == 0: return 1 elif len([j for j in [torg[z][w][2 - w]for w in range(3)]if j == True]) == 0: return 2 if len([j for j in [torg[w][w][x]for w in range(3)]if j == None]) == 0: if len([j for j in [torg[w][w][x]for w in range(3)]if j == False]) == 0: return 1 elif len([j for j in [torg[w][w][x]for w in range(3)]if j == True]) == 0: return 2 if len([j for j in [torg[w][2-w][x]for w in range(3)]if j == None]) == 0: if len([j for j in [torg[w][2-w][x]for w in range(3)]if j == False]) == 0: return 1 elif len([j for j in [torg[w][2-w][x]for w in range(3)]if j == True]) == 0: return 2 if len([j for j in [torg[w][y][w]for w in range(3)]if j == None]) == 0: if len([j for j in [torg[w][y][w]for w in range(3)]if j == False]) == 0: return 1 elif len([j for j in [torg[w][y][w]for w in range(3)]if j == True]) == 0: return 2 if len([j for j in [torg[2-w][y][w]for w in range(3)]if j == None]) == 0: if len([j for j in [torg[2-w][y][w]for w in range(3)]if j == False]) == 0: return 1 elif len([j for j in [torg[2-w][y][w]for w in range(3)]if j == True]) == 0: return 2 if len([j for j in [torg[w][w][w]for w in range(3)]if j == None]) == 0: if len([j for j in [torg[w][w][w]for w in range(3)]if j == False]) == 0: return 1 elif len([j for j in [torg[w][w][w]for w in range(3)]if j == True]) == 0: return 2 if len([j for j in [torg[2-w][w][w]for w in range(3)]if j == None]) == 0: if len([j for j in [torg[2-w][w][w]for w in range(3)]if j == False]) == 0: return 1 elif len([j for j in [torg[2-w][w][w]for w in range(3)]if j == True]) == 0: return 2 if len([j for j in [torg[w][w][2-w]for w in range(3)]if j == None]) == 0: if len([j for j in [torg[w][w][2-w]for w in range(3)]if j == False]) == 0: return 1 elif len([j for j in [torg[w][w][2-w]for w in range(3)]if j == True]) == 0: return 2 if len([j for j in [torg[2-w][w][2-w]for w in range(3)]if j == None]) == 0: if len([j for j in [torg[2-w][w][2-w]for w in range(3)]if j == False]) == 0: return 1 elif len([j for j in [torg[2-w][w][2-w]for w in range(3)]if j == True]) == 0: return 2 return 0
class Game(DirectObject): def __init__(self, model): self.model = model base.setBackgroundColor(0.1, 0.1, 0.8, 1) base.setFrameRateMeter(True) base.cam.setPos(0, -20, 4) base.cam.lookAt(0, 0, 0) w = WindowProperties() w.setFullscreen(False) w.setOrigin(5, 20) w.setSize(865, 800) base.win.requestProperties(w) # Light alight = AmbientLight('ambientLight') alight.setColor(Vec4(0.5, 0.5, 0.5, 1)) alightNP = render.attachNewNode(alight) dlight = DirectionalLight('directionalLight') dlight.setDirection(Vec3(1, 1, -1)) dlight.setColor(Vec4(0.7, 0.7, 0.7, 1)) dlightNP = render.attachNewNode(dlight) render.clearLight() render.setLight(alightNP) render.setLight(dlightNP) # Input self.accept('escape', self.doExit) self.accept('r', self.doReset) self.accept('f1', self.toggleWireframe) self.accept('f2', self.toggleTexture) self.accept('f3', self.toggleDebug) self.accept('f5', self.doScreenshot) inputState.watchWithModifiers('forward', 'w') inputState.watchWithModifiers('left', 'a') inputState.watchWithModifiers('reverse', 's') inputState.watchWithModifiers('right', 'd') inputState.watchWithModifiers('turnLeft', 'q') inputState.watchWithModifiers('turnRight', 'e') # Task taskMgr.add(self.update, 'updateWorld') # Physics self.setup() # _____HANDLER_____ def doExit(self): self.cleanup() sys.exit(1) def endLoop(self): self.penalized_distance = self.distance * (numpy.exp( -self.time_max_steering / self.total_time)) pickle.dump(self.penalized_distance, open('distance.p', 'wb')) sys.exit() #quit() #print("Distance was: ",self.distance) #os.execv(sys.executable,['python']+[__file__]) #taskMgr.running = False def doReset(self): self.cleanup() self.setup() def toggleWireframe(self): base.toggleWireframe() def toggleTexture(self): base.toggleTexture() def toggleDebug(self): if self.debugNP.isHidden(): self.debugNP.show() else: self.debugNP.hide() def doScreenshot(self): base.screenshot('Bullet') # ____TASK___ def calculate_moves(self): self.y = self.model.predict(self.x) #print(self.y) self.moves = self.y > 0 #+ self.model_offset # 0.5 #self.moves[0] = True # FIXME test def processInput(self, dt): engineForce = 0.0 brakeForce = 0.0 if self.moves[ 0]: #inputState.isSet('forward'): FIXME maybe engine and brake can be linked to self.y, rectified, continuous engineForce = 2000.0 # 1000. brakeForce = 0.0 if not self.moves[0]: #inputState.isSet('reverse'): engineForce = 200.0 #0.0 brakeForce = 100.0 self.steering = self.y[1] if self.moves[1]: self.steering = min(self.steering, self.steeringClamp) if not self.moves[1]: self.steering = max(self.steering, -self.steeringClamp) """ # FIXME option may be better if self.steering is fed into self.y[3] for 4th element if not self.moves[2]: # enabled steering lock if self.moves[1]:#inputState.isSet('turnLeft'): self.steering += dt * self.steeringIncrement self.steering = min(self.steering, self.steeringClamp) if not self.moves[1]:#inputState.isSet('turnRight'): self.steering -= dt * self.steeringIncrement self.steering = max(self.steering, -self.steeringClamp) """ """ if inputState.isSet('forward'): engineForce = 1000.0 brakeForce = 0.0 if inputState.isSet('reverse'): engineForce = 0.0 brakeForce = 100.0 if inputState.isSet('turnLeft'): self.steering += dt * self.steeringIncrement self.steering = min(self.steering, self.steeringClamp) if inputState.isSet('turnRight'): self.steering -= dt * self.steeringIncrement self.steering = max(self.steering, -self.steeringClamp) """ # Apply steering to front wheels self.vehicle.setSteeringValue(self.steering, 0) self.vehicle.setSteeringValue(self.steering, 1) # Apply engine and brake to rear wheels self.vehicle.applyEngineForce(engineForce, 2) self.vehicle.applyEngineForce(engineForce, 3) self.vehicle.setBrake(brakeForce, 2) self.vehicle.setBrake(brakeForce, 3) def check_collisions(self): """pFrom = render.getRelativePoint(self.yugoNP,Point3(0,0,0))#Point3(0,0,0) pFrom -= Point3(0,0,pFrom[2]) pRel = render.getRelativePoint(base.cam,self.yugoNP.getPos()) # FIXME THIS IS IT!! get rid of z component pRel -= Point3(0,0,pRel[2]) p45 = Point3(pRel[0] - pRel[1], pRel[1] + pRel[0],0) pn45 = Point3(pRel[0] + pRel[1], pRel[1] - pRel[0],0) #print(render.getRelativePoint(self.yugoNP,Point3(0,0,0))) #print(dir(self.yugoNP)) pTo = [pFrom + pn45, pFrom + pRel, pFrom + p45]#[pFrom + Vec3(-10,10,0)*999,pFrom + Vec3(0,10,0)*999,pFrom + Vec3(10,10,0)*999]# FIXME should be relative to front of car, getting cloe! #self.yugoNP.getPosDelta()*99999]#[Point3(-10,10,0) * 99999,Point3(0,10,0) * 99999,Point3(10,10,0) * 99999] #self.ray = CollisionRay(0,0,0,100,0,0) result = [self.world.rayTestClosest(pFrom,pt) for pt in pTo] #print(dir(self.yugoNP)) #print(result.getHitPos()) return tuple([res.getHitPos().length() for res in result]) """#queue = CollisionHandlerQueue() #traverser.addCollider(fromObject, queue) #traverser.traverse(render) #queue.sortEntries() #for entry in queue.getEntries(): #print(entry) #print(result.getHitPos()) #if result.getNode() != None: #print(self.yugoNP.getPos(result.getNode())) #print(self.cTrav) self.cTrav.traverse(render) entries = list(self.colHandler.getEntries()) #print(entries) entries.sort(key=lambda y: y.getSurfacePoint(render).getY()) #for entry in entries: print(entry.getFromNodePath().getName()) if entries: # and len(result) > 1: #print(entries) for r in entries: #print(r.getIntoNodePath().getName()) if r.getIntoNodePath().getName( ) == 'Plane' and r.getFromNodePath().getName() == 'yugo_box': self.endLoop() if r.getIntoNodePath().getName( ) == 'Plane' and r.getFromNodePath().getName() in [ 'ray%d' % i for i in range(self.n_rays) ]: #Box self.ray_col_vec_dict[ r.getFromNodePath().getName()].append( numpy.linalg.norm( list(r.getSurfacePoint( r.getFromNodePath()))[:-1])) self.ray_col_vec_dict = { k: (min(self.ray_col_vec_dict[k]) if len(self.ray_col_vec_dict[k]) >= 1 else 10000) for k in self.ray_col_vec_dict } self.x = numpy.array(list(self.ray_col_vec_dict.values())) #print(self.x) result = self.world.contactTest(self.yugoNP.node()) #print(result.getNumContacts()) #print(dir(self.yugoNP)) #return entries def check_prevPos(self): if len(self.prevPos) > 80: #print(self.prevPos) #print(numpy.linalg.norm(self.prevPos[-1] - self.prevPos[0])) if numpy.linalg.norm(self.prevPos[-1] - self.prevPos[0]) < 4.5: #print("ERROR") self.endLoop() del self.prevPos[0:len(self.prevPos) - 80] def update(self, task): self.prevPos.append(self.yugoNP.getPos(render)) dx = numpy.linalg.norm(self.prevPos[-1] - self.prevPos[-2]) self.distance += dx self.distance_text.setText('Distance=%.3f' % (self.distance)) #print(len(self.prevPos)) dt = globalClock.getDt() self.total_time += dt if abs(self.steering) == abs(self.steeringClamp): self.time_max_steering += dt self.time_text.setText('TotalTime=%.3f' % (self.total_time)) #self.time_maxsteer_text.setText('TotalTimeMaxSteer=%f'%(self.time_max_steering)) #self.penalized_distance = self.distance*(1.-numpy.exp(-self.time_max_steering/self.total_time)) if self.distance > 10000: self.endLoop() self.check_prevPos() self.speed = dx / dt self.speed_text.setText('Speed=%.3f' % (self.speed)) self.check_collisions() self.calculate_moves() self.model.plot_NN() #self.nn_image.setImage('neural_net_vis.png') self.ray_col_vec_dict = {k: [] for k in self.ray_col_vec_dict} self.processInput(dt) self.world.doPhysics(dt, 10, 0.008) # FIXME KEEP TRACK OF TOTAL DEGREES TURNED AND PENALIZE #self.doReset() #print(dir(result[1])) #print(numpy.linalg.norm(list(result[1].getSurfacePoint(result[1].getFromNodePath()))[:-1])) #base.camera.setPos(0,-40,10) #print self.vehicle.getWheel(0).getRaycastInfo().isInContact() #print self.vehicle.getWheel(0).getRaycastInfo().getContactPointWs() #print self.vehicle.getChassis().isKinematic() return task.cont def cleanup(self): self.world = None self.worldNP.removeNode() def setup(self): self.worldNP = render.attachNewNode('World') self.distance_text = OnscreenText( text='Distance=0', pos=(0.75, 0.85), scale=0.08, mayChange=1) #Directxxxxxx(distance='Distance=%d'%(0)) self.speed_text = OnscreenText( text='Speed=0', pos=(0.75, 0.78), scale=0.08, mayChange=1) #Directxxxxxx(distance='Distance=%d'%(0)) self.time_text = OnscreenText( text='TotalTime=0', pos=(0.75, 0.71), scale=0.08, mayChange=1) #Directxxxxxx(distance='Distance=%d'%(0)) #self.time_maxsteer_text = OnscreenText(text='TotalTimeMaxSteer=0', pos = (0.85,0.70), scale = 0.05, mayChange=1)#Directxxxxxx(distance='Distance=%d'%(0)) #self.nn_image = OnscreenImage(image='blank.png', pos= (0.85,0,0.15), scale=0.45) # http://dev-wiki.gestureworks.com/index.php/GestureWorksCore:Python_%26_Panda3D:_Getting_Started_II_(Hello_Multitouch)#8._Create_a_method_to_draw_touchpoint_data self.total_time = 0. self.time_max_steering = 0. # World self.debugNP = self.worldNP.attachNewNode(BulletDebugNode('Debug')) self.debugNP.show() self.world = BulletWorld() self.world.setGravity(Vec3(0, 0, -9.81)) self.world.setDebugNode(self.debugNP.node()) #terrain = GeoMipTerrain("mySimpleTerrain") #terrain.setHeightfield("./models/heightfield_2.png") #terrain.getRoot().reparentTo(self.worldNP)#render) #terrain.generate() # Plane shape = BulletPlaneShape(Vec3(0, 0, 1), 0) np = self.worldNP.attachNewNode(BulletRigidBodyNode('Ground')) np.node().addShape(shape) np.setPos(0, 0, -1) np.setCollideMask(BitMask32.allOn()) self.world.attachRigidBody(np.node()) #np = self.worldNP.attachNewNode(BulletRigidBodyNode('Track')) #np.node().setMass(5000.0) #np.setPos(3, 0, 10) #np.setCollideMask(BitMask32.allOn())#(0x0f)) #self.track = BulletVehicle(self.world, np.node()) #self.track.setCoordinateSystem(ZUp) self.track_np = loader.loadModel( 'models/race_track_2.egg' ) # https://discourse.panda3d.org/t/panda3d-and-bullet-physics/15724/10 self.track_np.setPos(-72, -7, -3.5) self.track_np.setScale(10) self.track_np.reparentTo(render) self.track_np.setCollideMask(BitMask32.allOn()) #(0))#.allOn()) self.world.attachRigidBody(np.node()) self.track_np = np #self.track_np.show() # Chassis shape = BulletBoxShape(Vec3(0.6, 1.4, 0.5)) ts = TransformState.makePos(Point3(0, 0, 0.5)) np = self.worldNP.attachNewNode(BulletRigidBodyNode('Vehicle')) np.node().addShape(shape, ts) np.setPos(0, 0, 0.05) np.node().setMass(800.0) np.node().setDeactivationEnabled(False) self.world.attachRigidBody(np.node()) #np.node().setCcdSweptSphereRadius(1.0) #np.node().setCcdMotionThreshold(1e-7) self.cTrav = CollisionTraverser() # Vehicle self.vehicle = BulletVehicle(self.world, np.node()) self.vehicle.setCoordinateSystem(ZUp) self.yugoNP = loader.loadModel('models/yugo/yugo.egg') self.yugoNP.setCollideMask(BitMask32(0)) #.allOn()) self.yugoNP.reparentTo(np) self.colHandler = CollisionHandlerQueue() # travel distance self.distance = 0. """self.sphere = CollisionSphere(0,0,0,2) self.sphere_col = CollisionNode('yugo') self.sphere_col.addSolid(self.sphere) self.sphere_col.setFromCollideMask(BitMask32.allOn()) self.sphere_col_np = self.yugoNP.attachNewNode(self.sphere_col) self.cTrav.addCollider(self.sphere_col_np,self.colHandler) self.sphere_col_np.show()""" self.yugo_col = CollisionNode('yugo_box') self.yugo_col.addSolid(CollisionBox(Point3(0, 0, 0.7), 0.9, 1.6, 0.05)) self.yugo_col.setFromCollideMask(BitMask32(1)) self.box_col_np = self.yugoNP.attachNewNode(self.yugo_col) self.cTrav.addCollider(self.box_col_np, self.colHandler) self.box_col_np.show() self.ray_col_np = {} self.ray_col_vec_dict = {} self.n_rays = self.model.shape[0] for i, ray_dir in enumerate( numpy.linspace(-numpy.pi / 4, numpy.pi / 4, self.n_rays)): # populate collision rays #print(ray_dir) self.ray = CollisionRay() y_dir, x_dir = numpy.cos(ray_dir), numpy.sin(ray_dir) self.ray.setOrigin(1.3 * x_dir, 1.3 * y_dir, 0.5) self.ray.setDirection(x_dir, y_dir, 0) self.ray_col = CollisionNode('ray%d' % (i)) self.ray_col.addSolid(self.ray) self.ray_col.setFromCollideMask( BitMask32.allOn()) #(0x0f))#CollideMask.bit(0) #self.ray_col.setIntoCollideMask(CollideMask.allOff()) self.ray_col_np['ray%d' % (i)] = self.yugoNP.attachNewNode( self.ray_col) self.cTrav.addCollider(self.ray_col_np['ray%d' % (i)], self.colHandler) self.ray_col_np['ray%d' % (i)].show() self.ray_col_vec_dict['ray%d' % (i)] = [] self.world.attachVehicle(self.vehicle) self.cTrav.showCollisions(render) # FIXME base.camera.reparentTo(self.yugoNP) # Right front wheel np = loader.loadModel('models/yugo/yugotireR.egg') np.reparentTo(self.worldNP) self.addWheel(Point3(0.70, 1.05, 0.3), True, np) # Left front wheel np = loader.loadModel('models/yugo/yugotireL.egg') np.reparentTo(self.worldNP) self.addWheel(Point3(-0.70, 1.05, 0.3), True, np) # Right rear wheel np = loader.loadModel('models/yugo/yugotireR.egg') np.reparentTo(self.worldNP) self.addWheel(Point3(0.70, -1.05, 0.3), False, np) # Left rear wheel np = loader.loadModel('models/yugo/yugotireL.egg') np.reparentTo(self.worldNP) self.addWheel(Point3(-0.70, -1.05, 0.3), False, np) # Steering info self.steering = 0.0 # degree self.steeringClamp = 38.0 #45.0 # degree self.steeringIncrement = 105.0 #120.0 # degree per second # add previous positions self.prevPos = [] self.prevPos.append(self.yugoNP.getPos(render)) self.model_offset = 0.5 if self.model.activation == 'relu' else 0. # Box """ for i,j in [(0,8),(-3,5),(6,-5),(8,3),(-4,-4),(0,0)]: shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5)) # https://discourse.panda3d.org/t/wall-collision-help/23606 np = self.worldNP.attachNewNode(BulletRigidBodyNode('Box')) np.node().setMass(1.0) np.node().addShape(shape) np.setPos(i, j, 2) np.setCollideMask(BitMask32.allOn())#(0x0f)) self.world.attachRigidBody(np.node()) self.boxNP = np #self.colHandler2 = CollisionHandlerQueue() visualNP = loader.loadModel('models/box.egg') visualNP.reparentTo(self.boxNP) #self.cTrav.addCollider(self.boxNP,self.colHandler) """ """ aNode = CollisionNode("TheRay") self.ray = CollisionRay() self.ray.setOrigin( self.yugoNP.getPos() ) self.ray.setDirection( Vec3(0, 10, 0) ) #self.ray.show() aNodePath = self.yugoNP.attachNewNode( CollisionNode("TheRay") ) aNodePath.node().addSolid(self.ray) aNodePath.show() """ #aNode.addSolid(self.ray) #self.ray = CollisionRay(0,0,0,10,0,0) #self.ray.reparentTo(self.yugoNP) #self.rayColl = CollisionNode('PlayerRay') #self.rayColl.addSolid(self.ray) #self.playerRayNode = self.yugoNP.attachNewNode( self.rayColl ) #self.playerRayNode.show() #base.myTraverser.addCollider (self.playerRayNode, base.floor) #base.floor.addCollider( self.playerRayNode, self.yugoNP) """ MyEvent=CollisionHandlerFloor() MyEvent.setReach(100) MyEvent.setOffset(15.0) aNode = CollisionNode("TheRay") ray = CollisionRay() ray.setOrigin( self.boxNP.getPos() ) ray.setDirection( Vec3(10, 0, 0) ) aNode.addSolid(ray) aNodePath = MyModel.attachNewNode( aNode ) Collision = ( aNode, "TheRay" ) Collision[0].setFromCollideMask( BitMask32.bit( 1 ) ) """ def addWheel(self, pos, front, np): wheel = self.vehicle.createWheel() wheel.setNode(np.node()) wheel.setChassisConnectionPointCs(pos) wheel.setFrontWheel(front) wheel.setWheelDirectionCs(Vec3(0, 0, -1)) wheel.setWheelAxleCs(Vec3(1, 0, 0)) wheel.setWheelRadius(0.25) wheel.setMaxSuspensionTravelCm(40.0) wheel.setSuspensionStiffness(40.0) wheel.setWheelsDampingRelaxation(2.3) wheel.setWheelsDampingCompression(4.4) wheel.setFrictionSlip(100.0) wheel.setRollInfluence(0.1)
class RoamingRalphDemo(ShowBase): def __init__(self): # Set up the window, camera, etc. ShowBase.__init__(self) # Set the background color to black self.win.setClearColor((0, 0, 0, 1)) # This is used to store which keys are currently pressed. self.keyMap = { "left": 0, "right": 0, "forward": 0, "back": 0, "cam-left": 0, "cam-right": 0} # Post the instructions self.title = addTitle( "Adventurer: 3rd Person File Manager (in progress)") self.inst1 = addInstructions(0.06, "[ESC]: Quit") self.inst2 = addInstructions(0.12, "[Arrows]: Angle Camera") self.inst3 = addInstructions(0.18, "[WASD]: Move") # 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) #loader.unload_model startPos = Point3(0,0,0)#self.environ.find("**/start_point").getPos() # Setup controls self.keys = {} for key in ['arrow_left', 'arrow_right', 'arrow_up', 'arrow_down', 'a', 'd', 'w', 's']: self.keys[key] = 0 self.accept(key, self.push_key, [key, 1]) self.accept('shift-%s' % key, self.push_key, [key, 1]) self.accept('%s-up' % key, self.push_key, [key, 0]) #self.accept('f', self.toggleWireframe) #self.accept('x', self.toggle_xray_mode) #self.accept('b', self.toggle_model_bounds) self.accept('escape', __import__('sys').exit, [0]) self.disableMouse() taskMgr.add(self.update, "moveTask") #insert test features #addCube(models, render, startPos + (0, 1, 0.5), 0.5) #addWall(models, render, startPos + (0, 1, 0.5), 30, 0.2) addDir(render, startPos + (0, 1, 0.5)) # Game state variables self.isMoving = False # Set up the camera self.disableMouse() lens = PerspectiveLens() lens.setFov(60) lens.setNear(0.01) lens.setFar(1000.0) self.cam.node().setLens(lens) self.camera.setPos(startPos) self.heading = -95.0 self.pitch = 0.0 # Add collision to keept he camera in the room cn = CollisionNode('camera') cn.addSolid(CollisionSphere(0, 0, 0, 0.5)) camColl = self.camera.attachNewNode(cn) self.cTrav = CollisionTraverser('camera traverser') self.camGroundHandler = CollisionHandlerPusher() self.camGroundHandler.addCollider(camColl, NodePath(self.camera)) self.cTrav.addCollider(camColl, self.camGroundHandler) # Makes colliding objects show up self.cTrav.showCollisions(render) # Create some lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection((-5, -5, -5)) directionalLight.setColor((1, 1, 1, 1)) directionalLight.setSpecularColor((1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) def push_key(self, key, value): """Stores a value associated with a key.""" self.keys[key] = value def update(self, task): """Updates the camera based on the keyboard input. Once this is done, then the CellManager's update function is called.""" posStart = self.camera.getPos() delta = globalClock.getDt() move_x = delta * SPEED_MOVE * -self.keys['a'] + delta * SPEED_MOVE * self.keys['d'] move_z = delta * SPEED_MOVE * self.keys['s'] + delta * SPEED_MOVE * -self.keys['w'] self.camera.setHpr(self.heading, 0, 0) self.camera.setPos(self.camera, move_x, -move_z, 0) self.heading += (delta * 90 * self.keys['arrow_left'] + delta * 90 * -self.keys['arrow_right']) self.pitch += (delta * 90 * self.keys['arrow_up'] + delta * 90 * -self.keys['arrow_down']) self.camera.setHpr(self.heading, self.pitch, 0) # for entry in self.camGroundHandler.getEntries(): # if entry.getFromNode().getName() == "camera": # print "Collision", posStart, self.camera.getPos() # self.camera.setPos(posStart) # break return task.cont
class Tunnel(ShowBase): def __init__(self): ShowBase.__init__(self) base.disableMouse() self.camera.setPosHpr(0, 0, 10, 0, -90, 0) self.setBackgroundColor(0, 0, 0) self.fog = Fog('distanceFog') self.fog.setColor(0, 0, 0) self.fog.setExpDensity(.08) render.setFog(self.fog) self.keyMap = {'left' : 0, 'right' : 0, 'up' : 0, 'down' : 0} # self.accept('escape', sys.exit) self.accept('arrow_left', self.setKey, ['left', True]) self.accept('arrow_right', self.setKey, ['right', True]) self.accept('arrow_up', self.setKey, ['up', True]) self.accept('arrow_down', self.setKey, ['down', 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, ['up', False]) self.accept('arrow_down-up', self.setKey, ['down', False]) self.queue = CollisionHandlerQueue() self.trav = CollisionTraverser('traverser') base.cTrav = self.trav # self.makeTunnel() self.makeSphere() self.continueTunnel() # self.crystals = [] for _ in xrange(CRYSTALS_CNT): self.makeRandomCrystal(randint(1, TUNNEL_CNT - 1)) self.collisionCnt = 0 # taskMgr.add(self.moveSphere, 'moveSphere') taskMgr.add(self.handleCollisions, 'handleCollisions') # if DEBUG: self.trav.showCollisions(render) render.find('**/sphere_collision').show() def makeTunnel(self): self.tunnel = [None] * TUNNEL_CNT for x in range(TUNNEL_CNT): self.tunnel[x] = loader.loadModel('models/tunnel') if x == 0: self.tunnel[x].reparentTo(render) else: self.tunnel[x].reparentTo(self.tunnel[x - 1]) self.tunnel[x].setPos(0, 0, -TUNNEL_SEGMENT_LENGTH) def makeSphere(self): self.sphere = loader.loadModel('models/alice-shapes--sphere-highpoly/sphere-highpoly.egg') self.sphere.reparentTo(render) self.sphere.setScale(0.07) self.sphere.setZ(2) # col_node = self.sphere.attachNewNode(CollisionNode('sphere_collision')) col_sphere = CollisionSphere(0, 0, 2, SPHERE_RADIUS) col_node.node().addSolid(col_sphere) self.trav.addCollider(col_node, self.queue) def makeRandomCrystal(self, tun): crystal = loader.loadModel('models/bvw-f2004--purplecrystal/purplecrystal.egg') crystal.reparentTo(self.tunnel[tun]) # pMin, pMax = LPoint3f(), LPoint3f() crystal.calcTightBounds(pMin, pMax) col_node = crystal.attachNewNode(CollisionNode('crystal_collision')) col_box = CollisionBox(pMin, pMax) col_node.node().addSolid(col_box) crystal.setScale(0.1) if DEBUG: col_node.show() pos = ['rx', '-rx', 'ry', 'down', 'up'] rnd = choice(pos) Z = randint(0, 10) if rnd == 'rx': R = randint(45, 90) X = uniform(-2, 6) crystal.setR(R) crystal.setX(X) elif rnd == '-rx': R = randint(45, 90) X = uniform(-2, 8) crystal.setR(-R) crystal.setX(-X) elif rnd == 'ry': R = randint(45, 120) Y = uniform(2, 6) crystal.setR(R) crystal.setY(Y) elif rnd == '-py': R = randint(45, 120) Y = uniform(3, 8) crystal.setR(-R) crystal.setY(-Y) elif rnd == 'down': Y = uniform(1, 6) P = randint(70, 120) crystal.setY(-Y) crystal.setP(P) elif rnd == 'up': Y = uniform(-1, 6) P = randint(-130, -60) crystal.setY(Y) crystal.setP(P) crystal.setZ(Z) self.crystals.append(crystal) def continueTunnel(self): self.tunnel = self.tunnel[1:] + self.tunnel[0:1] self.tunnel[0].setZ(0) self.tunnel[0].reparentTo(render) self.tunnel[0].setScale(.155, .155, .305) self.tunnel[3].reparentTo(self.tunnel[2]) self.tunnel[3].setZ(-TUNNEL_SEGMENT_LENGTH) self.tunnel[3].setScale(1) for child in self.tunnel[3].getChildren(): if child.getName() == 'purplecrystal.egg': self.crystals.remove(child) child.removeNode() self.makeRandomCrystal(3) self.tunnelMove = Sequence \ ( LerpFunc \ ( self.tunnel[0].setZ, duration=TUNNEL_TIME, fromData=0, toData=TUNNEL_SEGMENT_LENGTH * .305 ), Func(self.continueTunnel) ) self.tunnelMove.start() def setKey(self, key, value): self.keyMap[key] = value def moveSphere(self, task): dt = globalClock.getDt() addVec = LVector3f(0, 0, 0) if self.keyMap['left']: addVec[0] -= SPHERE_SPEED * dt elif self.keyMap['right']: addVec[0] += SPHERE_SPEED * dt elif self.keyMap['up']: addVec[1] += SPHERE_SPEED * dt elif self.keyMap['down']: addVec[1] -= SPHERE_SPEED * dt if ((self.sphere.getPos() + addVec) - LPoint3f(TUNNEL_CENTER)).length() < TUNNEL_RADIUS: self.sphere.setPos(self.sphere.getPos() + addVec) return task.cont def handleCollisions(self, task): for entry in self.queue.getEntries(): node = entry.getFromNodePath() if node.getName() == 'sphere_collision': self.collisionCnt += 1 print 'Oops! Collision counter: %d' % self.collisionCnt return task.cont
class MyApp(ShowBase): def __init__(self, path): ShowBase.__init__(self) self.verbose = False self.speed = 20 self.mouse_sensitivity = .1 self.setFrameRateMeter(True) #self.render.setAntialias(AntialiasAttrib.MAuto) self.setup_camera() self.setup_controls() self.setup_collisions() self.scene_node_history = [] self.scene_node = None t = threading.Thread(target=self.load_directory, args=(path, )) t.start() def setup_collisions(self): self.coll_traverser = CollisionTraverser( ) # does actual work of collision detection self.coll_handler = CollisionHandlerQueue( ) # records collisions that happened self.selector_ray = CollisionRay( ) # is a CollisionSolid, which is a basic object of the collision system self.selector_ray.setFromLens(self.camNode, 0, 0) # point straight away from camera selector_node = CollisionNode( 'mouseRay') # encapsulates a CollisionSolid selector_node.addSolid(self.selector_ray) selector_nodepath = self.camera.attachNewNode(selector_node) self.coll_traverser.addCollider(selector_nodepath, self.coll_handler) # debug if self.verbose: self.coll_traverser.showCollisions(self.render) selector_nodepath.show() def setup_camera(self): self.disableMouse() props = WindowProperties() props.setCursorHidden(True) props.setMouseMode(WindowProperties.M_relative) self.win.requestProperties(props) self.camera.setPos(2, -20, 3) self.taskMgr.add(self.controlCameraTask, 'controlCameraTask') # self.oobe() def setup_controls(self): # keyboard self.accept('escape', sys.exit) self.accept('w', self.handle_key, ['forward', True]) self.accept('w-up', self.handle_key, ['forward', False]) self.accept('s', self.handle_key, ['backward', True]) self.accept('s-up', self.handle_key, ['backward', False]) self.accept('a', self.handle_key, ['left', True]) self.accept('a-up', self.handle_key, ['left', False]) self.accept('d', self.handle_key, ['right', True]) self.accept('d-up', self.handle_key, ['right', False]) self.accept('space', self.handle_key, ['up', True]) self.accept('space-up', self.handle_key, ['up', False]) self.accept('shift', self.handle_key, ['down', True]) self.accept('shift-up', self.handle_key, ['down', False]) self.accept('b', self.traverse_history) self.accept('m', self.change_speed, [10]) self.accept('n', self.change_speed, [-10]) self.key_map = { 'forward': False, 'backward': False, 'right': False, 'left': False, 'up': False, 'down': False } # mouse self.accept('mouse1', self.handle_mouse) def change_speed(self, delta): self.speed += delta print(f'New speed: {self.speed}') def traverse_history(self): if len(self.scene_node_history) > 0: self.scene_node.detachNode() # remove current scene... self.scene_node = self.scene_node_history.pop() self.scene_node.reparentTo(self.render) # ...and activate old one else: print('History is empty') def handle_key(self, key, value): self.key_map[key] = value def handle_mouse(self): # check collisions self.coll_traverser.traverse(self.render) if self.coll_handler.getNumEntries() > 0: self.coll_handler.sortEntries() # sort by distance pickedObj = self.coll_handler.getEntry(0).getIntoNodePath() pickedObj = pickedObj.findNetTag('canCollide') if not pickedObj.isEmpty(): func = pickedObj.getPythonTag('callback') func() def load_directory(self, path): # save old scene if self.scene_node is not None: self.scene_node_history.append(self.scene_node) self.scene_node.detachNode() # create new scene under dummy node dummy = self.render.attachNewNode('dummy') # generate layout x = 0 y = 0 step = 3 filenum = len(os.listdir(path)) sidelen = int(np.ceil(np.sqrt(filenum))) idx_list = list(np.ndindex((sidelen, sidelen))) assert len(idx_list) >= filenum, f'{filenum} < {len(idx_list)}' for (i, j), entry in zip(idx_list, os.scandir(path)): print(f'Parsing "{entry.name}":', end=' ') x, y = i * step, j * step pos = (x, 0, y) if entry.is_dir(): if not entry.name.startswith('.'): e = DirectoryEntity(self, dummy, entry.path, pos) e.build() print('directory') continue general_type, _ = mimetypes.guess_type(entry.path) if general_type is None: ErrorEntity(self, dummy, entry.path, pos).build() print('error') continue type_, subtype = general_type.split('/') print(type_, subtype) Entity = { 'image': ImageEntity, 'text': TextEntity }.get(type_, None) if Entity is None: Entity = {'pdf': PdfEntity}.get(subtype, None) if Entity is None: try: TextEntity(self, dummy, entry.path, pos).build() except: ErrorEntity(self, dummy, entry.path, pos).build() else: Entity(self, dummy, entry.path, pos).build() # self.render.ls() self.scene_node = dummy def controlCameraTask(self, task): md = self.win.getPointer(0) x = md.getX() y = md.getY() self.camera.setH(x * self.mouse_sensitivity) self.camera.setP(y * self.mouse_sensitivity) dt = globalClock.getDt() # is magically available from panda3d if self.key_map['forward']: self.camera.setPos(self.camera, 0, self.speed * dt, 0) if self.key_map['backward']: self.camera.setPos(self.camera, 0, -self.speed * dt, 0) if self.key_map['left']: self.camera.setPos(self.camera, -self.speed * dt / 2, 0, 0) if self.key_map['right']: self.camera.setPos(self.camera, self.speed * dt / 2, 0, 0) if self.key_map['up']: self.camera.setPos(self.camera, 0, 0, self.speed * dt / 2) if self.key_map['down']: self.camera.setPos(self.camera, 0, 0, -self.speed * dt / 2) if self.verbose: self.coll_traverser.traverse(self.render) return Task.cont
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 Game(DirectObject): def __init__(self, model): self.model = model base.setBackgroundColor(0.1, 0.1, 0.8, 1) base.setFrameRateMeter(True) base.cam.setPos(0, -20, 4) base.cam.lookAt(0, 0, 0) # Light alight = AmbientLight('ambientLight') alight.setColor(Vec4(0.5, 0.5, 0.5, 1)) alightNP = render.attachNewNode(alight) dlight = DirectionalLight('directionalLight') dlight.setDirection(Vec3(1, 1, -1)) dlight.setColor(Vec4(0.7, 0.7, 0.7, 1)) dlightNP = render.attachNewNode(dlight) render.clearLight() render.setLight(alightNP) render.setLight(dlightNP) # Input self.accept('escape', self.doExit) self.accept('r', self.doReset) self.accept('f1', self.toggleWireframe) self.accept('f2', self.toggleTexture) self.accept('f3', self.toggleDebug) self.accept('f5', self.doScreenshot) inputState.watchWithModifiers('forward', 'w') inputState.watchWithModifiers('left', 'a') inputState.watchWithModifiers('reverse', 's') inputState.watchWithModifiers('right', 'd') inputState.watchWithModifiers('turnLeft', 'q') inputState.watchWithModifiers('turnRight', 'e') # Task taskMgr.add(self.update, 'updateWorld') # Physics self.setup() # _____HANDLER_____ def doExit(self): self.cleanup() sys.exit(1) def doReset(self): self.cleanup() self.setup() def toggleWireframe(self): base.toggleWireframe() def toggleTexture(self): base.toggleTexture() def toggleDebug(self): if self.debugNP.isHidden(): self.debugNP.show() else: self.debugNP.hide() def doScreenshot(self): base.screenshot('Bullet') # ____TASK___ def calculate_moves(self): self.y = self.model.predict(self.x) self.moves = self.y > 0 # 0.5 def processInput(self, dt): engineForce = 0.0 brakeForce = 0.0 if self.moves[0]: #inputState.isSet('forward'): engineForce = 1000.0 brakeForce = 0.0 if not self.moves[0]: #inputState.isSet('reverse'): engineForce = 0.0 brakeForce = 100.0 if self.moves[1]: #inputState.isSet('turnLeft'): self.steering += dt * self.steeringIncrement self.steering = min(self.steering, self.steeringClamp) if not self.moves[1]: #inputState.isSet('turnRight'): self.steering -= dt * self.steeringIncrement self.steering = max(self.steering, -self.steeringClamp) """ if inputState.isSet('forward'): engineForce = 1000.0 brakeForce = 0.0 if inputState.isSet('reverse'): engineForce = 0.0 brakeForce = 100.0 if inputState.isSet('turnLeft'): self.steering += dt * self.steeringIncrement self.steering = min(self.steering, self.steeringClamp) if inputState.isSet('turnRight'): self.steering -= dt * self.steeringIncrement self.steering = max(self.steering, -self.steeringClamp) """ # Apply steering to front wheels self.vehicle.setSteeringValue(self.steering, 0) self.vehicle.setSteeringValue(self.steering, 1) # Apply engine and brake to rear wheels self.vehicle.applyEngineForce(engineForce, 2) self.vehicle.applyEngineForce(engineForce, 3) self.vehicle.setBrake(brakeForce, 2) self.vehicle.setBrake(brakeForce, 3) def raycast(self): """pFrom = render.getRelativePoint(self.yugoNP,Point3(0,0,0))#Point3(0,0,0) pFrom -= Point3(0,0,pFrom[2]) pRel = render.getRelativePoint(base.cam,self.yugoNP.getPos()) # FIXME THIS IS IT!! get rid of z component pRel -= Point3(0,0,pRel[2]) p45 = Point3(pRel[0] - pRel[1], pRel[1] + pRel[0],0) pn45 = Point3(pRel[0] + pRel[1], pRel[1] - pRel[0],0) #print(render.getRelativePoint(self.yugoNP,Point3(0,0,0))) #print(dir(self.yugoNP)) pTo = [pFrom + pn45, pFrom + pRel, pFrom + p45]#[pFrom + Vec3(-10,10,0)*999,pFrom + Vec3(0,10,0)*999,pFrom + Vec3(10,10,0)*999]# FIXME should be relative to front of car, getting cloe! #self.yugoNP.getPosDelta()*99999]#[Point3(-10,10,0) * 99999,Point3(0,10,0) * 99999,Point3(10,10,0) * 99999] #self.ray = CollisionRay(0,0,0,100,0,0) result = [self.world.rayTestClosest(pFrom,pt) for pt in pTo] #print(dir(self.yugoNP)) #print(result.getHitPos()) return tuple([res.getHitPos().length() for res in result]) """#queue = CollisionHandlerQueue() #traverser.addCollider(fromObject, queue) #traverser.traverse(render) #queue.sortEntries() #for entry in queue.getEntries(): #print(entry) #print(result.getHitPos()) #if result.getNode() != None: #print(self.yugoNP.getPos(result.getNode())) #print(self.cTrav) self.cTrav.traverse(render) entries = list(self.colHandler.getEntries()) entries.sort(key=lambda y: y.getSurfacePoint(render).getY()) #for entry in entries: print(entry.getFromNodePath().getName()) if entries: # and len(result) > 1: for r in entries: if r.getIntoNodePath().getName( ) == 'Box' and r.getFromNodePath().getName() in [ 'ray%d' % i for i in range(3) ]: self.ray_col_vec_dict[ r.getFromNodePath().getName()].append( numpy.linalg.norm( list(r.getSurfacePoint( r.getFromNodePath()))[:-1])) self.ray_col_vec_dict = { k: (min(self.ray_col_vec_dict[k]) if len(self.ray_col_vec_dict[k]) >= 1 else 10000) for k in self.ray_col_vec_dict } self.x = numpy.array(list(self.ray_col_vec_dict.values())) #return entries def update(self, task): dt = globalClock.getDt() self.raycast() self.calculate_moves() self.ray_col_vec_dict = {k: [] for k in self.ray_col_vec_dict} self.processInput(dt) self.world.doPhysics(dt, 10, 0.008) #print(dir(result[1])) #print(numpy.linalg.norm(list(result[1].getSurfacePoint(result[1].getFromNodePath()))[:-1])) #base.camera.setPos(0,-40,10) #print self.vehicle.getWheel(0).getRaycastInfo().isInContact() #print self.vehicle.getWheel(0).getRaycastInfo().getContactPointWs() #print self.vehicle.getChassis().isKinematic() return task.cont def cleanup(self): self.world = None self.worldNP.removeNode() def setup(self): self.worldNP = render.attachNewNode('World') # World self.debugNP = self.worldNP.attachNewNode(BulletDebugNode('Debug')) self.debugNP.show() self.world = BulletWorld() self.world.setGravity(Vec3(0, 0, -9.81)) self.world.setDebugNode(self.debugNP.node()) #terrain = GeoMipTerrain("mySimpleTerrain") #terrain.setHeightfield("./models/heightfield_2.png") #terrain.getRoot().reparentTo(self.worldNP)#render) #terrain.generate() # Plane shape = BulletPlaneShape(Vec3(0, 0, 1), 0) np = self.worldNP.attachNewNode(BulletRigidBodyNode('Ground')) np.node().addShape(shape) np.setPos(0, 0, -1) np.setCollideMask(BitMask32.allOn()) self.world.attachRigidBody(np.node()) np = self.worldNP.attachNewNode(BulletRigidBodyNode('Track')) np.node().setMass(5000.0) np.setPos(3, 0, 10) np.setCollideMask(BitMask32.allOn()) #(0x0f)) #self.track = BulletVehicle(self.world, np.node()) #self.track.setCoordinateSystem(ZUp) self.track_np = loader.loadModel('models/race_track.egg') self.track_np.setScale(100) self.track_np.reparentTo(np) self.track_np.setCollideMask(BitMask32.allOn()) self.world.attachRigidBody(np.node()) self.track_np = np #self.track_np.show() # Chassis shape = BulletBoxShape(Vec3(0.6, 1.4, 0.5)) ts = TransformState.makePos(Point3(0, 0, 0.5)) np = self.worldNP.attachNewNode(BulletRigidBodyNode('Vehicle')) np.node().addShape(shape, ts) np.setPos(0, 0, 1) np.node().setMass(800.0) np.node().setDeactivationEnabled(False) self.world.attachRigidBody(np.node()) #np.node().setCcdSweptSphereRadius(1.0) #np.node().setCcdMotionThreshold(1e-7) self.cTrav = CollisionTraverser() # Vehicle self.vehicle = BulletVehicle(self.world, np.node()) self.vehicle.setCoordinateSystem(ZUp) self.yugoNP = loader.loadModel('models/yugo/yugo.egg') self.yugoNP.reparentTo(np) self.colHandler = CollisionHandlerQueue() self.ray_col_np = {} self.ray_col_vec_dict = {} for ray_dir in range(-1, 2): # populate collision rays self.ray = CollisionRay() self.ray.setOrigin(ray_dir, 0.5, 0.5) self.ray.setDirection(ray_dir, 1, 0) self.ray_col = CollisionNode('ray%d' % (ray_dir + 1)) self.ray_col.addSolid(self.ray) self.ray_col.setFromCollideMask( BitMask32.allOn()) #(0x0f))#CollideMask.bit(0) #self.ray_col.setIntoCollideMask(CollideMask.allOff()) self.ray_col_np['ray%d' % (ray_dir + 1)] = self.yugoNP.attachNewNode( self.ray_col) self.cTrav.addCollider(self.ray_col_np['ray%d' % (ray_dir + 1)], self.colHandler) self.ray_col_np['ray%d' % (ray_dir + 1)].show() self.ray_col_vec_dict['ray%d' % (ray_dir + 1)] = [] self.world.attachVehicle(self.vehicle) self.cTrav.showCollisions(render) # FIXME base.camera.reparentTo(self.yugoNP) # Right front wheel np = loader.loadModel('models/yugo/yugotireR.egg') np.reparentTo(self.worldNP) self.addWheel(Point3(0.70, 1.05, 0.3), True, np) # Left front wheel np = loader.loadModel('models/yugo/yugotireL.egg') np.reparentTo(self.worldNP) self.addWheel(Point3(-0.70, 1.05, 0.3), True, np) # Right rear wheel np = loader.loadModel('models/yugo/yugotireR.egg') np.reparentTo(self.worldNP) self.addWheel(Point3(0.70, -1.05, 0.3), False, np) # Left rear wheel np = loader.loadModel('models/yugo/yugotireL.egg') np.reparentTo(self.worldNP) self.addWheel(Point3(-0.70, -1.05, 0.3), False, np) # Steering info self.steering = 0.0 # degree self.steeringClamp = 45.0 # degree self.steeringIncrement = 120.0 # degree per second # Box for i, j in [(0, 8), (-3, 5), (6, -5), (8, 3), (-4, -4)]: shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5)) # https://discourse.panda3d.org/t/wall-collision-help/23606 np = self.worldNP.attachNewNode(BulletRigidBodyNode('Box')) np.node().setMass(1.0) np.node().addShape(shape) np.setPos(i, j, 2) np.setCollideMask(BitMask32.allOn()) #(0x0f)) self.world.attachRigidBody(np.node()) self.boxNP = np #self.colHandler2 = CollisionHandlerQueue() visualNP = loader.loadModel('models/box.egg') visualNP.reparentTo(self.boxNP) #self.cTrav.addCollider(self.boxNP,self.colHandler) """ aNode = CollisionNode("TheRay") self.ray = CollisionRay() self.ray.setOrigin( self.yugoNP.getPos() ) self.ray.setDirection( Vec3(0, 10, 0) ) #self.ray.show() aNodePath = self.yugoNP.attachNewNode( CollisionNode("TheRay") ) aNodePath.node().addSolid(self.ray) aNodePath.show() """ #aNode.addSolid(self.ray) #self.ray = CollisionRay(0,0,0,10,0,0) #self.ray.reparentTo(self.yugoNP) #self.rayColl = CollisionNode('PlayerRay') #self.rayColl.addSolid(self.ray) #self.playerRayNode = self.yugoNP.attachNewNode( self.rayColl ) #self.playerRayNode.show() #base.myTraverser.addCollider (self.playerRayNode, base.floor) #base.floor.addCollider( self.playerRayNode, self.yugoNP) """ MyEvent=CollisionHandlerFloor() MyEvent.setReach(100) MyEvent.setOffset(15.0) aNode = CollisionNode("TheRay") ray = CollisionRay() ray.setOrigin( self.boxNP.getPos() ) ray.setDirection( Vec3(10, 0, 0) ) aNode.addSolid(ray) aNodePath = MyModel.attachNewNode( aNode ) Collision = ( aNode, "TheRay" ) Collision[0].setFromCollideMask( BitMask32.bit( 1 ) ) """ def addWheel(self, pos, front, np): wheel = self.vehicle.createWheel() wheel.setNode(np.node()) wheel.setChassisConnectionPointCs(pos) wheel.setFrontWheel(front) wheel.setWheelDirectionCs(Vec3(0, 0, -1)) wheel.setWheelAxleCs(Vec3(1, 0, 0)) wheel.setWheelRadius(0.25) wheel.setMaxSuspensionTravelCm(40.0) wheel.setSuspensionStiffness(40.0) wheel.setWheelsDampingRelaxation(2.3) wheel.setWheelsDampingCompression(4.4) wheel.setFrictionSlip(100.0) wheel.setRollInfluence(0.1)
class Moving(ShowBase): def __init__(self): ShowBase.__init__(self) # This is used to store which keys are currently pressed. self.keyMap = { "left": 0, "right": 0, "forward": 0, "back": 0, "up": 0} # Set up the environment # # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("EggMod/SandPlan.egg") self.environ.reparentTo(render) self.environ.setScale(20) StartPos = LVector3(0,0,94) self.movint = loader.loadModel("EggMod/HailPar.egg") self.movint.reparentTo(render) self.movint.setScale(2) self.movint.setPos(StartPos + (0, 0, 0.5)) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left", True]) self.accept("arrow_right", self.setKey, ["right", True]) self.accept("arrow_up", self.setKey, ["forward", True]) self.accept("arrow_down", self.setKey, ["back", True]) self.accept("f", self.setKey, ["up", True]) self.accept("arrow_left-up", self.setKey, ["left", False]) self.accept("arrow_right-up", self.setKey, ["right", False]) self.accept("arrow_up-up", self.setKey, ["forward", False]) self.accept("arrow_down-up", self.setKey, ["back", False]) self.accept("f-up", self.setKey, ["up", False]) self.mopan=Pmango() self.alin = LinearEulerIntegrator() self.mopan.attachLinearIntegrator(self.alin) self.arin = AngularEulerIntegrator() self.mopan.attachAngularIntegrator(self.arin) taskMgr.add(self.move, "moveTask") self.cTrav = CollisionTraverser() #base.cTrav.setRespectPrevTransform(True) self.actMove = NodePath("ActMove") self.actMove.reparentTo(render) self.an = ActorNode("BMova") self.anp = self.actMove.attachNewNode(self.an) self.mopan.attachPhysicalNode(self.an) self.movint.reparentTo(self.anp) self.anp.node().getPhysicsObject().setMass(1) #self.an.getPhysicsObject().setTerminalVelocity(1.0) self.dvi=0 self.grava=ForceNode('GravAll') self.grar=render.attachNewNode(self.grava) self.grdi=LinearVectorForce(0.0,-0.0,-8.0) #self.grdi.setMassDependent(1) self.grava.addForce(self.grdi) #Forces have to be added to force nodes and to # a physics manager self.mopan.addLinearForce(self.grdi) self.BMoveBalance = CollisionSphere(0, 0, -7.0, 1) self.BMoveBalanceNode = CollisionNode('BMove') self.BMoveBalanceNode.addSolid(self.BMoveBalance) self.BMoveBalancePath = self.movint.attachNewNode(self.BMoveBalanceNode) self.DinGro = PhysicsCollisionHandler() self.DinGro.setStaticFrictionCoef(1) self.DinGro.setDynamicFrictionCoef(2) self.DinGro.setAlmostStationarySpeed(0.1) self.DinGro.addCollider(self.BMoveBalancePath,self.anp) #Colliders use nodepaths for collisions instead of nodes self.cTrav.addCollider(self.BMoveBalancePath, self.DinGro) # Uncomment this line to see the collision rays self.BMoveBalancePath.show() # Uncomment this line to show a visual representation of the # collisions occuring self.cTrav.showCollisions(render) # Create some lighting directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection((-5, -5, -5)) render.setLight(render.attachNewNode(directionalLight)) # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # Get the time that elapsed since last frame. We multiply this with # the desired speed in order to find out with which distance to move # in order to achieve that desired speed. dt = globalClock.getDt() self.dvi+=dt self.anr=self.an.getPhysicsObject() print(self.anr.getVelocity()) if dt<=.2: self.mopan.doPhysics(dt) if self.keyMap["left"]: self.movint.setH(self.movint.getH() + 200 * dt) if self.keyMap["right"]: self.movint.setH(self.movint.getH() - 200 * dt) if self.keyMap["forward"]: self.movint.setFluidY(self.movint, -25 * dt) if self.keyMap["back"]: self.movint.setFluidY(self.movint, 25 * dt) if self.keyMap["up"]: self.movint.setFluidZ(self.movint, 25 * dt) # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. #self.cTrav.traverse(render) return task.cont
class PandaHW(ShowBase): def __init__(self): messenger.toggleVerbose() ShowBase.__init__(self) self.environ = self.loader.loadModel("models/falcon") self.environ.reparentTo(self.render) self.environ.setScale(0.25, 0.25, 0.25) self.environ.setPos(-8, 42, 0) self.taskMgr.add(self.spinCameraTask, "SpinCameraTask") self.taskMgr.add(self.moveCameraTask, "MoveCameraTask") self.taskMgr.add(self.playerGravity, "PlayerGravity") #self.taskMgr.add(self.collTask, "CollisionTask") self.pandaActor = Actor("models/panda-model", {"walk": "models/panda-walk4"}) self.pandaActor.setScale(0.005, 0.005, 0.005) self.pandaActor.setPos(0, 0, 10) self.pandaActor.reparentTo(self.render) # Initialize the collision traverser. self.cTrav = CollisionTraverser() self.cTrav.showCollisions(self.render) # Initialize the Pusher collision handler. pusher = CollisionHandlerPusher() # Create a collision node for this object. cNode = CollisionNode('panda') # Attach a collision sphere solid to the collision node. cNode.addSolid(CollisionSphere(0, 0, 0, 600)) # Attach the collision node to the object's model. pandaC = self.pandaActor.attachNewNode(cNode) # Set the object's collision node to render as visible. pandaC.show() # Create a collsion node for this object. cNode = CollisionNode('environnement') # Attach a collision sphere solid to the collision node. cNode.addSolid(CollisionSphere(-1.3, 19, 0.5, 2.5)) cNode.addSolid(CollisionPlane(Plane(Vec3(0,0,1), Point3(0,0,0.2)))) # Attach the collision node to the object's model. environC = self.environ.attachNewNode(cNode) # Set the object's collision node to render as visible. environC.show() # Add the Pusher collision handler to the collision traverser. self.cTrav.addCollider(pandaC, pusher) # Add the 'frowney' collision node to the Pusher collision handler. pusher.addCollider(pandaC, self.environ, base.drive.node()) fromObject = self.pandaActor.attachNewNode(CollisionNode('colNode')) fromObject.node().addSolid(CollisionRay(0, 0, 0, 0, 0, -1)) lifter = CollisionHandlerFloor() lifter.addCollider(fromObject, self.pandaActor) self.cTrav.addCollider(pandaC, lifter) # Have the 'smiley' sphere moving to help show what is happening. #frowney.posInterval(5, Point3(5, 25, 0), startPos=Point3(-5, 25, 0), fluid=1).loop() #self.stuff = Actor("models/panda-model") #self.stuff.setScale(0.005, 0.005, 0.005) #self.stuff.setPos(-1.3, 19., 0.5) #self.stuff.reparentTo(self.render) # cTrav = CollisionTraverser() # ceh = CollisionHandlerQueue() # #ceh.addInPattern('%fn-into-%in') # #ceh.addAgainPattern('%fn-again-%in') # #ceh.addOutPattern('%fn-outof-%in') # self.pandaColl = self.pandaActor.attachNewNode(CollisionNode('cnode')) # self.pandaColl.node().addSolid(CollisionSphere(self.pandaActor.getChild( 0 ).getBounds( ).getCenter(), 400)) # self.pandaColl.show() # cTrav.addCollider( self.pandaColl, ceh ) # self.cTrav = cTrav # self.cTrav.showCollisions(self.render) # self.queue = ceh # cs = CollisionSphere(-1.3, 19, 0.5, 2.5) # pl = CollisionPlane(Plane(Vec3(0,0,1), Point3(0,0,0.2))) # # ray = CollisionRay(self.pandaActor.getPos(), Vec3(0,0,-1)) # cnodePath = self.render.attachNewNode(CollisionNode('cnode')) # # rayNodePath = self.render.attachNewNode(CollisionNode('raynode')) # cnodePath.node().addSolid(cs) # cnodePath.node().addSolid(pl) # # rayNodePath.node().addSolid(ray) # cnodePath.show() # # rayNodePath.show() # #rayNodePath.reparentTo(self.pandaActor) #self.accept('car-into-rail', handleRailCollision) #cTrav.addCollider(cnodePath, ceh) self.camera.reparentTo(self.pandaActor) self.camera.setPos(0., 1050., 1000.) self.camAlpha = 180 self.camBeta = 0 self.moving = [] self.playerAltitude = 0 self.jumping = False self.inJump = False self.playerFallingSpeed = 0 self.player = Mass(80) base.useDrive() #base.disableMouse( ) # disable the default camera controls that are created for us self.keyBoardSetup() def collEvent(self, entry): print "Collide event", entry # A task is a procedure that is called every frame def spinCameraTask(self, task): rotation_speed = 20 invert_camY = True w, h = self.getSize() if base.mouseWatcherNode.hasMouse(): cx = base.mouseWatcherNode.getMouseX() cy = base.mouseWatcherNode.getMouseY() self.camAlpha -= cx * rotation_speed self.camBeta -= (cy * rotation_speed) * (-1 if invert_camY else 1) for win in self.winList: if win.hasPointer(0): win.movePointer(0,w/2,h/2) self.pandaActor.setHpr(self.camAlpha, self.camBeta, 0.) self.camera.setHpr(180., -self.camBeta, 0.) return Task.cont def moveCameraTask(self, task): walk_speed = 1 newX = self.pandaActor.getX() newY = self.pandaActor.getY() newZ = self.pandaActor.getZ() if self.moving: self.pandaActor.loop("walk") else: self.pandaActor.stop() if 1 in self.moving: # Forward newX -= sin(degtorad(self.camAlpha)) * walk_speed newY += cos(degtorad(self.camAlpha)) * walk_speed newZ += sin(degtorad(self.camBeta)) * walk_speed if 2 in self.moving: # Backward newX += sin(degtorad(self.camAlpha)) * walk_speed newY -= cos(degtorad(self.camAlpha)) * walk_speed newZ -= sin(degtorad(self.camBeta)) * walk_speed if 3 in self.moving: # left newX -= cos(degtorad(self.camAlpha)) * walk_speed newY -= sin(degtorad(self.camAlpha)) * walk_speed if 4 in self.moving: # right newX += cos(degtorad(self.camAlpha)) * walk_speed newY += sin(degtorad(self.camAlpha)) * walk_speed newZ -= self.playerFallingSpeed #if newZ >= (self.playerAltitude - 0.1) and newZ <= (self.playerAltitude + 0.1) and not self.jumping: # Tolerance # newZ = self.playerAltitude self.pandaActor.setPos(newX, newY, newZ) self.player.pos = VBase3(newX, newY, newZ) return Task.cont def move(self, direction): if direction < 0 and -direction in self.moving: self.moving.remove(-direction) else: self.moving.append(direction) def playerGravity(self, task): self.player.simulate(task.time) self.pandaActor.setPos(self.player.pos) z = self.player.pos.getZ() pa = self.playerAltitude if self.jumping and z >= (pa - 0.1) and z <= (pa + 0.1): # Tolerance self.inJump = True self.player.vel = VBase3(0, 0, 0.05) self.player.force = VBase3(0, 0, 0) return Task.cont def jump(self, jumping = True): self.jumping = jumping def keyBoardSetup( self ): self.accept("escape", sys.exit ) key_directions = { "arrow_up": 1, "z" : 1, "arrow_down": 2, "s" : 2, "arrow_left": 3, "q" : 3, "arrow_right": 4, "d" : 4, } for key_name, direction in key_directions.items(): self.accept(key_name, self.move, [direction]) self.accept("%s-up" % (key_name,), self.move, [-direction]) self.accept("space", self.jump, [True]) self.accept("space-up", self.jump, [False])
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) ################ #Terrain ################ ####### #self.environ = GeoMipTerrain("terrain") #self.environ.setHeightfield("../terrain/first.png") #self.environ.setColorMap("../terrain/first-c.png") #self.environ.generate() #self.environ.getRoot().setScale(1, 1, 100) #self.environ.getRoot().setPos(0, 0, 0) #self.environ.getRoot().reparentTo(render) #self.environ.getRoot().setName("terrain") #self.environ.getRoot().setCollideMask(BitMask32.bit(0)) ####### self.environ = loader.loadModel("models/environment") self.environ.setScale(.25, .25, .25) self.environ.reparentTo(render) self.environ.setCollideMask(BitMask32.bit(0)) ################ #Game objects ################ self.pandaActor = Actor("models/panda", {"walk": "models/panda-walk"}) self.pandaActor.setScale(.5, .5, .5) self.pandaActor.setHpr(180, 0, 0) #self.pandaActor.setPos(50, 50, 50) self.pandaActor.setPythonTag("moving", False) self.pandaActor.setCollideMask(BitMask32.allOff()) self.avatarYawRot = 0 self.avatarPitchRot = 0 #self.teapot = loader.loadModel("models/teapot") #self.teapot.setScale(1, 1, 1) #self.teapot.setPos(60, 60, 50) #self.teapot.reparentTo(render) self.last_mouse_y = self.win.getPointer(0).getY() ################ #Physics ################ base.enableParticles() self.avatarNP=base.render.attachNewNode(ActorNode("actor")) # Sets up the mass. Note that in this scenario, mass is not taken into consideration. self.avatarNP.node().getPhysicsObject().setMass(100.) self.avatarNP.setPos(0,0,0) # Parent our avatar to the ready to go physics node self.pandaActor.reparentTo(self.avatarNP) gravityFN=ForceNode('world-forces') gravityFNP=render.attachNewNode(gravityFN) gravityForce=LinearVectorForce(0,0,-.1) gravityForce.setMassDependent(False) gravityFN.addForce(gravityForce) # Attach it to the global physics manager base.physicsMgr.addLinearForce(gravityForce) base.physicsMgr.attachPhysicalNode(self.avatarNP.node()) ################ #Collisions ################ self.cTrav = CollisionTraverser() self.cTrav.showCollisions(base.render) self.pandaGroundRay = CollisionSphere(0,0,0,1) self.pandaGroundRayNode = CollisionNode('pandaGroundRay') self.pandaGroundRayNode.addSolid(self.pandaGroundRay) self.pandaGroundRayNode.setFromCollideMask(BitMask32.bit(0)) self.pandaGroundRayNode.setIntoCollideMask(BitMask32.allOff()) self.pandaGroundRayNodepath = self.avatarNP.attachNewNode(self.pandaGroundRayNode) self.pandaGroundRayNodepath.show() self.pandaGroundCollisionHandler = PhysicsCollisionHandler() self.pandaGroundCollisionHandler.addCollider(self.pandaGroundRayNodepath, self.avatarNP) self.cTrav.addCollider(self.pandaGroundRayNodepath, self.pandaGroundCollisionHandler) #self.teapotRay = CollisionSphere(0,0,0,5) #self.teapotGroundCol = CollisionNode('teapotRay') #self.teapotGroundCol.addSolid(self.teapotRay) #self.teapotGroundCol.setFromCollideMask(BitMask32.allOff()) #self.teapotGroundCol.setIntoCollideMask(BitMask32.bit(0)) #self.teapotGroundColNp = self.teapot.attachNewNode(self.teapotGroundCol) #self.teapotGroundHandler = CollisionHandlerQueue() #self.cTrav.addCollider(self.teapotGroundColNp, self.teapotGroundHandler) ################ #Camera ################ self.disableMouse() self.cam_away = 20 self.cam_elevation = 0 self.rot_rate = .5 self.cam_dist = (self.cam_away**2 + self.cam_elevation**2) ** .5 self.cam.setHpr(0, 0, 0) ################ #Events ################ self.taskMgr.add(self.gameLoop, "gameLoop", priority = 35) self.keys = {"w" : 0, "s" : 0, "a" : 0, "d" : 0} self.accept("w", self.setKey, ["w", 1]) self.accept("w-up", self.setKey, ["w", 0]) self.accept("s", self.setKey, ["s", 1]) self.accept("s-up", self.setKey, ["s", 0]) self.accept("a", self.setKey, ["a", 1]) self.accept("a-up", self.setKey, ["a", 0]) self.accept("d", self.setKey, ["d", 1]) self.accept("d-up", self.setKey, ["d", 0]) self.accept("wheel_up", self.zoomCamera, [-1]) self.accept("wheel_down", self.zoomCamera, [1]) self.accept('window-event', self.handleWindowEvent) props = WindowProperties() props.setCursorHidden(True) base.win.requestProperties(props) self.last_mouse_x = self.win.getPointer(0).getX() def setKey(self, key, value): self.keys[key] = value def handleWindowEvent(self, window=None): wp = window.getProperties() self.win_center_x = wp.getXSize() / 2 self.win_center_y = wp.getYSize() / 2 def zoomCamera(self, direction): self.cam_away += direction def gameLoop(self, task): dt = globalClock.getDt() #self.avatarNP.setY(self.avatarNP, 10 * dt) if self.keys["w"]: self.avatarNP.setZ(self.avatarNP, 5 * dt) if self.keys["s"]: self.avatarNP.setZ(self.avatarNP, -5 * dt) if self.keys["a"]: self.avatarNP.setX(self.avatarNP, -5 * dt) if self.keys["d"]: self.avatarNP.setX(self.avatarNP, 5 * dt) #Mouse-based viewpoint rotation mouse_pos = self.win.getPointer(0) current_mouse_x = mouse_pos.getX() current_mouse_y = mouse_pos.getY() mouse_shift_x = current_mouse_x - self.last_mouse_x mouse_shift_y = current_mouse_y - self.last_mouse_y self.last_mouse_x = current_mouse_x self.last_mouse_y = current_mouse_y if current_mouse_x == 0 or current_mouse_x >= (self.win_center_x * 1.5): base.win.movePointer(0, self.win_center_x, self.win_center_y) self.last_mouse_x = self.win_center_x if current_mouse_y == 0 or current_mouse_y >= (self.win_center_y * 1.5): base.win.movePointer(0, self.win_center_x, self.win_center_y) self.last_mouse_y = self.win_center_y #self.cam.setP(0) yaw_shift = -((mouse_shift_x) * self.rot_rate) pitch_shift = -((mouse_shift_y) * self.rot_rate) self.avatarYawRot += yaw_shift self.avatarPitchRot += pitch_shift self.avatarNP.setH(self.avatarYawRot) self.cam.setH(self.avatarYawRot) self.cam.setP(-self.avatarPitchRot) xy_plane_cam_dist = self.cam_away*cos(radians(self.avatarPitchRot)) cam_x_adjust = xy_plane_cam_dist*sin(radians(self.avatarYawRot)) cam_y_adjust = xy_plane_cam_dist*cos(radians(self.avatarYawRot)) cam_z_adjust = self.cam_away*sin(radians(self.avatarPitchRot)) print self.camera.getPos() self.cam.setPos(self.avatarNP.getX() + cam_x_adjust, self.avatarNP.getY() - cam_y_adjust, self.avatarNP.getZ() + cam_z_adjust) print self.avatarNP.getPos() #self.cam.setP(self.x) #self.x += .01 #self.cTrav.traverse(render) #entries = [] #for i in range(self.pandaGroundCollisionHandler.getNumEntries()): # entry = self.pandaGroundCollisionHandler.getEntry(i) # entries.append(entry) #for entry in entries: # print entry.getIntoNode().getName() # if entry.getIntoNode().getName() == "terrain": # print "shiet" # self.pandaActor.setZ(entry.getSurfacePoint(render).getZ()) return Task.cont
def __init__(self): ShowBase.__init__(self) mySound = base.loader.loadSfx("sfx/tank_with_radar.ogg") self.mainShot_snd = base.loader.loadSfx("sfx/mainShot.ogg") self.enemyShot_snd = base.loader.loadSfx("sfx/enemyShot.ogg") self.enemyTankExplosion_snd = base.loader.loadSfx( "sfx/enemyTankExplosion.ogg") device_list = self.devices.getDevices() for device in device_list: print(device.device_class) # if device.device_class == DeviceClass.flight_stick: # print("Have Joy stick") # render.setDepthTest(False) self.camLens.setFov(50) render.setAntialias(AntialiasAttrib.MLine) base.setBackgroundColor(0, 0, 0) base.disableMouse() props = WindowProperties() # props.setCursorHidden(True) base.win.requestProperties(props) # Load the environment models self.ground = self.loader.loadModel("models/ground_bl.egg") self.tank = self.loader.loadModel("models/tank_bl.egg") self.tank.setRenderModeWireframe() self.ground.setRenderModeWireframe() self.ground.setScale(100, 100, 1) # tank as lines # set up explosion variables # explosion intervals added in renderTanks() method for t in tanks_list: tanks_dict[t]["explosion"] = Parallel( name="Tank{}-Explosion".format(t)) # group node for all enemy tanks self.tank_group = render.attachNewNode("Tanks") self.renderTanks(self.tank_group) # tank rounds with open('models/tank_round.json', "r") as f: data = json.load(f) lines = create_lineSegs_object(data, 0) lines.setThickness(3) gn_round = lines.create() np_round = NodePath(gn_round) self.tank_round = [] # self.tank_round.append(render.attachNewNode("tank-round")) np_round.instanceTo(self.tank_round[0]) # self.tank_round[0].hide() self.tank_round[0].setColorScale(0.3, 0.3, 1.0, 1.0) self.tank_round[0].setPos(0, 20, -0.2 - 10) self.tank_round[0].setHpr(self.tank_round[0], 0, 90, 0) self.tank_round[0].setScale(0.2, 0.2, 0.2) self.tank_round[0].reparentTo(camera) # render enemy tank round for t in tanks_list: tanks_dict[t]["round"] = render.attachNewNode( "tank{}-round".format(t)) np_round.instanceTo(tanks_dict[t]["round"]) tanks_dict[t]["round"].setPos(-0.4, 0, 1.61325) tanks_dict[t]["round"].setHpr(tanks_dict[t]["round"], 0, 0, 90) tanks_dict[t]["round"].setScale(0.14, 0.14, 0.14) tanks_dict[t]["round"].reparentTo(tanks_dict[t]["tank"]) # # new mountain method self.render_mountains() #################### # collisions # #################### print(CollisionNode.getDefaultCollideMask()) # Initialize collision Handler self.collHandEvent = CollisionHandlerEvent() self.collHandEvent.addInPattern('into-%in') # collision spheres enemy tank for t in tanks_list: cs = CollisionSphere(0, 0, 0.9, tanks_dict[t]["coll_rad"]) cnodePath = tanks_dict[t]["tank"].attachNewNode( CollisionNode('cTank' + t)) cnodePath.node().addSolid(cs) if DEBUG: # cnodePath.show() pass self.tank_group.setCollideMask(BitMask32(0x10)) # print(self.tank_group.getCollideMask()) # print(tanks_dict['1']["tank"].getCollideMask()) # collision sphere for round of main tank cs = CollisionSphere(0, 0, 0, 1) tr_cnodePath = self.tank_round[0].attachNewNode( CollisionNode('cTankRound')) tr_cnodePath.node().addSolid(cs) # collision spheres for enemy tank rounds cs = CollisionSphere(0, 0, 0, 1) for t in tanks_list: np = tanks_dict[t]["round"].attachNewNode( CollisionNode('ceTankRound' + t)) np.node().addSolid(cs) np.node().setFromCollideMask(BitMask32(0x20)) # np.show() # collision sphere main tank cs = CollisionSphere(0, 0, 0, 1) np = self.camera.attachNewNode(CollisionNode('cmTank')) np.node().addSolid(cs) # np.show() # Initialise Traverser traverser = CollisionTraverser('Main Traverser') if DEBUG: traverser.showCollisions(render) base.cTrav = traverser # from objects traverser.addCollider(tr_cnodePath, self.collHandEvent) np_list = render.findAllMatches("**/ceTankRound*") for np in np_list: traverser.addCollider(np, self.collHandEvent) # grid grid_lines = procedural_grid(-1000, 500, -1000, 500, 50) grid_lines.setThickness(1) node = grid_lines.create() self.grid = NodePath(node) self.grid.setColorScale(0.15, 0.2, 0.15, 1.0) self.grid.setPos(0, 0, -0.2) alight = AmbientLight('ambientLight') alight.setColor(Vec4(0, 0, 0, 0)) # ambient light is dim red # alightNP = self.render.attachNewNode(alight) # render sight self.render_sight() # Tasks for t in tanks_list: tanks_dict[t]["move"] = True self.taskMgr.add(self.spinCameraTask, "SpinCameraTask") self.taskMgr.add(self.moveTanksTask, "MoveTanksTask") self.taskMgr.add(self.moveTask, "MoveTask") self.taskMgr.add(self.enemy_shoot_task, "EnemyShoot") # base.messenger.toggleVerbose() self.accept('space', self.shoot) self.accept('space-up', self.shot_clear) self.accept('shot-done', self.reset_shot) self.accept('into-' + 'cmTank', self.struck) for t in tanks_list: self.accept('into-' + 'cTank' + t, self.tank0_round_hit) self.accept('explosion{}-done'.format(t), self.explosion_cleanup, extraArgs=[t]) self.accept('shot{}-done'.format(t), self.enemy_reset_shot, extraArgs=[t]) # on-screen text vect = self.camera.getHpr() self.textObject = OnscreenText(text=str(vect[0]), pos=(-0.5, -0.9), scale=(0.03, 0.05), fg=(0.4, 1.0, 0.4, 1), mayChange=True) self.textObject.reparentTo(self.render2d) mySound.setLoop(True) mySound.play()
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.seeNode = self.render.attachNewNode('see') self.cam.reparentTo(self.seeNode) self.cam.setPos(0, 0, 5) self.fpscamera = fpscontroller.FpsController(self, self.seeNode) self.fpscamera.setFlyMode(True) self.prevPos = self.fpscamera.getPos() self.prevInto = None self.info = self.genLabelText("Position: <unknown>", 4) self.makeInstructions() self.initCollisions() self.leftColor = LVecBase4i(224, 224, 64, 255) self.rightColor = LVecBase4i(64, 224, 224, 255) self.isDrawing = False self.toggleDrawing() self.accept("escape", sys.exit) #Escape quits self.accept("enter", self.toggleDrawing) def initCollisions(self): # Initialize the collision traverser. self.cTrav = CollisionTraverser() self.cTrav.showCollisions(self.render) # self.cQueue = CollisionHandlerQueue() # Initialize the Pusher collision handler. #self.pusher = CollisionHandlerPusher() self.pusher = CollisionHandlerFloor() ### player print DirectNotifyGlobal.directNotify.getCategories() # Create a collsion node for this object. playerNode = CollisionNode('player') playerNode.addSolid(CollisionSphere(0, 0, 0, 1)) # playerNode.setFromCollideMask(BitMask32.bit(0)) # playerNode.setIntoCollideMask(BitMask32.allOn()) # Attach the collision node to the object's model. self.playerC = self.fpscamera.player.attachNewNode(playerNode) # Set the object's collision node to render as visible. self.playerC.show() # Add the 'player' collision node to the Pusher collision handler. #self.pusher.addCollider(self.playerC, self.fpscamera.player) #self.pusher.addCollider(playerC, self.fpscamera.player) # self.cTrav.addCollider(self.playerC, self.cQueue) def toggleDrawing(self): self.isDrawing = not self.isDrawing if self.isDrawing: self.drawText.setText("Enter: Turn off drawing") self.fpscamera.setFlyMode(True) self.prevPos = None self.cTrav.removeCollider(self.playerC) self.pusher.removeCollider(self.playerC) self.removeTask('updatePhysics') self.addTask(self.drawHere, 'drawHere') self.geomNode = GeomNode('geomNode') self.geomNodePath = self.render.attachNewNode(self.geomNode) self.geomNodePath.setTwoSided(True) # apparently p3tinydisplay needs this self.geomNodePath.setColorOff() # Create a collision node for this object. self.floorCollNode = CollisionNode('geom') # self.floorCollNode.setFromCollideMask(BitMask32.bit(0)) # self.floorCollNode.setIntoCollideMask(BitMask32.allOn()) # Attach the collision node to the object's model. floorC = self.geomNodePath.attachNewNode(self.floorCollNode) # Set the object's collision node to render as visible. floorC.show() #self.pusher.addCollider(floorC, self.geomNodePath) self.newVertexData() self.newGeom() else: self.drawText.setText("Enter: Turn on drawing") self.removeTask('drawHere') if self.prevPos: self.completePath() self.fpscamera.setFlyMode(True) self.drive.setPos(self.fpscamera.getPos()) self.cTrav.addCollider(self.playerC, self.pusher) self.pusher.addCollider(self.playerC, self.fpscamera.player) self.taskMgr.add(self.updatePhysics, 'updatePhysics') def newVertexData(self): fmt = GeomVertexFormat.getV3c4() # fmt = GeomVertexFormat.getV3n3c4() self.vertexData = GeomVertexData("path", fmt, Geom.UHStatic) self.vertexWriter = GeomVertexWriter(self.vertexData, 'vertex') # self.normalWriter = GeomVertexWriter(self.vertexData, 'normal') self.colorWriter = GeomVertexWriter(self.vertexData, 'color') def newGeom(self): self.triStrips = GeomTristrips(Geom.UHDynamic) self.geom = Geom(self.vertexData) self.geom.addPrimitive(self.triStrips) def makeInstructions(self): OnscreenText(text="Draw Path by Walking", style=1, fg=(1, 1, 0, 1), pos=(0.5, -0.95), scale=.07) self.drawText = self.genLabelText("", 0) self.genLabelText("Walk (W/S/A/D), Jump=Space, Look=PgUp/PgDn", 1) self.genLabelText( " (hint, go backwards with S to see your path immediately)", 2) self.genLabelText("ESC: Quit", 3) def genLabelText(self, text, i): return OnscreenText(text=text, pos=(-1.3, .95 - .05 * i), fg=(1, 1, 0, 1), align=TextNode.ALeft, scale=.05) def drawHere(self, task): pos = self.fpscamera.getPos() self.info.setText("Position: {0}, {1}, {2} at {3} by {4}".format( int(pos.x * 100) / 100., int(pos.y * 100) / 100., int(pos.z) / 100., self.fpscamera.getHeading(), self.fpscamera.getLookAngle())) prevPos = self.prevPos if not prevPos: self.prevPos = pos elif (pos - prevPos).length() > 1: self.drawQuadTo(prevPos, pos, 2) row = self.vertexWriter.getWriteRow() numPrims = self.triStrips.getNumPrimitives() if numPrims == 0: primVerts = row else: primVerts = row - self.triStrips.getPrimitiveEnd(numPrims - 1) if primVerts >= 4: self.triStrips.closePrimitive() if row >= 256: print "Packing and starting anew" newGeom = True self.geom.unifyInPlace(row, False) else: newGeom = False self.completePath() if newGeom: self.newVertexData() self.newGeom() if not newGeom: self.triStrips.addConsecutiveVertices(row - 2, 2) else: self.drawQuadTo(prevPos, pos, 2) self.leftColor[1] += 63 self.rightColor[2] += 37 self.prevPos = pos return task.cont def drawLineTo(self, pos, color): self.vertexWriter.addData3f(pos.x, pos.y, pos.z) # self.normalWriter.addData3f(0, 0, 1) self.colorWriter.addData4i(color) self.triStrips.addNextVertices(1) def drawQuadTo(self, a, b, width): """ a (to) b are vectors defining a line bisecting a new quad. """ into = (b - a) if abs(into.x) + abs(into.y) < 1: if not self.prevInto: return into = self.prevInto print into else: into.normalize() # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space if self.vertexWriter.getWriteRow() == 0: self.drawQuadRow(a, into, width) self.drawQuadRow(b, into, width) self.prevInto = into def drawQuadRow(self, a, into, width): """ a defines a point, with 'into' being the normalized direction. """ # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space aLeft = Vec3(a.x - into.y * width, a.y + into.x * width, a.z) aRight = Vec3(a.x + into.y * width, a.y - into.x * width, a.z) row = self.vertexWriter.getWriteRow() self.vertexWriter.addData3f(aLeft) self.vertexWriter.addData3f(aRight) # self.normalWriter.addData3f(Vec3(0, 0, 1)) # self.normalWriter.addData3f(Vec3(0, 0, 1)) self.colorWriter.addData4i(self.leftColor) self.colorWriter.addData4i(self.rightColor) self.triStrips.addConsecutiveVertices(row, 2) def completePath(self): self.geomNode.addGeom(self.geom) if self.triStrips.getNumPrimitives() == 0: return floorMesh = CollisionFloorMesh() tris = self.triStrips.decompose() p = 0 vertexReader = GeomVertexReader(self.vertexData, 'vertex') for i in range(tris.getNumPrimitives()): v0 = tris.getPrimitiveStart(i) ve = tris.getPrimitiveEnd(i) if v0 < ve: vertexReader.setRow(tris.getVertex(v0)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(tris.getVertex(v0 + 1)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(tris.getVertex(v0 + 2)) floorMesh.addVertex(Point3(vertexReader.getData3f())) floorMesh.addTriangle(p, p + 1, p + 2) p += 3 self.floorCollNode.addSolid(floorMesh) def updatePhysics(self, task): pos = self.fpscamera.getPos() self.info.setText("Position: {0}, {1}, {2}".format( int(pos.x * 100) / 100., int(pos.y * 100) / 100., int(pos.z) / 100.)) return task.cont
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.seeNode = self.render.attachNewNode('see') self.cam.reparentTo(self.seeNode) self.cam.setPos(0, 0, 5) self.fpscamera = fpscontroller.FpsController(self, self.seeNode) self.fpscamera.setFlyMode(True) self.fpscamera.setMouseLook(True) self.prevPos = self.fpscamera.getPos() self.prevInto = None self.makeInstructions() self.info = self.genLabelText("Position: <unknown>", 2) self.initCollisions() self.leftColor = LVecBase4i(224, 224, 64, 255) self.rightColor = LVecBase4i(64, 224, 224, 255) self.isDrawing = False self.toggleDrawing() self.accept("escape", sys.exit) #Escape quits self.accept("enter", self.toggleDrawing) def initCollisions(self): # Initialize the collision traverser. self.cTrav = CollisionTraverser() self.cTrav.showCollisions(self.render) # Initialize the Pusher collision handler. self.pusher = CollisionHandlerFloor() ### player # Create a collsion node for this object. playerNode = CollisionNode('player') playerNode.addSolid(CollisionSphere(0, 0, 0, 1)) # Attach the collision node to the object's model. self.playerC = self.fpscamera.player.attachNewNode(playerNode) # Set the object's collision node to render as visible. self.playerC.show() def toggleDrawing(self): self.isDrawing = not self.isDrawing if self.isDrawing: self.instructionText.setText('Enter: Generate Tunnel from Movement') self.fpscamera.setFlyMode(True) self.prevPos = None # self.cTrav.remosveCollider(self.playerC) self.removeTask('updatePhysics') self.addTask(self.drawHere, 'drawHere') self.geomNode = GeomNode('geomNode') self.geomNodePath = self.render.attachNewNode(self.geomNode) self.geomNodePath.setTwoSided(True) # apparently p3tinydisplay needs this self.geomNodePath.setColorOff() # Create a collision node for this object. self.floorCollNode = CollisionNode('geom') # Attach the collision node to the object's model. floorC = self.geomNodePath.attachNewNode(self.floorCollNode) # Set the object's collision node to render as visible. floorC.show() self.newVertexData() self.newGeom() else: self.instructionText.setText('Enter: Record Movement for Tunnel') self.removeTask('drawHere') if self.prevPos: #self.completePath() self.completeTunnelPath() self.fpscamera.setFlyMode(True) self.drive.setPos(self.fpscamera.getPos()) self.cTrav.addCollider(self.playerC, self.pusher) self.pusher.addCollider(self.playerC, self.fpscamera.player) self.taskMgr.add(self.updatePhysics, 'updatePhysics') def newVertexData(self): fmt = GeomVertexFormat.getV3c4() # fmt = GeomVertexFormat.getV3n3c4() self.vertexData = GeomVertexData("path", fmt, Geom.UHStatic) self.vertexWriter = GeomVertexWriter(self.vertexData, 'vertex') # self.normalWriter = GeomVertexWriter(self.vertexData, 'normal') self.colorWriter = GeomVertexWriter(self.vertexData, 'color') def newGeom(self): self.triStrips = GeomTristrips(Geom.UHDynamic) self.geom = Geom(self.vertexData) self.geom.addPrimitive(self.triStrips) def makeInstructions(self): OnscreenText(text="Draw Path by Walking (WSAD/space/mouselook)", style=1, fg=(1,1,0,1), pos=(0.5,-0.95), scale = .07) self.genLabelText("ESC: Quit", 0) self.instructionText = self.genLabelText("", 1) def genLabelText(self, text, i): return OnscreenText(text = text, pos = (-1.3, .95-.05*i), fg=(1,1,0,1), align = TextNode.ALeft, scale = .05) def drawHere(self, task): pos = self.fpscamera.getPos() self.info.setText("Position: {0}, {1}, {2} at {3} by {4}".format(int(pos.x*100)/100., int(pos.y*100)/100., int(pos.z)/100., self.fpscamera.getHeading(), self.fpscamera.getLookAngle())) prevPos = self.prevPos if not prevPos: self.prevPos = pos elif (pos - prevPos).length() >= 1: # self.extendPathQuad(prevPos, pos, 2) self.extendPathTunnel(prevPos, pos, 3) self.leftColor[1] += 63 self.rightColor[2] += 37 self.prevPos = pos return task.cont def extendPathQuad(self, prevPos, pos, width): self.drawQuadTo(prevPos, pos, width) row = self.vertexWriter.getWriteRow() numPrims = self.triStrips.getNumPrimitives() if numPrims == 0: primVerts = row else: primVerts = row - self.triStrips.getPrimitiveEnd(numPrims-1) if primVerts >= 4: self.triStrips.closePrimitive() if row >= 256: print "Packing and starting anew" newGeom = True self.geom.unifyInPlace(row, False) else: newGeom = False self.completeQuadPath() if newGeom: self.newVertexData() self.newGeom() if newGeom: self.drawQuadTo(prevPos, pos, width) else: self.triStrips.addConsecutiveVertices(row - 2, 2) def extendPathTunnel(self, prevPos, pos, width): self.drawTunnelTo(prevPos, pos, width) def drawLineTo(self, pos, color): self.vertexWriter.addData3f(pos.x, pos.y, pos.z) # self.normalWriter.addData3f(0, 0, 1) self.colorWriter.addData4i(color) self.triStrips.addNextVertices(1) return 1 def drawQuadTo(self, a, b, width): """ a (to) b are vectors defining a line bisecting a new quad. """ into = (b - a) if abs(into.x) + abs(into.y) < 1: # ensure that if we jump in place, we don't get a thin segment if not self.prevInto: return into = self.prevInto else: into.normalize() # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space if self.vertexWriter.getWriteRow() == 0: self.drawQuadRow(a, into, width) verts = self.drawQuadRow(b, into, width) self.prevInto = into return verts def drawQuadRow(self, a, into, width): """ a defines a point, with 'into' being the normalized direction. """ # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space aLeft = Vec3(a.x - into.y * width, a.y + into.x * width, a.z) aRight = Vec3(a.x + into.y * width, a.y - into.x * width, a.z) row = self.vertexWriter.getWriteRow() self.vertexWriter.addData3f(aLeft) self.vertexWriter.addData3f(aRight) # self.normalWriter.addData3f(Vec3(0, 0, 1)) # self.normalWriter.addData3f(Vec3(0, 0, 1)) self.colorWriter.addData4i(self.leftColor) self.colorWriter.addData4i(self.rightColor) self.triStrips.addConsecutiveVertices(row, 2) return 2 def drawTunnelTo(self, a, b, width): """ a (to) b are vectors defining a line bisecting a new tunnel segment. """ into = (b - a) if abs(into.x) + abs(into.y) < 1: # ensure that if we jump in place, we don't get a thin segment if not self.prevInto: return into = self.prevInto else: into.normalize() # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space if self.vertexWriter.getWriteRow() == 0: self.drawTunnelBoundary(a, into, width) row = self.vertexWriter.getWriteRow() verts = self.drawTunnelBoundary(b, into, width) totalVerts = self.drawTunnelRow(row, verts) self.prevInto = into return totalVerts def drawTunnelBoundary(self, a, into, width): """ a defines a point, with 'into' being the normalized direction. """ aLowLeft = Vec3(a.x - into.y * width, a.y + into.x * width, a.z) aLowRight = Vec3(a.x + into.y * width, a.y - into.x * width, a.z) aHighRight = Vec3(a.x + into.y * width, a.y - into.x * width, a.z + width * 3) aHighLeft = Vec3(a.x - into.y * width, a.y + into.x * width, a.z + width * 3) self.vertexWriter.addData3f(aLowLeft) self.vertexWriter.addData3f(aLowRight) self.vertexWriter.addData3f(aHighRight) self.vertexWriter.addData3f(aHighLeft) self.colorWriter.addData4i(self.leftColor) self.colorWriter.addData4i(self.rightColor) self.colorWriter.addData4i(self.leftColor) self.colorWriter.addData4i(self.rightColor) return 4 def drawTunnelRowX(self, row, verts): # BOTTOM: bottom-left, new-bottom-left, bottom-right, new-bottom-right self.triStrips.addConsecutiveVertices(row - verts + 0, 1) self.triStrips.addConsecutiveVertices(row + 0, 1) self.triStrips.addConsecutiveVertices(row - verts + 1, 1) self.triStrips.addConsecutiveVertices(row + 1, 1) self.triStrips.closePrimitive() # RIGHT: (new-bottom-right) bottom-right, new-top-right, top-right self.triStrips.addConsecutiveVertices(row + 1, 1) self.triStrips.addConsecutiveVertices(row - verts + 1, 1) self.triStrips.addConsecutiveVertices(row + 2, 1) self.triStrips.addConsecutiveVertices(row - verts + 2, 1) self.triStrips.closePrimitive() # TOP: top-left, new top-right, new top-left self.triStrips.addConsecutiveVertices(row - verts + 2, 1) self.triStrips.addConsecutiveVertices(row - verts + 3, 1) self.triStrips.addConsecutiveVertices(row + 2, 1) self.triStrips.addConsecutiveVertices(row + 3, 1) self.triStrips.closePrimitive() # LEFT: (new top-left) new bottom-left, top-left, bottom-left, new-bottom-left self.triStrips.addConsecutiveVertices(row + 3, 1) self.triStrips.addConsecutiveVertices(row + 0, 1) self.triStrips.addConsecutiveVertices(row - verts + 3, 1) self.triStrips.addConsecutiveVertices(row - verts + 0, 1) self.triStrips.closePrimitive() return verts * 4 def drawTunnelRow(self, row, verts): # # clockwise for the inside of the tunnel # # TOP: new-top-left, top-left, new-top-right, top-right # self.triStrips.addConsecutiveVertices(row + 3, 1) # self.triStrips.addConsecutiveVertices(row - verts + 3, 1) # self.triStrips.addConsecutiveVertices(row + 2, 1) # self.triStrips.addConsecutiveVertices(row - verts + 2, 1) # # RIGHT: new-bottom-right, bottom-right # self.triStrips.addConsecutiveVertices(row + 1, 1) # self.triStrips.addConsecutiveVertices(row - verts + 1, 1) # # BOTTOM: new-bottom-left, bottom-left # self.triStrips.addConsecutiveVertices(row, 1) # self.triStrips.addConsecutiveVertices(row - verts, 1) # # LEFT: new top-left, top-left # self.triStrips.addConsecutiveVertices(row + 3, 1) # self.triStrips.addConsecutiveVertices(row - verts + 3, 1) # TOP: new-top-left, top-left, new-top-right, top-right self.triStrips.addConsecutiveVertices(row - verts + 3, 1) self.triStrips.addConsecutiveVertices(row + 3, 1) self.triStrips.addConsecutiveVertices(row - verts + 2, 1) self.triStrips.addConsecutiveVertices(row + 2, 1) # RIGHT: new-bottom-right, bottom-right self.triStrips.addConsecutiveVertices(row - verts + 1, 1) self.triStrips.addConsecutiveVertices(row + 1, 1) # BOTTOM: new-bottom-left, bottom-left self.triStrips.addConsecutiveVertices(row - verts, 1) self.triStrips.addConsecutiveVertices(row, 1) # LEFT: new top-left, top-left self.triStrips.addConsecutiveVertices(row - verts + 3, 1) self.triStrips.addConsecutiveVertices(row + 3, 1) self.triStrips.closePrimitive() return verts * 4 def completeQuadPath(self): self.geomNode.addGeom(self.geom) if self.triStrips.getNumPrimitives() == 0: return floorMesh = CollisionFloorMesh() vertexReader = GeomVertexReader(self.vertexData, 'vertex') tris = self.triStrips.decompose() print "Decomposed prims:",tris.getNumPrimitives() p = 0 for i in range(tris.getNumPrimitives()): v0 = tris.getPrimitiveStart(i) ve = tris.getPrimitiveEnd(i) if v0 < ve: vertexReader.setRow(tris.getVertex(v0)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(tris.getVertex(v0+1)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(tris.getVertex(v0+2)) floorMesh.addVertex(Point3(vertexReader.getData3f())) floorMesh.addTriangle(p, p+1, p+2) p += 3 self.floorCollNode.addSolid(floorMesh) def completeTunnelPath(self): self.geomNode.addGeom(self.geom) if self.triStrips.getNumPrimitives() == 0: return floorMesh = CollisionFloorMesh() vertexReader = GeomVertexReader(self.vertexData, 'vertex') print "Original prims:",self.triStrips.getNumPrimitives() p = 0 for i in range(self.triStrips.getNumPrimitives()): v0 = self.triStrips.getPrimitiveStart(i) ve = self.triStrips.getPrimitiveEnd(i) j = v0 + 4 # add the bottom triangles vertexReader.setRow(self.triStrips.getVertex(j)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(self.triStrips.getVertex(j+1)) floorMesh.addVertex(Point3(vertexReader.getData3f())) vertexReader.setRow(self.triStrips.getVertex(j+2)) floorMesh.addVertex(Point3(vertexReader.getData3f())) floorMesh.addTriangle(p, p+1, p+2) vertexReader.setRow(self.triStrips.getVertex(j+3)) floorMesh.addVertex(Point3(vertexReader.getData3f())) floorMesh.addTriangle(p+1, p+3, p+2) p += 4 # this adds every triangle, but is not appropriate for a closed path # tris = self.triStrips.decompose() # print "Decomposed prims:",tris.getNumPrimitives() # p = 0 # for i in range(tris.getNumPrimitives()): # v0 = tris.getPrimitiveStart(i) # ve = tris.getPrimitiveEnd(i) # if v0 < ve: # vertexReader.setRow(tris.getVertex(v0)) # floorMesh.addVertex(Point3(vertexReader.getData3f())) # vertexReader.setRow(tris.getVertex(v0+1)) # floorMesh.addVertex(Point3(vertexReader.getData3f())) # vertexReader.setRow(tris.getVertex(v0+2)) # floorMesh.addVertex(Point3(vertexReader.getData3f())) # floorMesh.addTriangle(p, p+1, p+2) # p += 3 self.floorCollNode.addSolid(floorMesh) def updatePhysics(self, task): pos = self.fpscamera.getPos() self.info.setText("Position: {0}, {1}, {2}".format(int(pos.x*100)/100., int(pos.y*100)/100., int(pos.z)/100.)) return task.cont
class Game(ShowBase): def __init__(self): # Set up the window, camera, etc. ShowBase.__init__(self) # Set the background color to black self.win.setClearColor(BACKGROUND_COLOR) # Set up the environment # # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) # Create the main character playerStartPos = self.environ.find("**/start_point").getPos() self.player = Actor("models/player", {"run": "models/player-run", "walk": "models/player-walk"}) self.player.reparentTo(render) self.player.setScale(0.2) self.player.setPos(playerStartPos + (0, 0, 0.5)) # Create a floater object, which floats 2 units above player. We # use this as a target for the camera to look at. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(self.player) self.floater.setZ(CAMERA_TARGET_HEIGHT_DELTA) self.first_person = False def key_dn(name): return lambda: self.setKey(name, True) def key_up(name): return lambda: self.setKey(name, False) def quit(): self.destroy() def toggle_first(): self.first_person = not self.first_person # Accept the control keys for movement and rotation key_map = [ # key command action help # --- ------- ------ ---- ("escape", "esc", lambda: quit(), "[ESC]: Quit"), ("arrow_left", "left", key_dn("left"), "[Left Arrow]: Rotate Left"), ("arrow_left-up", "left", key_up("left"), None), ("arrow_right", "right", key_dn("right"), "[Right Arrow]: Rotate Right"), ("arrow_right-up", "right", key_up("right"), None), ("arrow_up", "forward", key_dn("forward"), "[Up Arrow]: Run Forward"), ("arrow_up-up", "forward", key_up("forward"), None), ("arrow_down", "backward", key_dn("backward"), "[Down Arrow]: Run Backward"), ("arrow_down-up", "backward", key_up("backward"), None), ("a", "cam-left", key_dn("cam-left"), "[A]: Rotate Camera Left"), ("a-up", "cam-left", key_up("cam-left"), None), ("s", "cam-right", key_dn("cam-right"), "[S]: Rotate Camera Right"), ("s-up", "cam-right", key_up("cam-right"), None), ("f", "first-pers", lambda: toggle_first(), "[F]: Toggle first-person"), ] self.keyMap = {} inst = Instructions() for key, command, action, description in key_map: if command: self.setKey(command, False) self.accept(key, action) if description: inst.add(description) taskMgr.add(self.move, "moveTask") # Game state variables self.isMoving = False # Set up the camera self.disableMouse() self.camera.setPos(self.player.getX(), self.player.getY() + 10, 2) # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above player's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.playerGroundRay = CollisionRay() self.playerGroundRay.setOrigin(0, 0, 9) self.playerGroundRay.setDirection(0, 0, -1) self.playerGroundCol = CollisionNode("playerRay") self.playerGroundCol.addSolid(self.playerGroundRay) self.playerGroundCol.setFromCollideMask(CollideMask.bit(0)) self.playerGroundCol.setIntoCollideMask(CollideMask.allOff()) self.playerGroundColNp = self.player.attachNewNode(self.playerGroundCol) self.playerGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0, 0, 9) self.camGroundRay.setDirection(0, 0, -1) self.camGroundCol = CollisionNode("camRay") self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(CollideMask.bit(0)) self.camGroundCol.setIntoCollideMask(CollideMask.allOff()) self.camGroundColNp = self.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays self.playerGroundColNp.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((0.3, 0.3, 0.3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection((-5, -5, -5)) directionalLight.setColor((1, 1, 1, 1)) directionalLight.setSpecularColor((1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # Get the time that elapsed since last frame. We multiply this with # the desired speed in order to find out with which distance to move # in order to achieve that desired speed. dt = globalClock.getDt() # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. if self.keyMap["cam-left"]: self.camera.setX(self.camera, -20 * dt) if self.keyMap["cam-right"]: self.camera.setX(self.camera, +20 * dt) # save player's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.player.getPos() # If a move-key is pressed, move player in the specified direction. if self.keyMap["left"]: self.player.setH(self.player.getH() + 300 * dt) if self.keyMap["right"]: self.player.setH(self.player.getH() - 300 * dt) if self.keyMap["forward"]: self.player.setY(self.player, -25 * dt) if self.keyMap["backward"]: self.player.setY(self.player, 25 * dt) # If player 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.player.loop("run") self.isMoving = True else: if self.isMoving: self.player.stop() self.player.pose("walk", 5) self.isMoving = False # If the camera is too far from player, move it closer. # If the camera is too close to player, move it farther. if self.first_person: self.camera.setPos(self.player.getPos()) else: camvec = self.player.getPos() - self.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if camdist > CAMERA_DISTANCE_MAX: self.camera.setPos(self.camera.getPos() + camvec * (camdist - int(CAMERA_DISTANCE_MAX))) camdist = CAMERA_DISTANCE_MAX if camdist < CAMERA_DISTANCE_MIN: self.camera.setPos(self.camera.getPos() - camvec * (int(CAMERA_DISTANCE_MIN) - camdist)) camdist = CAMERA_DISTANCE_MIN # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. self.cTrav.traverse(render) # Adjust player's Z coordinate. If player's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = list(self.playerGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain": self.player.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.player.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above player, whichever is greater. entries = list(self.camGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain": self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + CAMERA_POSITION_HEIGHT_DELTA_MIN) if self.camera.getZ() < self.player.getZ() + CAMERA_POSITION_HEIGHT_DELTA_MAX: self.camera.setZ(self.player.getZ() + CAMERA_POSITION_HEIGHT_DELTA_MAX) # The camera should look in player's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above player's head. self.camera.lookAt(self.floater) return task.cont
class Game(ShowBase): def __init__(self): # Set up the window, camera, etc. ShowBase.__init__(self) # Set the background color to black self.win.setClearColor(BACKGROUND_COLOR) # Set up the environment # # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) # Create the main character playerStartPos = self.environ.find("**/start_point").getPos() self.player = Actor("models/player", {"run": "models/player-run", "walk": "models/player-walk"}) self.player.reparentTo(render) self.player.setScale(.2) self.player.setPos(playerStartPos + (0, 0, 0.5)) # Create a floater object, which floats 2 units above player. We # use this as a target for the camera to look at. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(self.player) self.floater.setZ(CAMERA_TARGET_HEIGHT_DELTA) self.first_person = False def key_dn(name): return lambda: self.setKey(name, True) def key_up(name): return lambda: self.setKey(name, False) def quit(): self.destroy() def toggle_first(): self.first_person = not self.first_person # Accept the control keys for movement and rotation key_map = [ # key command action help # --- ------- ------ ---- ("escape", "esc", lambda: quit(), '[ESC]: Quit'), ("arrow_left", 'left', key_dn("left"), "[Left Arrow]: Rotate Left"), ("arrow_left-up", 'left', key_up("left"), None), ("arrow_right", 'right', key_dn("right"), "[Right Arrow]: Rotate Right"), ("arrow_right-up", 'right', key_up("right"), None), ("arrow_up", 'forward', key_dn("forward"), "[Up Arrow]: Run Forward"), ("arrow_up-up", 'forward', key_up("forward"), None), ("arrow_down", 'backward', key_dn("backward"), "[Down Arrow]: Run Backward"), ("arrow_down-up", 'backward', key_up("backward"), None), ("a", 'cam-left', key_dn("cam-left"), "[A]: Rotate Camera Left"), ("a-up", 'cam-left', key_up("cam-left"), None), ("s", 'cam-right', key_dn("cam-right"), "[S]: Rotate Camera Right"), ("s-up", 'cam-right', key_up("cam-right"), None), ('f', 'first-pers', lambda: toggle_first(), '[F]: Toggle first-person'), ] self.keyMap = {} inst = Instructions() for key, command, action, description in key_map: if command: self.setKey(command, False) self.accept(key, action) if description: inst.add(description) taskMgr.add(self.move, "moveTask") # Game state variables self.isMoving = False # Set up the camera self.disableMouse() self.camera.setPos(self.player.getX(), self.player.getY() + 10, 2) # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above player's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.playerGroundRay = CollisionRay() self.playerGroundRay.setOrigin(0, 0, 9) self.playerGroundRay.setDirection(0, 0, -1) self.playerGroundCol = CollisionNode('playerRay') self.playerGroundCol.addSolid(self.playerGroundRay) self.playerGroundCol.setFromCollideMask(CollideMask.bit(0)) self.playerGroundCol.setIntoCollideMask(CollideMask.allOff()) self.playerGroundColNp = self.player.attachNewNode(self.playerGroundCol) self.playerGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0, 0, 9) self.camGroundRay.setDirection(0, 0, -1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(CollideMask.bit(0)) self.camGroundCol.setIntoCollideMask(CollideMask.allOff()) self.camGroundColNp = self.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays self.playerGroundColNp.show() self.camGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring self.cTrav.showCollisions(render) # Create some lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection((-5, -5, -5)) directionalLight.setColor((1, 1, 1, 1)) directionalLight.setSpecularColor((1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # Get the time that elapsed since last frame. We multiply this with # the desired speed in order to find out with which distance to move # in order to achieve that desired speed. dt = globalClock.getDt() # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. if self.keyMap["cam-left"]: self.camera.setX(self.camera, -20 * dt) if self.keyMap["cam-right"]: self.camera.setX(self.camera, +20 * dt) # save player's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.player.getPos() # If a move-key is pressed, move player in the specified direction. if self.keyMap["left"]: self.player.setH(self.player.getH() + 300 * dt) if self.keyMap["right"]: self.player.setH(self.player.getH() - 300 * dt) if self.keyMap["forward"]: self.player.setY(self.player, -25 * dt) if self.keyMap["backward"]: self.player.setY(self.player, 25 * dt) # If player 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.player.loop("run") self.isMoving = True else: if self.isMoving: self.player.stop() self.player.pose("walk", 5) self.isMoving = False # If the camera is too far from player, move it closer. # If the camera is too close to player, move it farther. if self.first_person: self.camera.setPos(self.player.getPos()) else: camvec = self.player.getPos() - self.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if camdist > CAMERA_DISTANCE_MAX: self.camera.setPos(self.camera.getPos() + camvec * (camdist - int(CAMERA_DISTANCE_MAX))) camdist = CAMERA_DISTANCE_MAX if camdist < CAMERA_DISTANCE_MIN: self.camera.setPos(self.camera.getPos() - camvec * (int(CAMERA_DISTANCE_MIN) - camdist)) camdist = CAMERA_DISTANCE_MIN # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. self.cTrav.traverse(render) # Adjust player's Z coordinate. If player's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = list(self.playerGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain": self.player.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.player.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above player, whichever is greater. entries = list(self.camGroundHandler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain": self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + CAMERA_POSITION_HEIGHT_DELTA_MIN) if self.camera.getZ() < self.player.getZ() + CAMERA_POSITION_HEIGHT_DELTA_MAX: self.camera.setZ(self.player.getZ() + CAMERA_POSITION_HEIGHT_DELTA_MAX) # The camera should look in player's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above player's head. self.camera.lookAt(self.floater) return task.cont
class TutorialGame(ShowBase): def __init__(self): # call superclass init (no implicit chaining) ShowBase.__init__(self) ######### load player model self.player = loader.loadModel("panda") self.player.setScale(0.1) self.player.reparentTo(render) self.player.setY(10) ######### move camera for tilted overhead view base.disableMouse() base.camera.setPos(0, -10, 10) base.camera.lookAt(self.player) ######### load "obstacle" model self.obs = loader.loadModel("models/box") self.obs.setScale(0.1) # re-use same model for multiple objects self.OBS = [] for i in range(0, 4): n = render.attachNewNode("Obstacle") self.obs.instanceTo(n) n.reparentTo(render) n.setPos(-1.5 + random.random() * 8.0, 8.5 + random.random() * 8.0, 0) self.OBS.append(n) ######### add directional light dlight = DirectionalLight('dlight') dlight.setColor((1, 1, 1, 1)) self.dlnp = render.attachNewNode(dlight) render.setLight(self.dlnp) dlight.setDirection(LVector3(-0.8, 0, 0)) ######### setup other systems self.setupInput() self.setupCollision() # pre-frame update taskMgr.add(self.update, "update") # helper for taking in input def setKey(self, key, value): self.keyMap[key] = value def setupInput(self): self.keyMap = {"left": 0, "right": 0, "fwd": 0, "back": 0} # this sets values in keyMap to True when keys are pressed self.accept("escape", sys.exit) self.accept("w", self.setKey, ["fwd", True]) self.accept("a", self.setKey, ["left", True]) self.accept("s", self.setKey, ["back", True]) self.accept("d", self.setKey, ["right", True]) # this sets values in keyMap to False when keys are released self.accept("w-up", self.setKey, ["fwd", False]) self.accept("a-up", self.setKey, ["left", False]) self.accept("s-up", self.setKey, ["back", False]) self.accept("d-up", self.setKey, ["right", False]) def setupCollision(self): cs = CollisionSphere(0, 0, 0, 10) cnodePath = self.player.attachNewNode(CollisionNode('cnode')) cnodePath.node().addSolid(cs) cnodePath.show() for o in self.OBS: ct = CollisionBox(0, 1, 1, 0.5) cn = o.attachNewNode(CollisionNode('ocnode')) cn.node().addSolid(ct) cn.show() pusher = CollisionHandlerPusher() pusher.addCollider(cnodePath, self.player) self.cTrav = CollisionTraverser() self.cTrav.addCollider(cnodePath, pusher) self.cTrav.showCollisions(render) # move the player based on the keyMap input def update(self, task): dt = globalClock.getDt() # user input if self.keyMap["fwd"]: self.player.setY(self.player.getY() + SPEED * dt) if self.keyMap["back"]: self.player.setY(self.player.getY() - SPEED * dt) if self.keyMap["left"]: self.player.setX(self.player.getX() - SPEED * dt) if self.keyMap["right"]: self.player.setX(self.player.getX() + SPEED * dt) return task.cont
class TheWorld(ShowBase): def __init__(self): ShowBase.__init__(self) self.params = { "mouse_x": 0, "mouse_y": 0, } self.disableMouse() self.cmd_mgr = commandmgr.TheWorldCommandMgr(self) util.hidden_relative_mouse(self) for cmd_str, cmd_fn in self.cmd_mgr.mapping.items(): self.accept(cmd_str, cmd_fn) # environment self.setBackgroundColor(.0, .0, .0, 1) # # ground self.ground_cube = self.loader.loadModel("cuby.gltf") self.ground_cube.setColor(1, 1, 1, 1) ground_cube_size = Vec3(2, 2, .4) self.ground_cube.setScale(ground_cube_size) self.ground = self.render.attachNewNode("ground") grid_size = 5 grid_max = grid_size - 1 dist = 8 grid_coordinates = itertools.product(range(grid_size), range(grid_size)) def normalize(x_y): x, y = x_y return (x - grid_max / 2) * dist, (y - grid_max / 2) * dist for x, y in map(normalize, grid_coordinates): placeholder = self.ground.attachNewNode("placeholder") placeholder.setPos(x, y, -ground_cube_size.z) self.ground_cube.instanceTo(placeholder) # collision ground coll_node = CollisionNode(f"ground_{x}_{y}") coll_node.setFromCollideMask(CollideMask.allOff()) coll_node.setIntoCollideMask(CollideMask.bit(0)) nodepath = placeholder.attachNewNode(coll_node) nodepath.node().addSolid( CollisionBox(Point3(0, 0, 0), ground_cube_size.x, ground_cube_size.y, ground_cube_size.z)) # lighting ambient_light = AmbientLight("ambient_light") ambient_light.setColor((.2, .2, .2, 1)) alight = self.render.attachNewNode(ambient_light) self.render.setLight(alight) # actor self.actor_obj = Actor(self, self.render, "cuby.gltf") self.actor = self.actor_obj.node self.actor.setColor(cube_color) # # collision actor self.cTrav = CollisionTraverser('traverser') self.cTrav.showCollisions(self.actor) self.actor_coll = CollisionNode('actor') self.actor_coll.addSolid(CollisionBox(Point3(0, 0, 0), 1, 1, 1)) self.actor_coll.setFromCollideMask(CollideMask.bit(0)) self.actor_coll.setIntoCollideMask(CollideMask.allOff()) self.actor_coll_np = self.actor.attachNewNode(self.actor_coll) self.pusher = CollisionHandlerPusher() self.pusher.addCollider(self.actor_coll_np, self.actor) self.cTrav.addCollider(self.actor_coll_np, self.pusher) # lighting self.centerlight_np = self.render.attachNewNode("basiclightcenter") self.centerlight_np.hprInterval(4, (360, 0, 0)).loop() d, h = 8, 1 self.basic_point_light((-d, 0, h), (.0, .0, .7, 1), "left_light") self.basic_point_light((d, 0, h), (.0, .7, 0, 1), "right_light") self.basic_point_light((0, d, h), (.7, .0, .0, 1), "front_light") self.basic_point_light((0, -d, h), (1, 1, 1, 1), "back_light") self.actor_stater = Stater(self.actor) self.cmd_mgr.set_actor_stater(self.actor_stater) self.actor_mover = Mover(self, self.actor_obj, self.actor_stater) self.camera.wrtReparentTo(self.actor) self.camera.setPos(Vec3(0, 4, 1).normalized() * cam_dist) self.camera.lookAt(0, 0, 0) self.taskMgr.add(self.update_params, "paramsTask") self.taskMgr.add(self.actor_mover.execute, "moveTask") self.taskMgr.add(self.log, "logTask") self.render.setShaderAuto() def update_params(self, task): if self.mouseWatcherNode.hasMouse(): self.params["mouse_x"] = self.mouseWatcherNode.getMouseX() self.params["mouse_y"] = self.mouseWatcherNode.getMouseY() self.win.movePointer(0, self.win.getProperties().getXSize() // 2, self.win.getProperties().getYSize() // 2) self.params["actor_pos"] = self.actor.getPos() return Task.cont def log(self, task): return Task.cont def basic_point_light(self, position, color, name, attenuation=(1, 0, 0.02)): light = PointLight(name) light.setColor(color) light.setAttenuation(attenuation) # light.setShadowCaster(True) # light.getLens().setNearFar(5, 20) plight = self.centerlight_np.attachNewNode(light) plight.setPos(position) self.render.setLight(plight) light_cube = self.loader.loadModel("cuby.gltf") light_cube.reparentTo(plight) light_cube.setScale(0.25) material = Material() material.setEmission(color) light_cube.setMaterial(material)
class PandaPath(ShowBase): def __init__(self): # Set up the window, camera, etc. ShowBase.__init__(self) # Set the background color to black self.win.setClearColor((0, 0, 0, 1)) # This is used to store which keys are currently pressed. self.key_map = {"left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0} # Post the Instruction self.title = add_title("Panda 3D Demo") # Instructions self.inst1 = add_instructions(0.06, "[ESC]: Quit") self.inst2 = add_instructions(0.12, "[Left Arrow]: Rotate Left") self.inst3 = add_instructions(0.18, "[Right Arrow]: Rotate Ralph Right") self.inst4 = add_instructions(0.24, "[Up Arrow]: Run Ralph Forward") # self.inst6 = add_instructions(0.30, "[A]: Rotate Camera Left") # self.inst7 = add_instructions(0.36, "[S]: Rotate Camera Right") # Load the Environment Model self.environ = self.loader.loadModel(ENVIRONMENT) # Reparent the model to the render controller self.environ.reparentTo(render) # Apply scale and position transform on the model # self.environ.setScale(0.25, 0.25, 0.25) # self.environ.setPos(-8, 42, 0) # Create the Main Character # Load and transform the panda actor ralph_start_pos = self.environ.find("**/start_point").getPos() self.ralph = Actor(RALPH_ACTOR, RALPH_ACTIONS) # self.ralph.setScale(0.005, 0.005, 0.005) self.ralph.reparentTo(render) # Loop it's animation self.ralph.setScale(0.2) self.ralph.setPos(ralph_start_pos + (0, 0, 0.5)) # self.ralph.loop("walk") # Create a floater object, which floats 2 units above rlaph. We use this as a target for the camera to look at self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(self.ralph) # 2 Units above Ralph self.floater.setZ(2.0) # Configure the Camera # Add the spin camera taks procedure to the taks manager # self.taskMgr.add(self.spinCameraTask, "SpinCameraTask") # Accept certain control keys self.accept("escape", sys.exit) self.accept("arrow_left", self.set_key, ["left", True]) self.accept("arrow_right", self.set_key, ["right", True]) self.accept("arrow_up", self.set_key, ["forward", True]) self.accept("a", self.set_key, ["cam-left", True]) self.accept("s", self.set_key, ["cam-right", True]) self.accept("arrow_left-up", self.set_key, ["left", False]) self.accept("arrow_right-up", self.set_key, ["right", False]) self.accept("arrow_up-up", self.set_key, ["forward", False]) self.accept("a-up", self.set_key, ["cam-left", False]) self.accept("s-up", self.set_key, ["cam-right", False]) # Game States taskMgr.add(self.move, "moveTask") self.is_moving = False self.disableMouse() self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2) self.camera.lookAt(self.floater) """ Detect the height of hte terrain by creating a collision ray and casting it down towards 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 ca ndetect the height. If it hits anything else, we rule that the move is illegal. """ self.cTrav = CollisionTraverser() # Create a vector, it's location is at the top of ralph's head self.ralph_ground_ray = CollisionRay() self.ralph_ground_ray.setOrigin(0, 0, 9) # Top of ralph's head self.ralph_ground_ray.setDirection(0, 0, -1) # Points -Z axis # Create a Collision node self.ralph_ground_col = CollisionNode("ralph_ray") # Give the node a name self.ralph_ground_col.addSolid(self.ralph_ground_ray) # the vector from ralph's head to the ground is solid self.ralph_ground_col.setFromCollideMask(CollideMask.bit(0)) # ?? self.ralph_ground_col.setIntoCollideMask( CollideMask.allOff() ) # ?? This seems like it defines the behavior of ray self.ralph_ground_col_np = self.ralph.attachNewNode(self.ralph_ground_col) # Attach the ray to ralph self.ralph_ground_handler = ( CollisionHandlerQueue() ) # I think that when a collision occurs it sends through this self.cTrav.addCollider(self.ralph_ground_col_np, self.ralph_ground_handler) # Attach the collision """ Attach the a camera ray to the camera """ self.cam_ground_ray = CollisionRay() self.cam_ground_ray.setOrigin(0, 0, 9) self.cam_ground_ray.setDirection(0, 0, -1) self.cam_ground_col = CollisionNode("camera_ray") self.cam_ground_col.addSolid(self.cam_ground_ray) self.cam_ground_col.setFromCollideMask(CollideMask.bit(0)) self.cam_ground_col.setIntoCollideMask(CollideMask.allOff()) self.cam_ground_col_np = self.camera.attachNewNode(self.cam_ground_col) self.cam_ground_handler = CollisionHandlerQueue() self.cTrav.addCollider(self.cam_ground_col_np, self.cam_ground_handler) # Uncomment the following lines to view the rays self.ralph_ground_col_np.show() self.cam_ground_col_np.show() # Uncomment this line to show a visual representation of the Collision occuring self.cTrav.showCollisions(render) # Create some lighting ambient_light = AmbientLight("ambient_light") ambient_light.setColor((0.3, 0.3, 0.3, 1)) directional_light = DirectionalLight("directional_light") directional_light.setDirection((-5, -5, -5)) directional_light.setColor((1, 1, 1, 1)) directional_light.setSpecularColor((1, 1, 1, 1)) render.setLight(render.attachNewNode(ambient_light)) render.setLight(render.attachNewNode(directional_light)) # Add Cube X_OFFSET = 0 Y_OFFSET = -3 Z_OFFSET = 1 CUBE_SIZE = 2 x, y, z = ralph_start_pos x += X_OFFSET y += Y_OFFSET z += Z_OFFSET # make_cube(x, y, z, CUBE_SIZE) def set_key(self, key, value): self.key_map[key] = value def move(self, task): dt = globalClock.getDt() # print "DT: %f" % dt # ****: Movement # Get Ralph's position before we do anything to it start_pos = self.ralph.getPos() # User wants to turn if self.key_map["left"]: self.ralph.setH(self.ralph.getH() + 300 * dt) if self.key_map["right"]: self.ralph.setH(self.ralph.getH() - 300 * dt) # Perform a move forward if self.key_map["forward"]: self.ralph.setY(self.ralph, -25 * dt) # ****: Animation if self.key_map["forward"] or self.key_map["left"] or self.key_map["right"]: if not self.is_moving: self.ralph.loop("run") self.is_moving = True else: if self.is_moving: self.ralph.stop() self.ralph.pose("walk", 5) self.is_moving = False # ****: Camera Movement if self.key_map["cam-left"]: self.camera.setX(self.camera, -20 * dt) elif self.key_map["cam-right"]: self.camera.setX(self.camera, +20 * dt) # 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 # ****: Collision """ 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 Adjust ralph's Z coordinate. If ralph's ray hit terrain update his Z. If it hit anything else, or didn't hit anything put him back where he was last frame. """ entries = list(self.ralph_ground_handler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) # print "Entry count: %d" % len(entries) if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain": self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.ralph.setPos(start_pos) # Keep the camera at one foot above the terrain or two feet above ralph, whichever is greater entries = list(self.cam_ground_handler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0 and entries[0].getIntoNode().getName() == "terrain": self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0) if self.camera.getZ() < self.ralph.getZ() + 2.0: self.camera.setZ(self.ralph.getZ() + 2.0) """ The camera should look in rlaphs direction, but it should also try to stay horizontal so look at a floater which hovers above ralph's head """ self.camera.lookAt(self.floater) return task.cont
class 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 PandaPath(ShowBase): def __init__(self): #Set up the window, camera, etc. ShowBase.__init__(self) #Set the background color to black self.win.setClearColor((0, 0, 0, 1)) # This is used to store which keys are currently pressed. self.key_map = { "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0 } #Post the Instruction self.title = add_title("Panda 3D Demo") #Instructions self.inst1 = add_instructions(0.06, "[ESC]: Quit") self.inst2 = add_instructions(0.12, "[Left Arrow]: Rotate Left") self.inst3 = add_instructions(0.18, "[Right Arrow]: Rotate Ralph Right") self.inst4 = add_instructions(0.24, "[Up Arrow]: Run Ralph Forward") #self.inst6 = add_instructions(0.30, "[A]: Rotate Camera Left") #self.inst7 = add_instructions(0.36, "[S]: Rotate Camera Right") #Load the Environment Model self.environ = self.loader.loadModel(ENVIRONMENT) #Reparent the model to the render controller self.environ.reparentTo(render) #Apply scale and position transform on the model #self.environ.setScale(0.25, 0.25, 0.25) #self.environ.setPos(-8, 42, 0) #Create the Main Character #Load and transform the panda actor ralph_start_pos = self.environ.find("**/start_point").getPos() self.ralph = Actor(RALPH_ACTOR, RALPH_ACTIONS) #self.ralph.setScale(0.005, 0.005, 0.005) self.ralph.reparentTo(render) #Loop it's animation self.ralph.setScale(0.2) self.ralph.setPos(ralph_start_pos + (0, 0, 0.5)) #self.ralph.loop("walk") #Create a floater object, which floats 2 units above rlaph. We use this as a target for the camera to look at self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(self.ralph) #2 Units above Ralph self.floater.setZ(2.0) #Configure the Camera #Add the spin camera taks procedure to the taks manager #self.taskMgr.add(self.spinCameraTask, "SpinCameraTask") #Accept certain control keys self.accept("escape", sys.exit) self.accept("arrow_left", self.set_key, ["left", True]) self.accept("arrow_right", self.set_key, ["right", True]) self.accept("arrow_up", self.set_key, ["forward", True]) self.accept("a", self.set_key, ["cam-left", True]) self.accept("s", self.set_key, ["cam-right", True]) self.accept("arrow_left-up", self.set_key, ["left", False]) self.accept("arrow_right-up", self.set_key, ["right", False]) self.accept("arrow_up-up", self.set_key, ["forward", False]) self.accept("a-up", self.set_key, ["cam-left", False]) self.accept("s-up", self.set_key, ["cam-right", False]) #Game States taskMgr.add(self.move, "moveTask") self.is_moving = False self.disableMouse() self.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2) self.camera.lookAt(self.floater) ''' Detect the height of hte terrain by creating a collision ray and casting it down towards 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 ca ndetect the height. If it hits anything else, we rule that the move is illegal. ''' self.cTrav = CollisionTraverser() #Create a vector, it's location is at the top of ralph's head self.ralph_ground_ray = CollisionRay() self.ralph_ground_ray.setOrigin(0, 0, 9) # Top of ralph's head self.ralph_ground_ray.setDirection(0, 0, -1) # Points -Z axis #Create a Collision node self.ralph_ground_col = CollisionNode( 'ralph_ray') # Give the node a name self.ralph_ground_col.addSolid( self.ralph_ground_ray ) # the vector from ralph's head to the ground is solid self.ralph_ground_col.setFromCollideMask(CollideMask.bit(0)) # ?? self.ralph_ground_col.setIntoCollideMask(CollideMask.allOff( )) # ?? This seems like it defines the behavior of ray self.ralph_ground_col_np = self.ralph.attachNewNode( self.ralph_ground_col) #Attach the ray to ralph self.ralph_ground_handler = CollisionHandlerQueue( ) #I think that when a collision occurs it sends through this self.cTrav.addCollider( self.ralph_ground_col_np, self.ralph_ground_handler) #Attach the collision ''' Attach the a camera ray to the camera ''' self.cam_ground_ray = CollisionRay() self.cam_ground_ray.setOrigin(0, 0, 9) self.cam_ground_ray.setDirection(0, 0, -1) self.cam_ground_col = CollisionNode("camera_ray") self.cam_ground_col.addSolid(self.cam_ground_ray) self.cam_ground_col.setFromCollideMask(CollideMask.bit(0)) self.cam_ground_col.setIntoCollideMask(CollideMask.allOff()) self.cam_ground_col_np = self.camera.attachNewNode(self.cam_ground_col) self.cam_ground_handler = CollisionHandlerQueue() self.cTrav.addCollider(self.cam_ground_col_np, self.cam_ground_handler) #Uncomment the following lines to view the rays self.ralph_ground_col_np.show() self.cam_ground_col_np.show() #Uncomment this line to show a visual representation of the Collision occuring self.cTrav.showCollisions(render) # Create some lighting ambient_light = AmbientLight("ambient_light") ambient_light.setColor((0.3, 0.3, 0.3, 1)) directional_light = DirectionalLight("directional_light") directional_light.setDirection((-5, -5, -5)) directional_light.setColor(( 1, 1, 1, 1, )) directional_light.setSpecularColor((1, 1, 1, 1)) render.setLight(render.attachNewNode(ambient_light)) render.setLight(render.attachNewNode(directional_light)) #Add Cube X_OFFSET = 0 Y_OFFSET = -3 Z_OFFSET = 1 CUBE_SIZE = 2 x, y, z = ralph_start_pos x += X_OFFSET y += Y_OFFSET z += Z_OFFSET #make_cube(x, y, z, CUBE_SIZE) def set_key(self, key, value): self.key_map[key] = value def move(self, task): dt = globalClock.getDt() #print "DT: %f" % dt #****: Movement #Get Ralph's position before we do anything to it start_pos = self.ralph.getPos() #User wants to turn if self.key_map["left"]: self.ralph.setH(self.ralph.getH() + 300 * dt) if self.key_map["right"]: self.ralph.setH(self.ralph.getH() - 300 * dt) #Perform a move forward if self.key_map["forward"]: self.ralph.setY(self.ralph, -25 * dt) #****: Animation if self.key_map["forward"] or self.key_map["left"] or self.key_map[ "right"]: if not self.is_moving: self.ralph.loop("run") self.is_moving = True else: if self.is_moving: self.ralph.stop() self.ralph.pose("walk", 5) self.is_moving = False #****: Camera Movement if self.key_map["cam-left"]: self.camera.setX(self.camera, -20 * dt) elif self.key_map["cam-right"]: self.camera.setX(self.camera, +20 * dt) #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 #****: Collision """ 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 Adjust ralph's Z coordinate. If ralph's ray hit terrain update his Z. If it hit anything else, or didn't hit anything put him back where he was last frame. """ entries = list(self.ralph_ground_handler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) #print "Entry count: %d" % len(entries) if len(entries) > 0 and entries[0].getIntoNode().getName( ) == "terrain": self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.ralph.setPos(start_pos) #Keep the camera at one foot above the terrain or two feet above ralph, whichever is greater entries = list(self.cam_ground_handler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0 and entries[0].getIntoNode().getName( ) == "terrain": self.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0) if self.camera.getZ() < self.ralph.getZ() + 2.0: self.camera.setZ(self.ralph.getZ() + 2.0) """ The camera should look in rlaphs direction, but it should also try to stay horizontal so look at a floater which hovers above ralph's head """ self.camera.lookAt(self.floater) return task.cont