class Physics: def __init__(self): self.rayCTrav = CollisionTraverser("collision traverser for ray tests") #self.pusher = PhysicsCollisionHandler() self.pusher = CollisionHandlerPusher() self.pusher.addInPattern('%fn-in-%in') self.pusher.addOutPattern('%fn-out-%in') self.pusher.addInPattern('%fn-in') self.pusher.addOutPattern('%fn-out') def startPhysics(self): #self.actorNode = ActorNode("playerPhysicsControler") #base.physicsMgr.attachPhysicalNode(self.actorNode) #self.actorNode.getPhysicsObject().setMass(self.player_mass) #self.mainNode = render.attachNewNode(self.actorNode) self.mainNode = render.attachNewNode("CharacterColliders") self.reparentTo(self.mainNode) charCollisions = self.mainNode.attachNewNode(CollisionNode(self.char_collision_name)) #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0, self.player_height/4.0)) #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0*3.05, self.player_height/4.0)) charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/2.0, self.player_height/4.0)) charCollisions.node().setIntoCollideMask(BitMask32(0x80)) # 1000 0000 if self.show_collisions: charCollisions.show() self.pusher.addCollider(charCollisions, self.mainNode) base.cTrav.addCollider(charCollisions, self.pusher) charFFootCollisions = self.attachNewNode(CollisionNode("floor_ray")) charFFootCollisions.node().addSolid(CollisionRay(0, 0, 0.5, 0, 0, -1)) #charFFootCollisions.node().addSolid(CollisionSegment((0, 0, 0.2), (0, 0, -1))) charFFootCollisions.node().setIntoCollideMask(BitMask32.allOff()) charFFootCollisions.node().setFromCollideMask(BitMask32(0x7f)) # 0111 1111 if self.show_collisions: charFFootCollisions.show() self.floor_handler = CollisionHandlerFloor() self.floor_handler.addCollider(charFFootCollisions, self.mainNode) #self.floor_handler.setOffset(0) self.floor_handler.setMaxVelocity(5) base.cTrav.addCollider(charFFootCollisions, self.floor_handler) self.accept("{}-in".format(self.char_collision_name), self.checkCharCollisions) self.raytest_segment = CollisionSegment(0, 1) self.raytest_np = render.attachNewNode(CollisionNode("testRay")) self.raytest_np.node().addSolid(self.raytest_segment) self.raytest_np.node().setIntoCollideMask(BitMask32.allOff()) self.raytest_np.node().setFromCollideMask(BitMask32(0x7f)) # 0111 1111 if self.show_collisions: self.raytest_np.show() self.raytest_queue = CollisionHandlerQueue() self.rayCTrav.addCollider(self.raytest_np, self.raytest_queue) def stopPhysics(self): self.raytest_segment.removeNode() self.pusher.clearColliders() self.floor_handler.clearColliders() self.rayCTrav.clearColliders() def updatePlayerPos(self, speed, heading, dt): if heading is not None: self.mainNode.setH(camera, heading) self.mainNode.setP(0) self.mainNode.setR(0) self.mainNode.setFluidPos(self.mainNode, speed) self.doStep() def checkCharCollisions(self, args): self.doStep() def doStep(self): # do the step height check tmpNP = self.mainNode.attachNewNode("temporary") tmpNP.setPos(self.mainNode, 0, 0, -self.stepheight) pointA = self.mainNode.getPos(render) pointA.setZ(pointA.getZ() + self.player_height/1.8) pointB = tmpNP.getPos(render) if pointA == pointB: return char_step_collision = self.getFirstCollisionInLine(pointA, pointB) tmpNP.removeNode() if char_step_collision is not None: self.mainNode.setFluidZ(char_step_collision.getZ()) return True return False def getFirstCollisionInLine(self, pointA, pointB): """A simple raycast check which will return the first collision point as seen from point A towards pointB""" self.raytest_segment.setPointA(pointA) self.raytest_segment.setPointB(pointB) self.rayCTrav.traverse(render) self.raytest_queue.sortEntries() pos = None if self.raytest_queue.getNumEntries() > 0: pos = self.raytest_queue.getEntry(0).getSurfacePoint(render) return pos
class Picker(object): """ Generic object picker class for Panda3d. Given a top Node Path to search, it finds the closest collision object under the mouse pointer. Picker takes a topNode to test for mouse ray collisions. the pick() method returns (NodePathPicked, 3dPosition, rawNode) underneath the mouse position. If no collision was detected, it returns None, None, None. 'NodePathPicked' is the deepest NAMED node path that was collided with, this is usually what you want. rawNode is the deep node (such as geom) if you want to play with that. 3dPosition is where the mouse ray touched the surface. The picker object uses base.camera to collide, so if you have a custom camera, well, sorry bout that. pseudo code: p = Picker(mycollisionTopNode) thingPicked, positionPicked, rawNode = p.pick() if thingPicked: # do something here like thingPicked.ls() """ def __init__(self, topNode, cameraObject = None): self.traverser = CollisionTraverser() self.handler = CollisionHandlerQueue() self.topNode = topNode self.cam = cameraObject pickerNode = CollisionNode('MouseRay') #NEEDS to be set to global camera. boo hoo self.pickerNP = base.camera.attachNewNode(pickerNode) # this seems to enter the bowels of the node graph, making it # difficult to perform logic on pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.pickRay = CollisionRay() #pickerNode.setCollideMask(BitMask32.allOff()) pickerNode.addSolid(self.pickRay) self.traverser.addCollider(self.pickerNP, self.handler) def setTopNode(self, topNode): """set the topmost node to traverse when detecting collisions""" self.topNode = topNode def destroy(self): """clean up my stuff.""" self.ignoreAll() # remove colliders, subnodes and such self.pickerNP.remove() self.traverser.clearColliders() def pick(self): """ pick closest object under the mouse if available. returns ( NodePathPicked, surfacePoint, rawNode ) or (None, None None) """ if not self.topNode: return None, None, None if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(self.topNode) if self.handler.getNumEntries() > 0: self.handler.sortEntries() picked = self.handler.getEntry(0).getIntoNodePath() thepoint = self.handler.getEntry(0).getSurfacePoint(self.topNode) return self.getFirstParentWithName(picked), thepoint, picked return None, None, None def getFirstParentWithName(self, pickedObject): """ return first named object up the node chain from the picked node. This helps remove drudgery when you just want to find a simple object to work with. Normally, you wouldn't use this method directly. """ name = pickedObject.getName() parent = pickedObject while not name: parent = parent.getParent() if not parent: raise Exception("Node '%s' needs a parent with a name to accept clicks." % (str(pickedObject))) name = parent.getName() if parent == self.topNode: raise Exception("Collision parent '%s' is top Node, surely you wanted to click something beneath it..." % (str(parent))) return parent
class Physics: def __init__(self): self.rayCTrav = CollisionTraverser("collision traverser for ray tests") #self.pusher = PhysicsCollisionHandler() self.pusher = CollisionHandlerPusher() self.pusher.addInPattern('%fn-in-%in') self.pusher.addOutPattern('%fn-out-%in') self.pusher.addInPattern('%fn-in') self.pusher.addOutPattern('%fn-out') def startPhysics(self): #self.actorNode = ActorNode("playerPhysicsControler") #base.physicsMgr.attachPhysicalNode(self.actorNode) #self.actorNode.getPhysicsObject().setMass(self.player_mass) #self.mainNode = render.attachNewNode(self.actorNode) self.mainNode = render.attachNewNode("CharacterColliders") self.reparentTo(self.mainNode) charCollisions = self.mainNode.attachNewNode( CollisionNode(self.char_collision_name)) #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0, self.player_height/4.0)) #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0*3.05, self.player_height/4.0)) charCollisions.node().addSolid( CollisionSphere(0, 0, self.player_height / 2.0, self.player_height / 4.0)) charCollisions.node().setIntoCollideMask(BitMask32(0x80)) # 1000 0000 if self.show_collisions: charCollisions.show() self.pusher.addCollider(charCollisions, self.mainNode) base.cTrav.addCollider(charCollisions, self.pusher) charFFootCollisions = self.attachNewNode(CollisionNode("floor_ray")) charFFootCollisions.node().addSolid(CollisionRay(0, 0, 0.5, 0, 0, -1)) #charFFootCollisions.node().addSolid(CollisionSegment((0, 0, 0.2), (0, 0, -1))) charFFootCollisions.node().setIntoCollideMask(BitMask32.allOff()) charFFootCollisions.node().setFromCollideMask( BitMask32(0x7f)) # 0111 1111 if self.show_collisions: charFFootCollisions.show() self.floor_handler = CollisionHandlerFloor() self.floor_handler.addCollider(charFFootCollisions, self.mainNode) #self.floor_handler.setOffset(0) self.floor_handler.setMaxVelocity(5) base.cTrav.addCollider(charFFootCollisions, self.floor_handler) self.accept("{}-in".format(self.char_collision_name), self.checkCharCollisions) self.raytest_segment = CollisionSegment(0, 1) self.raytest_np = render.attachNewNode(CollisionNode("testRay")) self.raytest_np.node().addSolid(self.raytest_segment) self.raytest_np.node().setIntoCollideMask(BitMask32.allOff()) self.raytest_np.node().setFromCollideMask(BitMask32(0x7f)) # 0111 1111 if self.show_collisions: self.raytest_np.show() self.raytest_queue = CollisionHandlerQueue() self.rayCTrav.addCollider(self.raytest_np, self.raytest_queue) def stopPhysics(self): self.raytest_segment.removeNode() self.pusher.clearColliders() self.floor_handler.clearColliders() self.rayCTrav.clearColliders() def updatePlayerPos(self, speed, heading, dt): if heading is not None: self.mainNode.setH(camera, heading) self.mainNode.setP(0) self.mainNode.setR(0) self.mainNode.setFluidPos(self.mainNode, speed) self.doStep() def checkCharCollisions(self, args): self.doStep() def doStep(self): # do the step height check tmpNP = self.mainNode.attachNewNode("temporary") tmpNP.setPos(self.mainNode, 0, 0, -self.stepheight) pointA = self.mainNode.getPos(render) pointA.setZ(pointA.getZ() + self.player_height / 1.8) pointB = tmpNP.getPos(render) if pointA == pointB: return char_step_collision = self.getFirstCollisionInLine(pointA, pointB) tmpNP.removeNode() if char_step_collision is not None: self.mainNode.setFluidZ(char_step_collision.getZ()) return True return False def getFirstCollisionInLine(self, pointA, pointB): """A simple raycast check which will return the first collision point as seen from point A towards pointB""" self.raytest_segment.setPointA(pointA) self.raytest_segment.setPointB(pointB) self.rayCTrav.traverse(render) self.raytest_queue.sortEntries() pos = None if self.raytest_queue.getNumEntries() > 0: pos = self.raytest_queue.getEntry(0).getSurfacePoint(render) return pos
class MetalSlender(ShowBase): VERSION=0.1 GRAVITY = 9.81 def __init__(self): ShowBase.__init__(self) self.initVideo() self.initGame() def initVideo(self): self.render.setShaderAuto() #TODO: Not working self.render.setAntialias(AntialiasAttrib.MMultisample) self.props = WindowProperties() # self.props.setFullscreen(True) # self.props.setSize(1920, 1080) self.props.setSize(1280, 720) self.props.setCursorHidden(False) self.props.setMouseMode(self.props.M_absolute) self.win.requestProperties(self.props) self.win.movePointer(0, 100, 100) def initGame(self): self.paused = False self.initTimer = True self.time = 0 self.gameOver = True # self.setFrameRateMeter(True) self.taskMgr.add(self.menuDisplay, "menuDisplay") self.mainMenu = MainMenu(self) self.introSound = self.loader.loadSfx('assets/sounds/intro.mp3') self.introSound.setLoop(True) self.introSound.play() #TODO: Refactor environment into a class that inherits from nodepath def setupEnvironment(self): self.setBackgroundColor(0,0,0) self.setupLighting() self.setupFog() self.setupSkydome() self.setupPhysics() def setupFog(self): self.fog = Fog("fog") self.fog.setColor(FOG_COLOR) self.fog.setExpDensity(FOG_EXP_DENSITY) self.render.setFog(self.fog) def setupSkydome(self): self.skydome = self.loader.loadModel(EGG_SKYDOME) self.skydome.setBin('background', 0) self.skydome.setDepthWrite(False) self.skydome.reparentTo(self.cam) self.skydome.setCompass() self.skydome.setLight(self.shadeless) self.skydome.setScale(20) def setupLighting(self): alight = AmbientLight("AmbientLight") alight.setColor(AMBIENT_LIGHT) self.amblight = self.render.attachNewNode(alight) self.render.setLight(self.amblight) alight = AmbientLight("ShadelessLight") alight.setColor((1.0, 1.0, 1.0, 1.0)) self.shadeless = self.render.attachNewNode(alight) def setupPhysics(self): self.cTrav = CollisionTraverser() plane = self.render.attachNewNode(CollisionNode('WorldBottom')) plane.node().addSolid(CollisionPlane(Plane(0, 0, 1, 30))) plane.node().setIntoCollideMask(CollisionMask.SCENE) #TODO: Set the scenario's into collide mask to a special value def loadScenario(self): self.rooms = [] self.rooms.append(Room(self, self.render, "LCG" , "assets/chicken/lcg" )) self.rooms.append(Room(self, self.render, "Bloco H" , "assets/chicken/blocoh" )) self.rooms.append(Room(self, self.render, "Bloco H2" , "assets/chicken/blocoh2")) self.rooms.append(Room(self, self.render, "Collision", "assets/chicken/collision" )) self.rooms[-1].root.setCollideMask(CollisionMask.SCENE) def addCommands(self): self.accept('escape', self.userExit) self.accept('g', self.endGame) self.accept('i', self.actionKeys, ['i']) self.accept('p', self.pauseGame) self.accept('z', self.restartGame) self.cTrav.setRespectPrevTransform(True) def addTasks(self): self.taskMgr.add(self.camctrl.update, "camera/control") self.taskMgr.add(self.player.updateAll, "player/update") self.taskMgr.add(self.hud.update, 'hud') self.taskMgr.add(self.player.flashlight.updatePower, 'player/flashlight/update') self.taskMgr.add(self.AIUpdate,"AIUpdate") self.taskMgr.add(self.camctrl.update, "camera/control") self.taskMgr.add(self.checkGoal, 'CheckGoal') def actionKeys(self, key): if key == 'i': self.player.fear = min(self.player.fear + 0.1, 1.0) def AIUpdate(self,task): pass hasAttacked = [] for enemy in self.enemies: attack = enemy.update() hasAttacked.append(attack) for i in hasAttacked: if (i == True): self.player.hurt()#TODO:The enemy itself should hurt the player #attack self.AIworld.update() if (self.player.isDead()): for enemy in self.enemies: enemy.stop() self.endGame() return task.done return task.cont def newGame(self): self.setupEnvironment() self.AIworld = AIWorld(self.render) self.introSound.stop() #TODO: Play creepy sound initialSound = loader.loadSfx('assets/sounds/enemies/nazgul_scream.mp3') initialSound.play() self.enemies = [] self.items = [] self.keys = [] #TODO: Many things are only done once the game is started # Load the scene. self.loadScenario() self.player = Player(self, self.render, 'Player', pos=Vec3(6, 1.44, -1.5)) self.actions = ActionManager(self, self.player, self.rooms) self.em = EventManager(self, self.player, self.actions, self.rooms) self.em.start() for enemy in self.enemies: enemy.getHooded().addIntruder(self.player) enemy.start() self.hud = HUD(self, self.player) self.controls = PlayerControls(self.player, self.actions) self.camctrl = CameraControls(self, self.player) self.props.setCursorHidden(True) self.win.requestProperties(self.props) self.mainMenu.hideNewGame() self.addTasks() self.addCommands() # self.cTrav = None def pauseGame(self): if (self.paused == True): self.props.setCursorHidden(True) self.win.requestProperties(self.props) self.mainMenu.hidePauseGame() self.paused = False self.events.start() self.taskMgr.add(self.player.updateAll, "player/update") self.taskMgr.add(self.hud.update, 'hud') self.taskMgr.add(self.player.flashlight.updatePower, 'player/flashlight/update') self.taskMgr.add(self.AIUpdate,"AIUpdate") self.taskMgr.add(self.camctrl.update, "camera/control") self.taskMgr.add(self.checkGoal, 'CheckGoal') self.accept('p', self.pauseGame) else: self.events.stop() self.ignore('p') self.player.pause() self.taskMgr.remove("camera/control") self.taskMgr.remove("player/update") self.taskMgr.remove('hud') self.player.resetLast() self.taskMgr.remove('player/flashlight/update') self.taskMgr.remove("AIUpdate") self.taskMgr.remove('CheckGoal') self.props.setCursorHidden(False) self.win.requestProperties(self.props) self.mainMenu.showPauseGame() self.paused = True def restartGame(self): self.events.stop() self.taskMgr.remove("camera/control") self.taskMgr.remove("player/update") self.taskMgr.remove('hud') self.taskMgr.remove('player/flashlight/update') self.taskMgr.remove("AIUpdate") self.taskMgr.remove('CheckGoal') self.cleanResources() self.props.setCursorHidden(False) self.win.requestProperties(self.props) self.initGame() def cleanResources(self): self.AIworld = None del self.enemies [:] del self.rooms [:] self.enemies = None self.rooms = None self.player = None self.actions = None self.events = None self.mainMenu = None self.fog = None self.skydome.removeNode() self.amblight.removeNode() self.shadeless.removeNode() self.target1.removeNode() self.target2.removeNode() self.banana.removeNode() self.skydome = None self.amblight = None self.shadeless = None self.target1 = None self.target2 = None self.banana = None self.hud = None self.camctrl = None self.controls = None self.cTrav.clearColliders() gc.collect() self.taskMgr.add(self.player.updateAll, "player/update") self.taskMgr.add(self.player.flashlight.updatePower, 'player/flashlight/update') self.taskMgr.add(self.AIUpdate,"AIUpdate") self.taskMgr.add(self.camctrl.update, "camera/control") self.taskMgr.add(self.playerUpdate, "playerUpdate") self.taskMgr.add(self.checkGoal, 'CheckGoal') def endGame(self): self.hud.hide() if (self.gameOver): self.image = OnscreenImage(image="assets/images/GameOver.png", pos = (0, 0, 0), parent=base.render2d, scale=(1,1,1)) else: self.image = OnscreenImage(image="assets/images/to-be-continued.jpg", pos = (0, 0, 0), parent=base.render2d, scale=(1,1,1)) self.startTimer(3) self.taskMgr.remove("camera/control") def menuDisplay(self, task): if (self.initTimer == False): hasFinished = self.timer() if (hasFinished): self.resetTimer() self.image.hide() self.props.setCursorHidden(False) self.props.setMouseMode(self.props.M_absolute) self.win.requestProperties(self.props) self.mainMenu.showNewGame() return task.cont def timer(self): currentTime = time.time() diff = currentTime - self.time if (diff > self.interval): self.resetTimer() return True else: return False def resetTimer(self): self.initTimer = True def startTimer(self, interval): if (self.initTimer == True): self.interval = interval self.initTimer = False self.time = time.time() def playerUpdate(self, task): reached = self.checkGoal() if (reached): # self.player.die() self.endGame() return task.done someKey = False for key in self.actions.keys: if (key.wasPicked()): someKey = True self.hud.setKey(someKey) return task.cont def checkGoal(self, task): close = not self.goal.isEmpty() and self.player.getNodePath().getDistance(self.goal) < 2 hasKey = 'goal' in [key.lock for key in self.player.inventory] if (close and hasKey): self.gameOver = False self.endGame() return task.cont