def makePerspective(parent): v = Viewport('persp', parent) v.camPos = Point3(-19, -19, 19) v.camLookAt = Point3(0, 0, 0) v.grid = DirectGrid(parent=render) collPlane = CollisionNode('PerspGridCol') collPlane.addSolid(CollisionPlane(Plane(0, 0, 1, 0))) #oldBitmask = collPlane.getIntoCollideMask() #collPlane.setIntoCollideMask(BitMask32.bit(21)|oldBitmask) collPlane.setIntoCollideMask(BitMask32.bit(21)) v.collPlane = NodePath(collPlane) v.collPlane.reparentTo(v.grid) collPlane2 = CollisionNode('PerspGridCol2') collPlane2.addSolid(CollisionPlane(Plane(0, 0, -1, 0))) #oldBitmask = collPlane2.getIntoCollideMask() #collPlane2.setIntoCollideMask(BitMask32.bit(21)|oldBitmask) collPlane2.setIntoCollideMask(BitMask32.bit(21)) v.collPlane2 = NodePath(collPlane2) v.collPlane2.reparentTo(v.grid) #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_perspViewGridBack") LE_showInOneCam(v.grid, 'persp') return v
def __init__(self, nick): self.player = player.Player(nick=nick) self.controller = controller.ClientController(self.player) self.handgui = hand.HandGUI(self.player.hand) camera.setPos(0, -20, 0) self.accept("turn_time_changed", self.update_turn_time) self.turn_timer = TurnTimer() # Mouse detection: base.cTrav = CollisionTraverser() self.mouse_ray_handler = CollisionHandlerQueue() mouse_ray_node = CollisionNode('mouse_ray') mouse_ray_np = camera.attachNewNode(mouse_ray_node) mouse_ray_node.setFromCollideMask(GeomNode.getDefaultCollideMask()) mouse_ray_node.setIntoCollideMask(0) self.mouse_ray = CollisionRay() mouse_ray_node.addSolid(self.mouse_ray) base.cTrav.addCollider(mouse_ray_np, self.mouse_ray_handler) self.mouse_overed_entry = None self.accept("mouse_enter", self.enlarge_entry) self.accept("mouse_leave", self.shrink_entry) self.accept("p-up", self.change_card_picture) taskMgr.doMethodLater(0.1, self.check_mouse_over, "check_mouse_over")
def loadVirtualSuit(self): dna = SuitDNA.SuitDNA() dna.newSuit(self.getSuitName()) self.virtualSuit = Suit.Suit() self.virtualSuit.reparentTo(self) self.virtualSuit.setDNA(dna) self.virtualSuit.setPos(self, 0.0, 2.5, 0.0) self.virtualSuit.makeSkeleton(wantNameInfo=False) self.virtualSuit.makeVirtual() self.virtualSuit.hideName() anims = self.generateSuitAnimDict() self.virtualSuit.loadAnims(anims) self.virtualSuit.loop('walk', 0) synergyBox = CollisionBox(0, 3.5, 10, 1) synergyBox.setTangible(0) synergyNode = CollisionNode(self.uniqueName('SynergyAttack')) synergyNode.setTag('damage', '10') synergyNode.addSolid(synergyBox) synergyNode.setIntoCollideMask(WallBitmask) self.synergyColl = self.virtualSuit.attachNewNode(synergyNode) self.synergyColl.setPos(0.0, 9.0, 0.0) self.synergyColl.stash() self.synergySfx = loader.loadSfx('phase_5/audio/sfx/SA_synergy.ogg') self.teeOffSfx = loader.loadSfx('phase_5/audio/sfx/SA_tee_off.ogg') self.writeOffSfx = loader.loadSfx('phase_5/audio/sfx/SA_writeoff_pen_only.ogg') self.dingSfx = loader.loadSfx('phase_5/audio/sfx/SA_writeoff_ding_only.ogg')
def placeCollectibles(self): self.placeCol = render.attachNewNode("Collectible-Placeholder") self.placeCol.setPos(0,0,0) # Add the health items to the placeCol node for i in range(self.numObjects): # Load in the health item model self.collect = loader.loadModel("models/trex") self.collect.setPos(0,0,0) self.collect.reparentTo(self.placeCol) self.collect.setScale(0.1) self.tex3= loader.loadTexture("models/Face.jpg") self.collect.setTexture(self.tex3,1) self.placeItem(self.collect) # Add spherical collision detection colSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('colSphere') sphereNode.addSolid(colSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.collect.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue()
def __init__(self, cr): DistributedObject.__init__(self, cr) #self.model = loader.loadModel('environment') #self.model.setZ(0) #self.builder = Builder(self, "map.txt", "development") plane = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0))) cnode = CollisionNode('cnode') cnode.setIntoCollideMask(BitMask32.bit(1)) cnode.setFromCollideMask(BitMask32.bit(1)) cnode.addSolid(plane) self.planeNP = self.model.attachNewNode(cnode) self.planeNP.show() # Setup a traverser for the picking collisions self.picker = CollisionTraverser() # Setup mouse ray self.pq = CollisionHandlerQueue() # Create a collision Node pickerNode = CollisionNode('MouseRay') # set the nodes collision bitmask pickerNode.setFromCollideMask(BitMask32.bit(1)) # create a collision ray self.pickerRay = CollisionRay() # add the ray as a solid to the picker node pickerNode.addSolid(self.pickerRay) # create a nodepath with the camera to the picker node self.pickerNP = base.camera.attachNewNode(pickerNode) # add the nodepath to the base traverser self.picker.addCollider(self.pickerNP, self.pq) print "model loaded" #TODO: check how to load multiple levels and set players in specific levels! self.accept("mouse1", self.mouseClick)
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
def placeHealthItems(self): self.placeholder = render.attachNewNode("HealthItem-Placeholder") self.placeholder.setPos(0,0,0) # Add the health items to the placeholder node for i in range(5): # Load in the health item model self.foodchick = loader.loadModel("models/chicken2") self.foodchick.setPos(0,0,0) self.foodchick.reparentTo(self.placeholder) #self.tex2=self.setTexture("models/orange.jpg") #self.foodchick.setTexture(self.tex2,1) #self.tex2= loader.loadTexture("models/orange.jpg") #self.foodchick.setTexture(self.tex1,1) self.placeItem(self.foodchick) # Add spherical collision detection healthSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('healthSphere') sphereNode.addSolid(healthSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(0)) sphereNp = self.foodchick.attachNewNode(sphereNode) sphereColHandler = CollisionHandlerQueue()
def initCollisionRay(self, originZ, dirZ): ray = CollisionRay(0,0,originZ,0,0,dirZ) collNode = CollisionNode('playerRay') collNode.addSolid(ray) collNode.setFromCollideMask(BitMask32.bit(1)) collNode.setIntoCollideMask(BitMask32.allOff()) collRayNP = self.playerNode.attachNewNode(collNode) collRayNP.show() return collRayNP
def attachCollisionSphere(self, name, cx, cy, cz, r, fromCollide, intoCollide): from panda3d.core import CollisionSphere from panda3d.core import CollisionNode coll = CollisionSphere(cx, cy, cz, r) collNode = CollisionNode(name) collNode.addSolid(coll) collNode.setFromCollideMask(fromCollide) collNode.setIntoCollideMask(intoCollide) collNodePath = self.attachNewNode(collNode) return collNodePath
def attachCollisionSegment(self, name, ax, ay, az, bx, by, bz, fromCollide, intoCollide): from panda3d.core import CollisionSegment from panda3d.core import CollisionNode coll = CollisionSegment(ax, ay, az, bx, by, bz) collNode = CollisionNode(name) collNode.addSolid(coll) collNode.setFromCollideMask(fromCollide) collNode.setIntoCollideMask(intoCollide) collNodePath = self.attachNewNode(collNode) return collNodePath
def attachCollisionRay(self, name, ox, oy, oz, dx, dy, dz, fromCollide, intoCollide): from panda3d.core import CollisionRay from panda3d.core import CollisionNode coll = CollisionRay(ox, oy, oz, dx, dy, dz) collNode = CollisionNode(name) collNode.addSolid(coll) collNode.setFromCollideMask(fromCollide) collNode.setIntoCollideMask(intoCollide) collNodePath = self.attachNewNode(collNode) return collNodePath
def create_sphere(self, model_name, bitmask): model = loader.loadModel("models/" + model_name) model.reparent_to(base.render) target = CollisionSphere(0, 0, 0, 1) target_node = CollisionNode('collision_target') target_node.setIntoCollideMask(bitmask) target_nodepath = model.attach_new_node(target_node) target_nodepath.node().addSolid(target) target_nodepath.show() return model
def getFlyBallBubble(self): if self.__flyBallBubble == None: bubble = CollisionSphere(0, 0, 0, GolfGlobals.GOLF_BALL_RADIUS) node = CollisionNode('flyBallBubble') node.addSolid(bubble) node.setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) node.setIntoCollideMask(BitMask32.allOff()) self.__flyBallBubble = NodePath(node) self.flyBallHandler = CollisionHandlerEvent() self.flyBallHandler.addInPattern('flyBallHit-%d' % self.index) return self.__flyBallBubble
def __init__(self, model = "cube_nocol", texture = "lava", pos = (0,0,0), scale = (1,1,1), cubetype = "A"): super(LavaCube, self).__init__(model, texture, pos, scale) cn = CollisionNode('lava') cn.setFromCollideMask(COLLISIONMASKS['lava']) cn.setIntoCollideMask(BitMask32.allOff()) np = self.node.attachNewNode(cn) cn.addSolid(CollisionSphere(0,0,0,1.1)) h = CollisionHandlerEvent() h.addInPattern('%fn-into-%in') h.addOutPattern('%fn-outof-%in') base.cTrav.addCollider(np, h)
def createMouseCollisions(self): # Fire the portals firingNode = CollisionNode('mouseRay') firingNP = self.base.camera.attachNewNode(firingNode) firingNode.setFromCollideMask(COLLISIONMASKS['geometry']) firingNode.setIntoCollideMask(BitMask32.allOff()) firingRay = CollisionRay() firingRay.setOrigin(0,0,0) firingRay.setDirection(0,1,0) firingNode.addSolid(firingRay) self.firingHandler = CollisionHandlerQueue() self.base.cTrav.addCollider(firingNP, self.firingHandler)
def setupEventSphere(self, bitmask, avatarRadius): self.avatarRadius = avatarRadius cSphere = CollisionSphere(0.0, 0.0, self.avatarRadius + 0.75, self.avatarRadius * 1.04) cSphere.setTangible(0) cSphereNode = CollisionNode('Flyer.cEventSphereNode') cSphereNode.addSolid(cSphere) cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode) cSphereNode.setFromCollideMask(bitmask) cSphereNode.setIntoCollideMask(BitMask32.allOff()) self.event = CollisionHandlerEvent() self.event.addInPattern('enter%in') self.event.addOutPattern('exit%in') self.cEventSphereNodePath = cSphereNodePath
def setupHeadSphere(self, avatarNodePath): collSphere = CollisionSphere(0, 0, 0, 1) collSphere.setTangible(1) collNode = CollisionNode('Flyer.cHeadCollSphere') collNode.setFromCollideMask(ToontownGlobals.CeilingBitmask) collNode.setIntoCollideMask(BitMask32.allOff()) collNode.addSolid(collSphere) self.cHeadSphereNodePath = avatarNodePath.attachNewNode(collNode) self.cHeadSphereNodePath.setZ(base.localAvatar.getHeight() + 1.0) self.headCollisionEvent = CollisionHandlerEvent() self.headCollisionEvent.addInPattern('%fn-enter-%in') self.headCollisionEvent.addOutPattern('%fn-exit-%in') base.cTrav.addCollider(self.cHeadSphereNodePath, self.headCollisionEvent)
def setupFloorEventSphere(self, avatarNodePath, bitmask, avatarRadius): cSphere = CollisionSphere(0.0, 0.0, 0.0, 0.75) cSphereNode = CollisionNode('Flyer.cFloorEventSphere') cSphereNode.addSolid(cSphere) cSphereNodePath = avatarNodePath.attachNewNode(cSphereNode) cSphereNode.setFromCollideMask(bitmask) cSphereNode.setIntoCollideMask(BitMask32.allOff()) self.floorCollisionEvent = CollisionHandlerEvent() self.floorCollisionEvent.addInPattern('%fn-enter-%in') self.floorCollisionEvent.addAgainPattern('%fn-again-%in') self.floorCollisionEvent.addOutPattern('%fn-exit-%in') base.cTrav.addCollider(cSphereNodePath, self.floorCollisionEvent) self.cFloorEventSphereNodePath = cSphereNodePath
def __init__(self, _main): self.main = _main self.name = "" self.points = 0 self.health = 100.0 self.runSpeed = 1.8 self.keyMap = { "left":False, "right":False, "up":False, "down":False } base.camera.setPos(0,0,0) self.model = loader.loadModel("Player") self.model.find('**/+SequenceNode').node().stop() self.model.find('**/+SequenceNode').node().pose(0) base.camera.setP(-90) self.playerHud = Hud() self.playerHud.hide() self.model.hide() # Weapons: size=2, 0=main, 1=offhand self.mountSlot = [] self.activeWeapon = None self.isAutoActive = False self.trigger = False self.lastShot = 0.0 self.fireRate = 0.0 self.playerTraverser = CollisionTraverser() self.playerEH = CollisionHandlerEvent() ## INTO PATTERNS self.playerEH.addInPattern('intoPlayer-%in') #self.playerEH.addInPattern('colIn-%fn') self.playerEH.addInPattern('intoHeal-%in') self.playerEH.addInPattern('intoWeapon-%in') ## OUT PATTERNS self.playerEH.addOutPattern('outOfPlayer-%in') playerCNode = CollisionNode('playerSphere') playerCNode.setFromCollideMask(BitMask32.bit(1)) playerCNode.setIntoCollideMask(BitMask32.bit(1)) self.playerSphere = CollisionSphere(0, 0, 0, 0.6) playerCNode.addSolid(self.playerSphere) self.playerNP = self.model.attachNewNode(playerCNode) self.playerTraverser.addCollider(self.playerNP, self.playerEH) #self.playerNP.show() self.playerPusher = CollisionHandlerPusher() self.playerPusher.addCollider(self.playerNP, self.model) self.playerPushTraverser = CollisionTraverser() self.playerPushTraverser.addCollider(self.playerNP, self.playerPusher)
def __init__(self, model = "models/sphere", texture = "exit", pos = (0,0,0), scale = (1,1,1), cubetype = "A"): super(LevelExit, self).__init__(model, texture, pos, scale) #self.node.setTransparency(TransparencyAttrib.MAlpha) self.node.setTag('noportals', '1') self.node.setTag('isexit', '1') cn = CollisionNode('levelExit') cn.setFromCollideMask(COLLISIONMASKS['exit']) cn.setIntoCollideMask(BitMask32.allOff()) np = self.node.attachNewNode(cn) cn.addSolid(CollisionSphere(0,0,0,1.1)) h = CollisionHandlerEvent() h.addInPattern('%fn-into-%in') h.addOutPattern('%fn-outof-%in') base.cTrav.addCollider(np, h)
def setupWallSphere(self, bitmask, avatarRadius): self.avatarRadius = avatarRadius cSphere = CollisionSphere(0.0, 0.0, self.avatarRadius + 0.75, self.avatarRadius) cSphereNode = CollisionNode('Flyer.cWallSphereNode') cSphereNode.addSolid(cSphere) cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode) cSphereNode.setFromCollideMask(bitmask) cSphereNode.setIntoCollideMask(BitMask32.allOff()) if config.GetBool('want-fluid-pusher', 0): self.pusher = CollisionHandlerFluidPusher() else: self.pusher = CollisionHandlerPusher() self.pusher.addCollider(cSphereNodePath, self.avatarNodePath) self.cWallSphereNodePath = cSphereNodePath
class PlayerObject(): def __init__(self, render, player): self.username = player.getUsername() self.isMoving = False self.render = render self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0} self.actor = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.actor.reparentTo(render) self.actor.setScale(0.2) self.actor.setPos(player.getX(), player.getY(), player.getZ()) self.actor.setH(player.getH()) self.cTrav = CollisionTraverser() self.GroundRay = CollisionRay() self.GroundRay.setOrigin(0,0,1000) self.GroundRay.setDirection(0,0,-1) self.GroundCol = CollisionNode('actorRay') self.GroundCol.addSolid(self.GroundRay) self.GroundCol.setFromCollideMask(BitMask32.bit(0)) self.GroundCol.setIntoCollideMask(BitMask32.allOff()) self.GroundColNp = self.actor.attachNewNode(self.GroundCol) self.GroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.GroundColNp, self.GroundHandler) # def getUsername(self): # return self.username def getActor(self): return self.actor def setPos(self, x, y, z): self.actor.setPos(x, y, z) def setH(self, h): self.actor.setH(h) def move(self, isActorMove): if isActorMove == "True": if self.isMoving is False: self.actor.loop("run") self.isMoving = True else: if self.isMoving: self.actor.stop() self.actor.pose("walk",5) self.isMoving = False
def loadLever(self): self.lever = self.root.attachNewNode('%sLever' % self.activityName) self.leverModel = self.party.defaultLeverModel.copyTo(self.lever) self.controlColumn = NodePath('cc') column = self.leverModel.find('**/column') column.getChildren().reparentTo(self.controlColumn) self.controlColumn.reparentTo(column) self.stickHinge = self.controlColumn.attachNewNode('stickHinge') self.stick = self.party.defaultStickModel.copyTo(self.stickHinge) self.stickHinge.setHpr(0.0, 90.0, 0.0) self.stick.setHpr(0, -90.0, 0) self.stick.flattenLight() self.bottom = self.leverModel.find('**/bottom') self.bottom.wrtReparentTo(self.controlColumn) self.bottomPos = self.bottom.getPos() cs = CollisionSphere(0.0, 1.35, 2.0, 1.0) cs.setTangible(False) cn = CollisionNode(self.leverTriggerEvent) cn.addSolid(cs) cn.setIntoCollideMask(OTPGlobals.WallBitmask) self.leverTrigger = self.root.attachNewNode(cn) self.leverTrigger.reparentTo(self.lever) self.leverTrigger.stash() cs = CollisionTube(0.0, 2.7, 0.0, 0.0, 2.7, 3.0, 1.2) cn = CollisionNode('levertube') cn.addSolid(cs) cn.setIntoCollideMask(OTPGlobals.WallBitmask) self.leverTube = self.leverModel.attachNewNode(cn) host = base.cr.doId2do.get(self.party.partyInfo.hostId) if host is None: self.notify.debug('%s loadLever : Host has left the game before lever could be created.' % self.activityName) return scale = host.getGeomNode().getChild(0).getSz(render) self.leverModel.setScale(scale) self.controlColumn.setPos(0, 0, 0) host.setPosHpr(self.lever, 0, 0, 0, 0, 0, 0) host.pose('leverNeutral', 0) host.update() pos = host.rightHand.getPos(self.controlColumn) self.controlColumn.setPos(pos[0], pos[1], pos[2] - 1) self.bottom.setZ(host, 0.0) self.bottom.setPos(self.bottomPos[0], self.bottomPos[1], self.bottom.getZ()) lookAtPoint = Point3(0.3, 0, 0.1) lookAtUp = Vec3(0, -1, 0) self.stickHinge.lookAt(host.rightHand, lookAtPoint, lookAtUp) host.play('walk') host.update() return
def setupRay(self, bitmask, floorOffset, reach): cRay = CollisionRay(0.0, 0.0, 3.0, 0.0, 0.0, -1.0) cRayNode = CollisionNode('Flyer.cRayNode') cRayNode.addSolid(cRay) self.cRayNodePath = self.avatarNodePath.attachNewNode(cRayNode) cRayNode.setFromCollideMask(bitmask) cRayNode.setIntoCollideMask(BitMask32.allOff()) self.lifter = CollisionHandlerGravity() self.lifter.setLegacyMode(self._legacyLifter) self.lifter.setGravity(self.getGravity(0)) self.lifter.addInPattern('%fn-enter-%in') self.lifter.addAgainPattern('%fn-again-%in') self.lifter.addOutPattern('%fn-exit-%in') self.lifter.setOffset(floorOffset) self.lifter.setReach(reach) self.lifter.addCollider(self.cRayNodePath, self.avatarNodePath)
def _initCollisions(self): self._camCollRay = CollisionRay() camCollNode = CollisionNode('CameraToonRay') camCollNode.addSolid(self._camCollRay) camCollNode.setFromCollideMask(OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask) camCollNode.setIntoCollideMask(0) self._camCollNP = self._camera.attachNewNode(camCollNode) self._camCollNP.show() self._collOffset = Vec3(0, 0, 0.5) self._collHandler = CollisionHandlerQueue() self._collTrav = CollisionTraverser() self._collTrav.addCollider(self._camCollNP, self._collHandler) self._betweenCamAndToon = {} self._transNP = NodePath('trans') self._transNP.reparentTo(render) self._transNP.setTransparency(True) self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon) self._transNP.setBin('fixed', 10000)
class Collectible: def __init__(self, base, model, pickSound): self.model = model #TODO: Refactor constants and collision solid self.collisionNd = CollisionNode(model.getName()) self.collisionNP = self.model.attachNewNode(self.collisionNd) self.collisionNd.addSolid(CollisionSphere(0, 0, 0, 0.3)) self.collisionNd.setIntoCollideMask(CollisionMask.HAND) self.pickedSound = base.loader.loadSfx(pickSound) self.picked = False def __del__(self): self.model.removeNode() self.pickedSound = None def reset(self): self.picked = False self.model.show() #TODO: Make Collectible a subclass of NodePath? def getName(self): return self.model.getName() def act(self, player): if (not self.picked): self.pickedSound.play() self.model.hide() self.picked = True player.inventory.append(self) def wasPicked(self): return self.picked def used(self): self.picked = False def clean(self): #self.audio3d.unloadSfx(self.pickedSound) #self.audio3d.disable() pass
class MouseCollision: def __init__(self, game): self.game = game self.c_trav = CollisionTraverser() self.mouse_groundHandler = CollisionHandlerQueue() self.mouse_ground_ray = CollisionRay() self.mouse_ground_col = CollisionNode('mouseRay') self.mouse_ground_ray.setOrigin(0, 0, 0) self.mouse_ground_ray.setDirection(0, -1, 0) self.mouse_ground_col.addSolid(self.mouse_ground_ray) self.mouse_ground_col.setFromCollideMask(CollideMask.bit(0)) self.mouse_ground_col.setIntoCollideMask(CollideMask.allOff()) self.mouse_ground_col_np = self.game.camera.attachNewNode(self.mouse_ground_col) self.c_trav.addCollider(self.mouse_ground_col_np, self.mouse_groundHandler) self.game.taskMgr.add(self.update, 'updateMouse') def update(self, task): if self.game.mouseWatcherNode.hasMouse(): if self.game.ship.model: mouse_pos = self.game.mouseWatcherNode.getMouse() self.mouse_ground_ray.setFromLens(self.game.camNode, mouse_pos.getX(), mouse_pos.getY()) near_point = render.getRelativePoint(self.game.camera, self.mouse_ground_ray.getOrigin()) near_vec = render.getRelativeVector(self.game.camera, self.mouse_ground_ray.getDirection()) self.game.ship.shipPoint.setPos(self.PointAtY(self.game.ship.model.getY(), near_point, near_vec)) return task.cont def PointAtY(self, y, point, vec): return point + vec * ((y - point.getY()) / vec.getY())
def loadAssets(self): self.root = render.attachNewNode('golfSpot-%d' % self.index) self.root.setPos(*self.positions[self.index]) self.ballModel = loader.loadModel('phase_6/models/golf/golf_ball') self.ballColor = VBase4(1, 1, 1, 1) if self.index < len(GolfGlobals.PlayerColors): self.ballColor = VBase4(*GolfGlobals.PlayerColors[self.index]) self.ballModel.setColorScale(self.ballColor) self.ballModel.reparentTo(self.root) self.club = loader.loadModel('phase_6/models/golf/putter') self.clubLookatSpot = self.root.attachNewNode('clubLookat') self.clubLookatSpot.setY(-(GolfGlobals.GOLF_BALL_RADIUS + 0.1)) cs = CollisionSphere(0, 0, 0, 1) cs.setTangible(0) cn = CollisionNode(self.triggerName) cn.addSolid(cs) cn.setIntoCollideMask(ToontownGlobals.WallBitmask) self.trigger = self.root.attachNewNode(cn) self.trigger.stash() self.hitBallSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Ball.ogg')
def createPortalCollisions(self): # Enter the portals cn = CollisionNode('bluePortal') cn.setFromCollideMask(COLLISIONMASKS['portals']) cn.setIntoCollideMask(BitMask32.allOff()) np = self.bluePortal.attachNewNode(cn) cn.addSolid(CollisionSphere(0,0,0,2)) h = CollisionHandlerEvent() h.addInPattern('%fn-into-%in') h.addOutPattern('%fn-outof-%in') self.base.cTrav.addCollider(np, h) cn = CollisionNode('orangePortal') cn.setFromCollideMask(COLLISIONMASKS['portals']) cn.setIntoCollideMask(BitMask32.allOff()) np = self.orangePortal.attachNewNode(cn) cn.addSolid(CollisionSphere(0,0,0,2)) h = CollisionHandlerEvent() h.addInPattern('%fn-into-%in') h.addOutPattern('%fn-outof-%in') self.base.cTrav.addCollider(np, h)
class IceTreasure(DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory('IceTreasure') RADIUS = 1.0 def __init__(self, model, pos, serialNum, gameId, penalty=False): self.serialNum = serialNum self.penalty = penalty center = model.getBounds().getCenter() center = Point3(0, 0, 0) self.nodePath = model.copyTo(render) self.nodePath.setPos(pos[0] - center[0], pos[1] - center[1], pos[2] - center[2]) self.nodePath.setZ(0) self.notify.debug('newPos = %s' % self.nodePath.getPos()) if self.penalty: self.sphereName = 'penaltySphere-%s-%s' % (gameId, self.serialNum) else: self.sphereName = 'treasureSphere-%s-%s' % (gameId, self.serialNum) self.collSphere = CollisionSphere(center[0], center[1], center[2], self.RADIUS) self.collSphere.setTangible(0) self.collNode = CollisionNode(self.sphereName) self.collNode.setIntoCollideMask(ToontownGlobals.PieBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = render.attachNewNode(self.collNode) self.collNodePath.setPos(pos[0] - center[0], pos[1] - center[1], pos[2] - center[2]) self.collNodePath.hide() self.track = None if self.penalty: self.tip = self.nodePath.find('**/fusetip') sparks = BattleParticles.createParticleEffect(file='icetnt') self.sparksEffect = sparks sparks.start(self.tip) self.penaltyGrabSound = loader.loadSfx( 'phase_4/audio/sfx/MG_cannon_fire_alt.mp3') self.penaltyGrabSound.setVolume(0.75) kaboomAttachPoint = self.nodePath.attachNewNode('kaboomAttach') kaboomAttachPoint.setZ(3) self.kaboom = loader.loadModel( 'phase_4/models/minigames/ice_game_kaboom') self.kaboom.reparentTo(kaboomAttachPoint) self.kaboom.setScale(2.0) self.kaboom.setBillboardPointEye() return def destroy(self): self.ignoreAll() if self.penalty: self.sparksEffect.cleanup() if self.track: self.track.finish() self.nodePath.removeNode() del self.nodePath del self.collSphere self.collNodePath.removeNode() del self.collNodePath del self.collNode def showGrab(self): self.nodePath.hide() self.collNodePath.hide() self.collNode.setIntoCollideMask(BitMask32(0)) if self.penalty: self.track = Parallel( SoundInterval(self.penaltyGrabSound), Sequence( Func(self.kaboom.showThrough), LerpScaleInterval(self.kaboom, duration=0.5, scale=Point3(10, 10, 10), blendType='easeOut'), Func(self.kaboom.hide))) self.track.start()
class MazeSuit(DirectObject): COLL_SPHERE_NAME = 'MazeSuitSphere' COLLISION_EVENT_NAME = 'MazeSuitCollision' MOVE_IVAL_NAME = 'moveMazeSuit' DIR_UP = 0 DIR_DOWN = 1 DIR_LEFT = 2 DIR_RIGHT = 3 oppositeDirections = [DIR_DOWN, DIR_UP, DIR_RIGHT, DIR_LEFT] directionHs = [0, 180, 90, 270] DEFAULT_SPEED = 4.0 SUIT_Z = 0.1 def __init__(self, serialNum, maze, randomNumGen, cellWalkPeriod, difficulty, suitDnaName = 'f', startTile = None, ticFreq = MazeGameGlobals.SUIT_TIC_FREQ, walkSameDirectionProb = MazeGameGlobals.WALK_SAME_DIRECTION_PROB, walkTurnAroundProb = MazeGameGlobals.WALK_TURN_AROUND_PROB, uniqueRandomNumGen = True, walkAnimName = None): self.serialNum = serialNum self.maze = maze if uniqueRandomNumGen: self.rng = RandomNumGen(randomNumGen) else: self.rng = randomNumGen self.difficulty = difficulty self._walkSameDirectionProb = walkSameDirectionProb self._walkTurnAroundProb = walkTurnAroundProb self._walkAnimName = walkAnimName or 'walk' self.suit = Suit.Suit() d = SuitDNA.SuitDNA() d.newSuit(suitDnaName) self.suit.setDNA(d) if startTile is None: defaultStartPos = MazeGameGlobals.SUIT_START_POSITIONS[self.serialNum] self.startTile = (defaultStartPos[0] * self.maze.width, defaultStartPos[1] * self.maze.height) else: self.startTile = startTile self.ticFreq = ticFreq self.ticPeriod = int(cellWalkPeriod) self.cellWalkDuration = float(self.ticPeriod) / float(self.ticFreq) self.turnDuration = 0.6 * self.cellWalkDuration return def destroy(self): self.suit.delete() def uniqueName(self, str): return str + `(self.serialNum)` def gameStart(self, gameStartTime): self.gameStartTime = gameStartTime self.initCollisions() self.startWalkAnim() self.occupiedTiles = [(self.nextTX, self.nextTY)] n = 20 self.nextThinkTic = self.serialNum * self.ticFreq / n self.fromPos = Point3(0, 0, 0) self.toPos = Point3(0, 0, 0) self.fromHpr = Point3(0, 0, 0) self.toHpr = Point3(0, 0, 0) self.moveIval = WaitInterval(1.0) def gameEnd(self): self.moveIval.pause() del self.moveIval self.shutdownCollisions() self.suit.loop('neutral') def initCollisions(self): self.collSphere = CollisionSphere(0, 0, 0, 2.0) self.collSphere.setTangible(0) self.collNode = CollisionNode(self.uniqueName(self.COLL_SPHERE_NAME)) self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.suit.attachNewNode(self.collNode) self.collNodePath.hide() self.accept(self.uniqueName('enter' + self.COLL_SPHERE_NAME), self.handleEnterSphere) def shutdownCollisions(self): self.ignore(self.uniqueName('enter' + self.COLL_SPHERE_NAME)) del self.collSphere self.collNodePath.removeNode() del self.collNodePath del self.collNode def handleEnterSphere(self, collEntry): messenger.send(self.COLLISION_EVENT_NAME, [self.serialNum]) def __getWorldPos(self, sTX, sTY): wx, wy = self.maze.tile2world(sTX, sTY) return Point3(wx, wy, self.SUIT_Z) def onstage(self): sTX = int(self.startTile[0]) sTY = int(self.startTile[1]) c = 0 lim = 0 toggle = 0 direction = 0 while not self.maze.isWalkable(sTX, sTY): if 0 == direction: sTX -= 1 elif 1 == direction: sTY -= 1 elif 2 == direction: sTX += 1 elif 3 == direction: sTY += 1 c += 1 if c > lim: c = 0 direction = (direction + 1) % 4 toggle += 1 if not toggle & 1: lim += 1 self.TX = sTX self.TY = sTY self.direction = self.DIR_DOWN self.lastDirection = self.direction self.nextTX = self.TX self.nextTY = self.TY self.suit.setPos(self.__getWorldPos(self.TX, self.TY)) self.suit.setHpr(self.directionHs[self.direction], 0, 0) self.suit.reparentTo(render) self.suit.pose(self._walkAnimName, 0) self.suit.loop('neutral') def offstage(self): self.suit.reparentTo(hidden) def startWalkAnim(self): self.suit.loop(self._walkAnimName) speed = float(self.maze.cellWidth) / self.cellWalkDuration self.suit.setPlayRate(speed / self.DEFAULT_SPEED, self._walkAnimName) def __applyDirection(self, dir, TX, TY): if self.DIR_UP == dir: TY += 1 elif self.DIR_DOWN == dir: TY -= 1 elif self.DIR_LEFT == dir: TX -= 1 elif self.DIR_RIGHT == dir: TX += 1 return (TX, TY) def __chooseNewWalkDirection(self, unwalkables): if not self.rng.randrange(self._walkSameDirectionProb): newTX, newTY = self.__applyDirection(self.direction, self.TX, self.TY) if self.maze.isWalkable(newTX, newTY, unwalkables): return self.direction if self.difficulty >= 0.5: if not self.rng.randrange(self._walkTurnAroundProb): oppositeDir = self.oppositeDirections[self.direction] newTX, newTY = self.__applyDirection(oppositeDir, self.TX, self.TY) if self.maze.isWalkable(newTX, newTY, unwalkables): return oppositeDir candidateDirs = [self.DIR_UP, self.DIR_DOWN, self.DIR_LEFT, self.DIR_RIGHT] candidateDirs.remove(self.oppositeDirections[self.direction]) while len(candidateDirs): dir = self.rng.choice(candidateDirs) newTX, newTY = self.__applyDirection(dir, self.TX, self.TY) if self.maze.isWalkable(newTX, newTY, unwalkables): return dir candidateDirs.remove(dir) return self.oppositeDirections[self.direction] def getThinkTimestampTics(self, curTic): if curTic < self.nextThinkTic: return [] else: r = range(self.nextThinkTic, curTic + 1, self.ticPeriod) self.lastTicBeforeRender = r[-1] return r def prepareToThink(self): self.occupiedTiles = [(self.nextTX, self.nextTY)] def think(self, curTic, curT, unwalkables): self.TX = self.nextTX self.TY = self.nextTY self.lastDirection = self.direction self.direction = self.__chooseNewWalkDirection(unwalkables) self.nextTX, self.nextTY = self.__applyDirection(self.direction, self.TX, self.TY) self.occupiedTiles = [(self.TX, self.TY), (self.nextTX, self.nextTY)] if curTic == self.lastTicBeforeRender: fromCoords = self.maze.tile2world(self.TX, self.TY) toCoords = self.maze.tile2world(self.nextTX, self.nextTY) self.fromPos.set(fromCoords[0], fromCoords[1], self.SUIT_Z) self.toPos.set(toCoords[0], toCoords[1], self.SUIT_Z) self.moveIval = LerpPosInterval(self.suit, self.cellWalkDuration, self.toPos, startPos=self.fromPos, name=self.uniqueName(self.MOVE_IVAL_NAME)) if self.direction != self.lastDirection: self.fromH = self.directionHs[self.lastDirection] toH = self.directionHs[self.direction] if self.fromH == 270 and toH == 0: self.fromH = -90 elif self.fromH == 0 and toH == 270: self.fromH = 360 self.fromHpr.set(self.fromH, 0, 0) self.toHpr.set(toH, 0, 0) turnIval = LerpHprInterval(self.suit, self.turnDuration, self.toHpr, startHpr=self.fromHpr, name=self.uniqueName('turnMazeSuit')) self.moveIval = Parallel(self.moveIval, turnIval, name=self.uniqueName(self.MOVE_IVAL_NAME)) else: self.suit.setH(self.directionHs[self.direction]) moveStartT = float(self.nextThinkTic) / float(self.ticFreq) self.moveIval.start(curT - (moveStartT + self.gameStartTime)) self.nextThinkTic += self.ticPeriod @staticmethod def thinkSuits(suitList, startTime, ticFreq = MazeGameGlobals.SUIT_TIC_FREQ): curT = globalClock.getFrameTime() - startTime curTic = int(curT * float(ticFreq)) suitUpdates = [] for i in xrange(len(suitList)): updateTics = suitList[i].getThinkTimestampTics(curTic) suitUpdates.extend(zip(updateTics, [i] * len(updateTics))) suitUpdates.sort(lambda a, b: a[0] - b[0]) if len(suitUpdates) > 0: curTic = 0 for i in xrange(len(suitUpdates)): update = suitUpdates[i] tic = update[0] suitIndex = update[1] suit = suitList[suitIndex] if tic > curTic: curTic = tic j = i + 1 while j < len(suitUpdates): if suitUpdates[j][0] > tic: break suitList[suitUpdates[j][1]].prepareToThink() j += 1 unwalkables = [] for si in xrange(suitIndex): unwalkables.extend(suitList[si].occupiedTiles) for si in xrange(suitIndex + 1, len(suitList)): unwalkables.extend(suitList[si].occupiedTiles) suit.think(curTic, curT, unwalkables)
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/panda", { "run": "models/panda-walk", "walk": "models/panda-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 bullet(): #tuple pos, tuple target, float damage, float speed, float range, float accuracy -> bullet def __init__(self, sender, pos, dir, damage, speed, range, accuracy=1): #bullets have a speed, a model, and a damage. Both should be parameters #range as well self.start = pos self.sender = sender self.accuracy = accuracy self.direction = dir.normalized() self.damage = damage self.tasks = [] self.speed = speed self.range = range self.model = base.loader.loadModel('models/bullet') self.model.reparentTo(base.render) self.model.setPos(pos) #self.target=target #create collision sphere #TODO account for larger bullet sizes cs = CollisionSphere(0, 0, 0, 1) self.mainCol = CollisionNode('cNode') #set up circular reference so collision volume knows parent self.mainCol.setPythonTag('owner', self) self.mainCol.setIntoCollideMask( CollideMask.bit(1) ) # send objects with intoCollideMask bit 1. Relates to most entities self.cNode = self.model.attachNewNode(self.mainCol) self.cNode.node().addSolid(cs) #create collider handler, if one doesn't already exist try: # attempt to add to global collision traverser base.cTrav.addCollider(self.cNode, base.bulletCollider) except AttributeError: base.bulletCollider = CollisionHandlerEvent() # create event called 'bulletCollision' on hit base.bulletCollider.addInPattern('bulletCollision') finally: # retry base.cTrav.addCollider(self.cNode, base.bulletCollider) #rotate model such that it follows the passed direction argument vector self.model.setHpr(helper.vectorToHPR(dir)) #assign direction based on rotation #THIS TOOK WAY TOO MUCH EFFORT TO FIGURE OUT #normVec here is the model nodepath taking the passed argument vector (dir) #belonging to another node (base.render) #and adjusting it to its local coordinate space - what would this vector look like from #self.model's perspective. Then it is normalized and assigned. normVec = self.model.getRelativeVector(base.render, dir) normVec.normalize() self.direction = normVec #normVec=base.render.getRelativeVector(self.model,Vec3(0,1,0)) #print(self.model.getHpr()) #print(normVec) #start task to move forward at speed self.tasks.append(taskMgr.add(self.accelerate, "bulletAccelerateTask")) #task: accelerate def accelerate(self, task): """ Task moves bullet forward until it hits an object or range is met """ #range is decremented each tick #check to make sure not 0 if self.range <= 0: #if range has ran out kill task and this object self.delete() return task.done #otherwise proceed, move object and decrement range dt = globalClock.getDt() #distVec=min((self.start-self.target),(self.target-self.start)) #distVec=distVec.normalized() #print(distVec) #print(self.direction) #take normalized direction vector and apply to transform self.model.setFluidX(self.model, self.direction[0] * self.speed * dt) self.model.setFluidY(self.model, self.direction[1] * self.speed * dt) self.model.setFluidZ(self.model, self.direction[2] * self.speed * dt) self.range -= (self.speed * dt) return task.cont #class deconstructor def delete(self): self.model.hide() #clear tasks for task in self.tasks: taskMgr.remove(task) #clear collision self.mainCol.clearPythonTag("owner") #remove object self.model.removeNode()
class CogdoMazeDrop(NodePath, DirectObject): def __init__(self, game, id, x, y): NodePath.__init__(self, 'dropNode%s' % id) self.game = game self.id = id self.reparentTo(hidden) self.setPos(x, y, 0) shadow = loader.loadModel('phase_3/models/props/square_drop_shadow') shadow.setZ(0.2) shadow.setBin('ground', 10) shadow.setColor(1, 1, 1, 1) shadow.reparentTo(self) self.shadow = shadow drop = CogdoUtil.loadMazeModel('cabinetSmFalling') roll = random.randint(-15, 15) drop.setHpr(0, 0, roll) drop.setZ(Globals.DropHeight) self.collTube = CollisionTube(0, 0, 0, 0, 0, 4, Globals.DropCollisionRadius) self.collTube.setTangible(0) name = Globals.DropCollisionName self.collNode = CollisionNode(name) self.collNode.addSolid(self.collTube) self.collNodePath = drop.attachNewNode(self.collNode) self.collNodePath.hide() self.collNodePath.setTag('isFalling', str('True')) drop.reparentTo(self) self.drop = drop self._dropSfx = base.cogdoGameAudioMgr.createSfxIval('drop', volume=0.6) def disableCollisionDamage(self): self.collTube.setTangible(1) self.collTube.setRadius(Globals.DroppedCollisionRadius) self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask) self.collNodePath.setTag('isFalling', str('False')) def getDropIval(self): shadow = self.shadow drop = self.drop id = self.id hangTime = Globals.ShadowTime dropTime = Globals.DropTime dropHeight = Globals.DropHeight targetShadowScale = 0.5 targetShadowAlpha = 0.4 shadowScaleIval = LerpScaleInterval(shadow, dropTime, targetShadowScale, startScale=0) shadowAlphaIval = LerpColorScaleInterval( shadow, hangTime, Point4(1, 1, 1, targetShadowAlpha), startColorScale=Point4(1, 1, 1, 0)) shadowIval = Parallel(shadowScaleIval, shadowAlphaIval) startPos = Point3(0, 0, dropHeight) drop.setPos(startPos) dropIval = LerpPosInterval(drop, dropTime, Point3(0, 0, 0), startPos=startPos, blendType='easeIn') dropSoundIval = self._dropSfx dropSoundIval.node = self self.drop.setTransparency(1) def _setRandScale(t): self.drop.setScale(self, 1 - random.random() / 16, 1 - random.random() / 16, 1 - random.random() / 4) scaleChange = 0.4 + random.random() / 4 dropShakeSeq = Sequence( LerpScaleInterval(self.drop, 0.25, Vec3(1.0 + scaleChange, 1.0 + scaleChange / 2, 1.0 - scaleChange), blendType='easeInOut'), LerpScaleInterval(self.drop, 0.25, Vec3(1.0, 1.0, 1.0), blendType='easeInOut'), Func(self.disableCollisionDamage), LerpScaleInterval(self.drop, 0.2, Vec3(1.0 + scaleChange / 8, 1.0 + scaleChange / 8, 1.0 - scaleChange / 8), blendType='easeInOut'), LerpScaleInterval(self.drop, 0.2, Vec3(1.0, 1.0, 1.0), blendType='easeInOut'), LerpScaleInterval(self.drop, 0.15, Vec3(1.0 + scaleChange / 16, 1.0 + scaleChange / 16, 1.0 - scaleChange / 16), blendType='easeInOut'), LerpScaleInterval(self.drop, 0.15, Vec3(1.0, 1.0, 1.0), blendType='easeInOut'), LerpScaleInterval(self.drop, 0.1, Vec3(1.0 + scaleChange / 16, 1.0 + scaleChange / 8, 1.0 - scaleChange / 16), blendType='easeInOut'), LerpColorScaleInterval(self.drop, Globals.DropFadeTime, Vec4(1.0, 1.0, 1.0, 0.0))) ival = Sequence(Func(self.reparentTo, render), Parallel(Sequence(WaitInterval(hangTime), dropIval), shadowIval), Parallel(Func(self.game.dropHit, self, id), dropSoundIval, dropShakeSeq), Func(self.game.cleanupDrop, id), name='drop%s' % id) self.ival = ival return ival def destroy(self): self.ival.pause() self.ival = None self._dropSfx.pause() self._dropSfx = None self.collTube = None self.collNode = None self.collNodePath.removeNode() self.collNodePath = None self.removeNode() return
class RacingGame(ShowBase): # method completely taken from RoamingRalph demo: def addInstructions(self, pos, msg): return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=.05, shadow=(0, 0, 0, 1), parent=base.a2dTopLeft, pos=(0.08, -pos - 0.04), align=TextNode.ALeft) def addWin(self, time): msg = ( "You finished the course in: \n%d seconds \n press z to race again" % (time)) self.winText = OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=.2, shadow=(0, 0, 0, 1), parent=base.a2dTopLeft, pos=(0.10, -0.5), align=TextNode.ALeft) def destroyWin(self): if (self.winText != None): self.winText.destroy() def setUpFlyingInstructions(self): self.inst[0] = self.addInstructions(.06, "Arrow Keys to move around") self.inst[1] = self.addInstructions(.12, "w and s to control pitch") self.inst[2] = self.addInstructions(.18, "a and d to control yaw") self.inst[3] = self.addInstructions(.24, "h to switch to driving mode") self.inst[4] = self.addInstructions(.3, "mouse click to add object") self.inst[5] = self.addInstructions(.36, "m to go to main") def startMovement(self): taskMgr.add(self.move, "moveTask") def destroyInstructions(self): # got way to destroy text from: # https://www.panda3d.org/manual/index.php/OnscreenText for element in self.inst: element.destroy() def startCreating(self): self.switchToCreateMode() self.destroyStartScreenButtons() self.startMovement() def startDriving(self): self.switchToDrivingMode() self.destroyStartScreenButtons() self.startMovement() def startTutorial(self): self.mode = self.modeTutorial self.setUpTutorial() self.destroyStartScreenButtons() self.startMovement() def setUpStartScreenButtons(self): self.creatingButton = DirectButton(text="Start Creating", scale=.1, command=self.startCreating, pos=(0, 0, .2)) self.drivingButton = DirectButton(text="Start Driving", scale=.1, command=self.startDriving, pos=(0, 0, 0)) self.tutorialButton = DirectButton(text="Start Tutorial", scale=.1, command=self.startTutorial, pos=(0, 0, -.2)) def destroyStartScreenButtons(self): self.creatingButton.destroy() self.drivingButton.destroy() self.tutorialButton.destroy() def setAddObjectTree(self): self.createdObject = self.createTree def setAddObjectRock(self): self.createdObject = self.createRock def setAddObjectPole(self): self.createdObject = self.createPole def setUpCreateButtons(self): # todo: add toggle for instructions so that they do not always interfere with button self.treeButton = DirectButton(text="Add Block", scale=.1, command=self.setAddObjectTree, pos=(0, 0, .85)) #self.rockButton = DirectButton(text="Add Rock", scale=.1, command=self.setAddObjectRock, pos=(-.5,.9,.85)) self.poleButton = DirectButton(text="Add Pole", scale=.1, command=self.setAddObjectPole, pos=(.5, 0, .85)) def setUpCreateObjects(self): self.createdObject = 0 self.createTree = 0 self.createRock = 1 self.createPole = 2 def destroyCreateButtons(self): self.treeButton.destroy() #self.rockButton.destroy() self.poleButton.destroy() def setUpDrivingInstructions(self): self.inst[0] = self.addInstructions( .06, "Right arrow and left arrow to turn") self.inst[1] = self.addInstructions( .12, "Forward and Backward arrow to go forward and backward") self.inst[2] = self.addInstructions(.18, "h to switch to add object mode") self.inst[3] = self.addInstructions(.24, "z to switch to start the race") self.inst[4] = self.addInstructions(.30, "m to go to main") def setUpWindow(self): # set up the egg files needed # since this method is made for python 2.7 but these objects are made for python 3.5, seems to be incompatible #m = Mountain("TestMountain", 60) #m.editFile() #p = Pole("TestPole", 0, 0, 0) #p.editFile() #c = Car("TestCar", 0,0,0) #c.editFile() #b = BeaconLight("BeaconLight",0,0,0) #b.editFile() # Set up the window, camera, etc ShowBase.__init__(self) # Set the background color to black self.win.setClearColor((0, 1, 1, 1)) # this is the model I created using mountainMaker.py self.environ = loader.loadModel("TestMountain1") self.environ.reparentTo(render) self.car = loader.loadModel("TestCar") # found how to solve the problem of only being able to see objects from # certain angles with this: # http://www.panda3d.org/manual/index.php/Backface_Culling_and_Frontface_Culling self.car.setTwoSided(True) self.car.reparentTo(render) # Create some lighting # this is a part that is completely unchanged from demo 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)) # to get light from other direction to light up things on both sides directionalLight2 = DirectionalLight("directionalLight") directionalLight2.setDirection((5, 5, 5)) directionalLight2.setColor((1, 1, 1, 1)) directionalLight2.setSpecularColor((1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(directionalLight2)) def setUpCar(self): # for adjusting so that the position is the center of the car self.adjustedXForCenter = 10 / 2 self.adjustedYForCenter = 20 / 2 # for some reason can't change this or the collisions do not work self.carPositionX = 20 self.carPositionY = 20 self.carPositionZ = 100 # note for rotating camera: from this website: # https://www.panda3d.org/manual/index.php/Common_State_Changes # setHpr(Yaw, Pitch, Roll) # setting up initial conditions for which way camera is rotated self.carYaw = 0 self.carPitch = 0 (actualXPos, actualYPos) = RacingGame.findActualCenter( self, self.carPositionX, self.carPositionY, self.adjustedXForCenter, self.adjustedYForCenter, self.carYaw) self.car.setX(actualXPos) self.car.setY(actualYPos) self.car.setZ(self.carPositionZ) self.car.setHpr(self.carYaw, self.carPitch, 0) def setUpCamera(self): # for flying mode self.cameraPositionX = 500 self.cameraPositionY = 500 self.cameraPositionZ = 40 # note for rotating camera: from this website: # https://www.panda3d.org/manual/index.php/Common_State_Changes # setHpr(Yaw, Pitch, Roll) # setting up initial conditions for which way camera is rotated self.cameraYaw = 0 self.cameraPitch = 0 # Set up the camera self.disableMouse() # should probably clean up these magic numbers self.camera.setPos(self.cameraPositionX, self.cameraPositionY, self.cameraPositionZ) def setUpKeyMap(self): # This is used to store which keys are currently pressed. self.keyMap = { "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0, "backward": 0, "cam-up": 0, "cam-down": 0, "add-car": 0, "switch-mode": 0, "mouse-click": 0, "race-start": 0, "to-main": 0 } # Accept the control keys for movement and rotation #setting up keys for movement 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, ["backward", True]) self.accept("arrow_left-up", self.setKey, ["left", False]) self.accept("arrow_right-up", self.setKey, ["right", False]) self.accept("arrow_up-up", self.setKey, ["forward", False]) self.accept("arrow_down-up", self.setKey, ["backward", False]) self.accept("m", self.setKey, ["to-main", True]) self.accept("m-up", self.setKey, ["to-main", False]) # starting race self.accept("z", self.setKey, ["race-start", True]) self.accept("z-up", self.setKey, ["race-start", False]) # adding car self.accept("mouse1", self.setKey, ["mouse-click", True]) self.accept("mouse1-up", self.setKey, ["mouse-click", False]) # setting up orientation of the camera self.accept("a", self.setKey, ["cam-left", True]) self.accept("s", self.setKey, ["cam-down", True]) self.accept("a-up", self.setKey, ["cam-left", False]) self.accept("s-up", self.setKey, ["cam-down", False]) self.accept("d", self.setKey, ["cam-right", True]) self.accept("d-up", self.setKey, ["cam-right", False]) self.accept("w", self.setKey, ["cam-up", True]) self.accept("w-up", self.setKey, ["cam-up", False]) # to switch between tasks self.accept("h", self.setKey, ["switch-mode", True]) self.accept("h-up", self.setKey, ["switch-mode", False]) def __init__(self): self.setUpWindow() self.setUpKeyMap() #instructions self.inst = [""] * 6 self.setUpFlyingInstructions() self.mouseClicked = False self.winText = None # important for setting the size relative to everything else # found it here : https://www.panda3d.org/manual/index.php/Common_State_Changes # set the mode that the player is currently in self.mode = 0 self.modeFly = 2 self.modeRace = 1 self.modeStart = 0 self.modeTutorial = 3 # to ensure that when pressing h it only switches once each press self.hasSwitched = False self.raceBegan = False self.raceTime = 0 self.poleOn = 0 self.setUpCamera() self.setUpCar() self.setUpCarCollider() self.setUpMouseCollider() self.setUpStartScreenButtons() # make the rocks and other stuff that will show up self.setUpCreateObjects() self.objects = [] self.poles = [] self.beaconLight = None self.beaconLightZ = 50 self.target = None taskMgr.add(self.move, "moveTask") def findCollisionTube(self): # using bassically same formula as Y position # decided not to use this because possible problems with ground getting # hit instead of things in front degToRad = math.pi / 180 xAddition = ( self.adjustedXForCenter * math.cos(self.carYaw * degToRad) + self.adjustedYForCenter * math.sin(self.carYaw * degToRad)) / 2 yAddition = ( self.adjustedXForCenter * math.cos(self.carYaw * degToRad) + self.adjustedYForCenter * math.sin(self.carYaw * degToRad)) def findCarFrontDir(self): degToRad = math.pi / 180 xDir = -1 * math.sin(degToRad * self.carYaw) * math.cos( degToRad * self.carPitch) yDir = 1 * math.cos(degToRad * self.carYaw) * math.cos( degToRad * self.carPitch) zDir = 1 * math.sin(degToRad * self.carPitch) return (xDir, yDir, zDir) def setUpCarCollider(self): self.carCollideTrav = CollisionTraverser() base.cTrav = self.carCollideTrav self.handler = CollisionHandlerQueue() self.carRay = CollisionRay(self.carPositionX, self.carPositionY, self.carPositionZ, 0, 0, -1) self.carForwardHandler = CollisionHandlerQueue() # so that it doesn't collide with things forward and backward. degToRad = math.pi / 180 (xDir, yDir, zDir) = self.findCarFrontDir() self.carRayForward = CollisionRay(self.carPositionX, self.carPositionY, self.carPositionZ, xDir, yDir, zDir) self.carForwardCollision = CollisionNode("forwardCollision") self.carForwardCollision.addSolid(self.carRayForward) self.carForwardCollision.setIntoCollideMask(CollideMask.allOff()) self.carForwardCollisionNode = self.car.attachNewNode( self.carForwardCollision) (centerX, centerY) = self.findActualCenter(0, 0, self.adjustedXForCenter, self.adjustedYForCenter, self.carYaw) self.carRayForward.setOrigin(5, 10, 5) self.carCollision = CollisionNode("groundCollision") self.carCollision.addSolid(self.carRay) self.carCollision.setIntoCollideMask(CollideMask.allOff()) self.carCollisionNode = self.car.attachNewNode(self.carCollision) self.carCollideTrav.addCollider(self.carCollisionNode, self.handler) self.carCollideTrav.addCollider(self.carForwardCollisionNode, self.carForwardHandler) self.carForwardCollisionNode.show() def setUpMouseCollider(self): # clicking on objects stuff came from here: # https://www.panda3d.org/manual/index.php/Collision_Traversers # https://www.panda3d.org/manual/index.php/Collision_Handlers # will not use the traverser set up by car because slow # instead we will render each time clicked self.mouseCollideTrav = CollisionTraverser("mouseTraverse") self.mousehandler = CollisionHandlerQueue() # edit this so that from Object is the camera # self.mouseCollideTrav.addCollider(fromObject, queue) # self.mouseCollideTrav.traverse(render) # this next part came from: # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects pickerNode = CollisionNode("mouseRay") pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) pickerNode.setIntoCollideMask(CollideMask.allOff()) self.pickerRay = CollisionRay() pickerNode.addSolid(self.pickerRay) pickerNp = camera.attachNewNode(pickerNode) self.mouseCollideTrav.addCollider(pickerNp, self.mousehandler) # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value def switchToCreateMode(self): self.mode = self.modeFly self.destroyInstructions() self.setUpFlyingInstructions() self.hasSwitched = True self.setUpCreateButtons() def switchToDrivingMode(self): self.mode = self.modeRace self.destroyInstructions() self.setUpDrivingInstructions() self.hasSwitched = True def switchToMainMode(self): self.mode = 0 self.setUpStartScreenButtons() def setTutorialText(self, str): # reusing inst so that it is easy to erase self.inst[0] = self.addInstructions(.06, str) def move(self, task): if (self.keyMap["to-main"]): self.switchToMainMode() elif (self.mode == self.modeFly): if self.keyMap["switch-mode"] and not self.hasSwitched: self.switchToDrivingMode() self.destroyCreateButtons() elif not self.keyMap["switch-mode"]: # to ensure switch mode only happens once per button pressed self.hasSwitched = False self.findNewCameraPosition() self.checkAndAddNewObject() elif (self.mode == self.modeRace): if self.keyMap["switch-mode"] and not self.hasSwitched: self.destroyWin() self.switchToCreateMode() elif not self.keyMap["switch-mode"]: # this ensures that when key is pressed only switch states once self.hasSwitched = False self.findCarNewXandY() # when implementing the use of the mouse look here: # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects self.setCarZ() self.setCameraPositionBehindCar() if (self.keyMap["race-start"] and not self.raceBegan and len(self.poles) >= 2): self.destroyWin() # try so that if there are not enough poles then the game # doesn't crash try: self.raceBegan = True self.raceTime = time.time() # puts in the car where the first two poles are # first col of poles is model, second x coord, thrid y coord, fourth z coord self.carPositionX = (self.poles[0][1] + self.poles[1][1]) / 2 self.carPositionY = (self.poles[0][2] + self.poles[1][2]) / 2 # meant to show where car should go # got info on how to do point lights from here: # https://www.panda3d.org/manual/index.php/Lighting self.beaconLight = PointLight("beaconLight") self.beaconLight.setColor((1, 1, 1, 1)) self.beaconLight.setAttenuation((0, 0, 1)) self.beaconLightHolder = render.attachNewNode( self.beaconLight) (beaconLightX, beaconLightY) = self.getNextGateCenter() # target for driver if (self.target == None): self.target = loader.loadModel("BeaconLight.egg") self.target.setTwoSided(True) self.target.reparentTo(render) if (beaconLightX != None): self.beaconLightHolder.setPos(beaconLightX, beaconLightY, self.beaconLightZ) render.setLight(self.beaconLightHolder) self.target.setPos(beaconLightX, beaconLightY, self.beaconLightZ) except: # not enough poles pass if (self.raceBegan): # minus 1 just in case non even if (self.poleOn + 1 >= len(self.poles)): self.raceBegan = False self.addWin(time.time() - self.raceTime) # since race ended try: self.target.destroy() except: pass self.beaconLight = None # use object + lights self.beaconLightHolder = None self.poleOn = 0 else: acceptableError = 100 # formula I created: (p2y-p1y)/(p2x-p1x)*(p2x-pAx)+p2y = # expected pAy # so if the actual car positionY is within acceptableError of # pAy then the car is between the two poles # if in between poles middleX = (self.poles[self.poleOn][1] + self.poles[self.poleOn + 1][1]) / 2 middleY = (self.poles[self.poleOn][2] + self.poles[self.poleOn + 1][2]) / 2 expectedCarY = ( (self.poles[self.poleOn][2] - self.poles[self.poleOn + 1][2]) / (self.poles[self.poleOn][1] - self.poles[self.poleOn + 1][1]) * (self.poles[self.poleOn][1] - self.carPositionX) + self.poles[self.poleOn][2]) # do not really care about car being inbetween pole in z axis # because 2 demensional if (expectedCarY + acceptableError > self.carPositionY and expectedCarY - acceptableError < self.carPositionY): self.poleOn += 2 # only when last pole found is it necesary to add light # to guide to next place elsewhere (beaconLightX, beaconLightY) = self.getNextGateCenter() if (beaconLightX != None): self.beaconLightHolder.setPos( beaconLightX, beaconLightY, self.beaconLightZ) self.target.setPos(beaconLightX, beaconLightY, self.beaconLightZ) elif (self.mode == self.modeTutorial): self.destroyWin() # do the tutorial part for the creating timeBeforeNext = 2 if (self.tutorialPause == True): if (time.time() - self.tutorialActionTime > timeBeforeNext): self.tutorialPause = False else: if (self.tutorialStep == -1): self.destroyInstructions() self.setTutorialText( "use w and s to move camera up and down") self.tutorialStep += 1 # do this until the user has completed all of the task self.checkTutorialStep( 0, (self.keyMap["cam-up"] or self.keyMap["cam-down"]), "use a and d to rotate camera right and left") self.checkTutorialStep( 1, (self.keyMap["cam-left"] or self.keyMap["cam-right"]), "use up-arrow and down-arrow to turn camera forward and backward" ) self.checkTutorialStep( 2, (self.keyMap["forward"] or self.keyMap["backward"]), "use left-arrow and right-arrow to slide camera left and right" ) self.checkTutorialStep( 3, (self.keyMap["left"] or self.keyMap["right"]), "use mouse click to place objects on terrain") self.checkTutorialStep( 4, (self.keyMap["mouse-click"]), "use up-arrow and down-arrow to move car forward and backward", (self.switchToDrivingMode, self.destroyInstructions)) # need to ensure that the mode stays as tutorial self.mode = self.modeTutorial # then tutorial part for the driving self.checkTutorialStep( 5, (self.keyMap["forward"] or self.keyMap["backward"]), "use right-arrow and left-arrow to rotate car left and right" ) self.checkTutorialStep( 6, (self.keyMap["left"] or self.keyMap["right"]), "Use poles to make the race course\n use z to start race") self.checkTutorialStep( 7, True, "Follow yellow block through the gates till you win") self.checkTutorialStep( 8, True, "Watch for high Terrain and blocks because you can not get through those" ) self.checkTutorialStep(9, True, "") if (self.tutorialStep > 9): # switch to main self.switchToMainMode() # for movement if (self.tutorialStep <= 4): self.findNewCameraPosition() self.checkAndAddNewObject() if (self.tutorialStep > 4 and self.tutorialStep <= 9): self.findCarNewXandY() self.setCarZ() self.setCameraPositionBehindCar() return task.cont def getNextGateCenter(self): if (len(self.poles) > self.poleOn + 1): positionX = (self.poles[self.poleOn][1] + self.poles[self.poleOn + 1][1]) / 2 positionY = (self.poles[self.poleOn][2] + self.poles[self.poleOn + 1][2]) / 2 return (positionX, positionY) else: return (None, None) def checkTutorialStep(self, step, keysNeeded, nextText, functions=None): if (self.tutorialStep == step and self.tutorialNextStep == True): if (functions != None): for func in functions: func() self.destroyInstructions() self.setTutorialText(nextText) self.tutorialStep += 1 self.tutorialNextStep = False elif (self.tutorialStep == step and keysNeeded): self.tutorialNextStep = True self.tutorialActionTime = time.time() self.tutorialPause = True def setUpTutorial(self): self.tutorialStep = -1 self.tutorialPause = False # this records when last tutorial action taken self.tutorialActionTime = 0 self.tutorialNextStep = False def checkAndAddNewObject(self): # clicking on 3D objects comes from here: # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects # checks if it needs to add any objects: if (self.keyMap["mouse-click"] and self.mouseClicked == False): self.mouseClicked = True # found way to speed this up by only doing collision check # when mouse clicked by not using cTrav like in this method # the way I did it I found here: # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects # self.mouseCollideTrav.traverse(render) if (base.mouseWatcherNode.hasMouse()): mousePos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mousePos.getX(), mousePos.getY()) # do not put this before previous line, will get the coordinates # of last mouse click and where pickerRay was # ahhhhhhh!!!!!!!!!!! self.mouseCollideTrav.traverse(render) if (self.mousehandler.getNumEntries() > 0): entries = list(self.mousehandler.getEntries()) # pathagorean formula for sorting entries.sort( key=lambda x: ((x.getSurfacePoint(render).getX( ) - self.cameraPositionX)**2 + (x.getSurfacePoint( render).getY() - self.cameraPositionY)**2)**.5) newX = entries[0].getSurfacePoint(render).getX() newY = entries[0].getSurfacePoint(render).getY() newZ = entries[0].getSurfacePoint(render).getZ() adjustedX = 10 / 2 adjustedY = 20 / 2 yaw = 0 # have to adjust this once there are different sized # objects added (actualXPos, actualYPos) = RacingGame.findActualCenter( self, newX, newY, adjustedX, adjustedY, yaw) if (self.createdObject == self.createPole): self.poles.append([ loader.loadModel("TestPole.egg"), actualXPos, actualYPos, newZ ]) self.poles[len(self.poles) - 1][0].reparentTo(render) self.poles[len(self.poles) - 1][0].setTwoSided(True) self.poles[len(self.poles) - 1][0].setPos( actualXPos, actualYPos, newZ) else: newCar = loader.loadModel("TestCar.egg") newCar.reparentTo(render) newCar.setPos(actualXPos, actualYPos, newZ) # should take out because slow, but objects can not be # seen without this because only seen from one direction # even though normal vectors set up. newCar.setTwoSided(True) self.objects.append(newCar) elif (not self.keyMap["mouse-click"]): # elif because for some reason mouseClicked was becoming false # while click still pressed self.mouseClicked = False def findNewCameraPosition(self): # 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() # the angle is in degrees with 360 equal to full rotation angleAdjustment = 100 if self.keyMap["cam-left"]: self.cameraYaw += angleAdjustment * dt if self.keyMap["cam-right"]: self.cameraYaw -= angleAdjustment * dt if self.keyMap["cam-up"]: self.cameraPitch += angleAdjustment * dt if self.keyMap["cam-down"]: self.cameraPitch -= angleAdjustment * dt positionAdjustment = 500 # should switch rad and Deg in variable name radToDeg = math.pi / 180 # the x and y component of left and right moves, do not need to # compensate in z axis because not doing any roll, so there should be # no zComponent xComponent = math.cos(self.cameraYaw * radToDeg) yComponent = math.sin(self.cameraYaw * radToDeg) if self.keyMap["left"]: self.cameraPositionX -= positionAdjustment * dt * xComponent self.cameraPositionY -= positionAdjustment * dt * yComponent if self.keyMap["right"]: self.cameraPositionX += positionAdjustment * dt * xComponent self.cameraPositionY += positionAdjustment * dt * yComponent # for going forward, the orientation is rotated 90 degrees so need to # change components xComponent = math.cos(self.cameraYaw * radToDeg + math.pi / 2) * math.cos(self.cameraPitch * radToDeg) yComponent = math.sin(self.cameraYaw * radToDeg + math.pi / 2) * math.cos(self.cameraPitch * radToDeg) zComponent = math.sin(self.cameraPitch * radToDeg) if self.keyMap["forward"]: self.cameraPositionX += positionAdjustment * dt * xComponent self.cameraPositionY += positionAdjustment * dt * yComponent self.cameraPositionZ += positionAdjustment * dt * zComponent if self.keyMap["backward"]: self.cameraPositionX -= positionAdjustment * dt * xComponent self.cameraPositionY -= positionAdjustment * dt * yComponent self.cameraPositionZ -= positionAdjustment * dt * zComponent self.camera.setX(self.cameraPositionX) self.camera.setY(self.cameraPositionY) self.camera.setZ(self.cameraPositionZ) self.camera.setHpr(self.cameraYaw, self.cameraPitch, 0) def carForwardImpact(self): # update position so that it is pointing right directions #(dirX, dirY, dirZ) = self.findCarFrontDir() #self.carRayForward.setDirection(dirX, dirY, dirZ) degToRad = math.pi / 180 # + math.pi since it is taking corner and going to center rather # than opposite that function actually does #(centerX,centerY) = self.findActualCenter(0,0,self.adjustedXForCenter, # self.adjustedYForCenter, self.carYaw # +math.pi) posAboveGround = 5 # need to update with new coordinates self.carCollideTrav.traverse(render) collisions = list(self.carForwardHandler.getEntries()) # closest collision using pythagorean formula collisions.sort( key=lambda x: (x.getSurfacePoint(render).getX() - self.carPositionX)**2 + (x.getSurfacePoint(render).getY() - self.carPositionY)**2) if (len(collisions) > 0): (actualX, actualY) = RacingGame.findActualCenter( self, self.carPositionX, self.carPositionY, self.adjustedXForCenter, self.adjustedYForCenter, self.carYaw) distance = ( (collisions[0].getSurfacePoint(render).getX() - actualX)**2 + (collisions[0].getSurfacePoint(render).getY() - actualY)** 2)**.5 error = .9 # so that the collisionray does not detect car itself return distance / 2 <= self.adjustedYForCenter * .9 else: return False def findCarNewXandY(self): # 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. deltaTime = globalClock.getDt() degreeAdjustment = 60 positionAdjustment = 100 # should switch rad and Deg in variable name radToDeg = math.pi / 180 # the x and y component of left and right moves, do not need to # compensate in z axis because not doing any roll, so there should be # no zComponent xComponent = math.sin(self.carYaw * radToDeg) yComponent = math.cos(self.carYaw * radToDeg) if self.keyMap["left"]: self.carYaw += degreeAdjustment * deltaTime if self.keyMap["right"]: self.carYaw -= degreeAdjustment * deltaTime if (self.keyMap["forward"] and not self.carForwardImpact()): self.carPositionX -= positionAdjustment * deltaTime * xComponent self.carPositionY += positionAdjustment * deltaTime * yComponent if self.keyMap["backward"]: self.carPositionX += positionAdjustment * deltaTime * xComponent self.carPositionY -= positionAdjustment * deltaTime * yComponent # need to consider both the x and y component of offset for both # because x slowly changes to y as it turns (actualXPos, actualYPos) = RacingGame.findActualCenter( self, self.carPositionX, self.carPositionY, self.adjustedXForCenter, self.adjustedYForCenter, self.carYaw) self.car.setX(actualXPos) self.car.setY(actualYPos) self.car.setZ(self.carPositionZ) self.car.setHpr(self.carYaw, self.carPitch, 0) def setCarZ(self): # almost directly taken from ralph example entries = list(self.handler.getEntries()) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) # worry about which thing it collides with later if (len(entries) > 0): # and entries[0].getIntoNode().getName() == "mountainCollide": self.carPositionZ = (entries[0].getSurfacePoint(render).getZ()) else: # because at 25 everything should be below car and do not want # to continually go up or else it may go up forever. self.carPositionZ = 25 self.setCameraPositionBehindCar() def setCameraPositionBehindCar(self): # Modify view of camera so that it is behind car # should be named degToRad radToDeg = math.pi / 180 distanceBehind = 200 distanceAbove = 60 self.camera.setHpr(self.carYaw, -.5, 0) (actualXPos, actualYPos) = self.findActualCenter( self.carPositionX, self.carPositionY, self.adjustedXForCenter, self.adjustedXForCenter, self.carYaw) camX = actualXPos + distanceBehind * math.sin(radToDeg * self.carYaw) camY = actualYPos - distanceBehind * math.cos(radToDeg * self.carYaw) camZ = self.carPositionZ + distanceAbove self.camera.setPos(camX, camY, camZ) def findActualCenter(self, positionX, positionY, adjustedX, adjustedY, yaw): # will need to fix this later, it seems to be adjusting wrong # so that it is puting box away from click instead of on it # update, I think this is fixed?!? degToRad = math.pi / 180 actualXPos = (positionX - adjustedX * math.cos(degToRad * yaw) + adjustedY * math.sin(degToRad * yaw)) actualYPos = (positionY - adjustedY * math.cos(degToRad * yaw) - adjustedX * math.sin(degToRad * yaw)) return (actualXPos, actualYPos)
def makeWriteOffTrack(self): pad = BattleProps.globalPropPool.getProp('pad') pad.setScale(1.89) pencil = BattleProps.globalPropPool.getProp('pencil') BattleParticles.loadParticles() checkmark = copyProp(BattleParticles.getParticle('checkmark')) checkmark.setBillboardPointEye() # Make prop virtual: pad.setColorScale(1.0, 0.0, 0.0, 0.8) pad.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd)) pencil.setColorScale(1.0, 0.0, 0.0, 0.8) pencil.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd)) checkmark.setColorScale(1.0, 0.0, 0.0, 0.8) checkmark.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd)) # Prop collisions: colNode = CollisionNode(self.uniqueName('SuitAttack')) colNode.setTag('damage', str(self.attackInfo[1])) bounds = checkmark.getBounds() center = bounds.getCenter() radius = bounds.getRadius() sphere = CollisionSphere(center.getX(), center.getY(), center.getZ(), radius) sphere.setTangible(0) colNode.addSolid(sphere) colNode.setIntoCollideMask(WallBitmask) checkmark.attachNewNode(colNode) toonId = self.toon toon = base.cr.doId2do.get(toonId) if not toon: return self.virtualSuit.lookAt(toon) if self.virtualSuit.style.body in ['a', 'b']: throwDelay = 3 elif self.virtualSuit.style.body == 'c': throwDelay = 2.3 else: throwDelay = 2 def throwProp(): if not self.virtualSuit: return toon = self.cr.doId2do.get(toonId) if not toon: self.cleanupProp(checkmark, False) self.finishPropAttack() return self.virtualSuit.lookAt(toon) checkmark.wrtReparentTo(render) hitPos = toon.getPos() + Vec3(0, 0, 2.5) distance = (checkmark.getPos() - hitPos).length() speed = 50.0 if self.attackProp == 'teeth': throwSequence = Sequence( Parallel( checkmark.posInterval(distance / speed, hitPos), ActorInterval(checkmark, 'teeth', duration=distance / speed), ), Func(self.cleanupProp, checkmark, False), ) else: throwSequence = Sequence( checkmark.posInterval(distance / speed, hitPos), Func(self.cleanupProp, checkmark, False)) throwSequence.start() pencilTrack = Sequence( Wait(0.5), Func(pencil.setPosHpr, -0.47, 1.08, 0.28, 21.045, 12.702, -176.374), Func(pencil.reparentTo, self.virtualSuit.getRightHand()), LerpScaleInterval(pencil, 0.5, Point3(1.5, 1.5, 1.5), startScale=Point3(0.01)), Wait(throwDelay), Func(checkmark.reparentTo, render), Func(checkmark.setScale, 1.6), Func(checkmark.setPosHpr, pencil, 0, 0, 0, 0, 0, 0), Func(checkmark.setP, 0), Func(checkmark.setR, 0), Func(throwProp), Wait(0.3), LerpScaleInterval(pencil, 0.5, Point3(0.01, 0.01, 0.01)), Func(pencil.removeNode), ) suitTrack = Sequence( ActorInterval(self.virtualSuit, 'hold-pencil'), Func(self.virtualSuit.loop, 'neutral', 0), ) soundTrack = Sequence( Wait(2.3), SoundInterval(self.writeOffSfx, duration=0.9, node=self.virtualSuit), SoundInterval(self.dingSfx, node=self.virtualSuit)) padTrack = Track( (0.0, Func(pad.setPosHpr, -0.25, 1.38, -0.08, -19.078, -6.603, -171.594)), (0.4, Func(pad.reparentTo, self.virtualSuit.getLeftHand())), (3.0, Func(pad.removeNode)), ) track = Sequence( Parallel(suitTrack, soundTrack, padTrack, pencilTrack, Func(self.sayFaceoffTaunt)), Func(self.virtualSuit.loop, 'walk', 0)) return track
class World(ShowBase): def __init__(self): # Setup window size, title and so on load_prc_file_data( "", """ win-size 1600 900 window-title Render Pipeline - Roaming Ralph Demo """) # ------ Begin of render pipeline code ------ # Insert the pipeline path to the system path, this is required to be # able to import the pipeline classes pipeline_path = "../../" # Just a special case for my development setup, so I don't accidentally # commit a wrong path. You can remove this in your own programs. if not os.path.isfile(os.path.join(pipeline_path, "setup.py")): pipeline_path = "../../RenderPipeline/" sys.path.insert(0, pipeline_path) from rpcore import RenderPipeline, SpotLight self.render_pipeline = RenderPipeline() self.render_pipeline.create(self) # ------ End of render pipeline code, thats it! ------ # Set time of day self.render_pipeline.daytime_mgr.time = "7:40" # Use a special effect for rendering the scene, this is because the # roaming ralph model has no normals or valid materials self.render_pipeline.set_effect(render, "scene-effect.yaml", {}, sort=250) self.keyMap = { "left": 0, "right": 0, "forward": 0, "backward": 0, "cam-left": 0, "cam-right": 0 } self.speed = 1.0 base.win.setClearColor(Vec4(0, 0, 0, 1)) # Post the instructions self.inst1 = addInstructions(0.95, "[ESC] Quit") self.inst4 = addInstructions(0.90, "[W] Run Ralph Forward") self.inst4 = addInstructions(0.85, "[S] Run Ralph Backward") self.inst2 = addInstructions(0.80, "[A] Rotate Ralph Left") self.inst3 = addInstructions(0.75, "[D] Rotate Ralph Right") self.inst6 = addInstructions(0.70, "[Left Arrow] Rotate Camera Left") self.inst7 = addInstructions(0.65, "[Right Arrow] 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("resources/world") self.environ.reparentTo(render) self.environ.setPos(0, 0, 0) # Remove wall nodes self.environ.find("**/wall").remove_node() # Create the main character, Ralph self.ralph = Actor("resources/ralph", { "run": "resources/ralph-run", "walk": "resources/ralph-walk" }) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(Vec3(-110.9, 29.4, 1.8)) # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("a", self.setKey, ["left", 1]) self.accept("d", self.setKey, ["right", 1]) self.accept("w", self.setKey, ["forward", 1]) self.accept("s", self.setKey, ["backward", 1]) self.accept("arrow_left", self.setKey, ["cam-left", 1]) self.accept("arrow_right", self.setKey, ["cam-right", 1]) self.accept("a-up", self.setKey, ["left", 0]) self.accept("d-up", self.setKey, ["right", 0]) self.accept("w-up", self.setKey, ["forward", 0]) self.accept("s-up", self.setKey, ["backward", 0]) self.accept("arrow_left-up", self.setKey, ["cam-left", 0]) self.accept("arrow_right-up", self.setKey, ["cam-right", 0]) self.accept("=", self.adjustSpeed, [0.25]) self.accept("+", self.adjustSpeed, [0.25]) self.accept("-", self.adjustSpeed, [-0.25]) taskMgr.add(self.move, "moveTask") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX() + 10, self.ralph.getY() + 10, 2) base.camLens.setFov(80) # 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 # Adjust movement speed def adjustSpeed(self, delta): newSpeed = self.speed + delta if 0 <= newSpeed <= 3: self.speed = newSpeed # 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()) elif (self.keyMap["right"] != 0): self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt()) if (self.keyMap["forward"] != 0): self.ralph.setY(self.ralph, -25 * self.speed * globalClock.getDt()) elif (self.keyMap["backward"] != 0): self.ralph.setY(self.ralph, 25 * self.speed * 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["backward"]!=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) 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) 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 GameContainer(ShowBase): def __init__(self): ShowBase.__init__(self) ########## Window configuration ######### wp = WindowProperties() wp.setSize(1024, 860) self.win.requestProperties(wp) ########## Gameplay settings ######### self.GAME_MODE = NORMAL self.NAVIGATION_MODE = SPACE self.mode_initialized = False #Trigger game chain self.loadWorld(LEVEL) ######### Camera ######### self.disableMouse() self.mainCamera = Camera(self.camera) self.mainCamera.camObject.setHpr(0, 0, 0) ######### Events ######### self.taskMgr.add(self.gameLoop, "gameLoop", priority=35) self.keys = {"w": 0, "s": 0, "a": 0, "d": 0, "space": 0} self.accept("w", self.setKey, ["w", 1]) self.accept("w-up", self.setKey, ["w", 0]) self.accept("s", self.setKey, ["s", 1]) self.accept("s-up", self.setKey, ["s", 0]) self.accept("a", self.setKey, ["a", 1]) self.accept("a-up", self.setKey, ["a", 0]) self.accept("d", self.setKey, ["d", 1]) self.accept("d-up", self.setKey, ["d", 0]) self.accept("space", self.setKey, ["space", 1]) self.accept("space-up", self.setKey, ["space", 0]) self.accept("wheel_up", self.zoomCamera, [-1]) self.accept("wheel_down", self.zoomCamera, [1]) self.accept("escape", self.switchGameMode, [IN_GAME_MENU]) self.accept("window-event", self.handleWindowEvent) self.accept("playerGroundRayJumping-in", self.avatar.handleCollisionEvent, ["in"]) self.accept("playerGroundRayJumping-out", self.avatar.handleCollisionEvent, ["out"]) ######### GUI ######### self.gui_elements = [] def loadWorld(self, level): self.avatarActor = Actor("models/panda", {"walk": "models/panda-walk"}) self.avatarActor.setScale(.5, .5, .5) self.avatarActor.setHpr(180, 0, 0) self.avatarActor.setPythonTag("moving", False) self.avatarActor.setCollideMask(BitMask32.allOff()) if int(level) == level: pass ########## Terrain ######### self.environ = loader.loadModel("models/environment") self.environ.setName("terrain") self.environ.reparentTo(render) self.environ.setPos(0, 0, 0) self.environ.setCollideMask(BitMask32.bit(0)) ######### Models ######### ######### Physics ######### base.enableParticles() gravityForce = LinearVectorForce(0, 0, -9.81) gravityForce.setMassDependent(False) gravityFN = ForceNode("world-forces") gravityFN.addForce(gravityForce) render.attachNewNode(gravityFN) base.physicsMgr.addLinearForce(gravityForce) self.avatarPhysicsActorNP = render.attachNewNode(ActorNode("player")) self.avatarPhysicsActorNP.node().getPhysicsObject().setMass(50.) self.avatarActor.reparentTo(self.avatarPhysicsActorNP) base.physicsMgr.attachPhysicalNode(self.avatarPhysicsActorNP.node()) self.avatarPhysicsActorNP.setPos(15, 10, 5) ######### Game objects ######### self.avatar = Avatar(self.avatarPhysicsActorNP) ######### Collisions ######### self.cTrav = CollisionTraverser() #Make player rigid body self.pandaBodySphere = CollisionSphere(0, 0, 4, 3) self.pandaBodySphereNode = CollisionNode("playerBodyRay") self.pandaBodySphereNode.addSolid(self.pandaBodySphere) self.pandaBodySphereNode.setFromCollideMask(BitMask32.bit(0)) self.pandaBodySphereNode.setIntoCollideMask(BitMask32.allOff()) self.pandaBodySphereNodepath = self.avatar.objectNP.attachNewNode( self.pandaBodySphereNode) self.pandaBodySphereNodepath.show() self.pandaBodyCollisionHandler = PhysicsCollisionHandler() self.pandaBodyCollisionHandler.addCollider( self.pandaBodySphereNodepath, self.avatar.objectNP) #Keep player on ground self.pandaGroundSphere = CollisionSphere(0, 0, 1, 1) self.pandaGroundSphereNode = CollisionNode("playerGroundRay") self.pandaGroundSphereNode.addSolid(self.pandaGroundSphere) self.pandaGroundSphereNode.setFromCollideMask(BitMask32.bit(0)) self.pandaGroundSphereNode.setIntoCollideMask(BitMask32.allOff()) self.pandaGroundSphereNodepath = self.avatar.objectNP.attachNewNode( self.pandaGroundSphereNode) self.pandaGroundSphereNodepath.show() self.pandaGroundCollisionHandler = PhysicsCollisionHandler() self.pandaGroundCollisionHandler.addCollider( self.pandaGroundSphereNodepath, self.avatar.objectNP) #Notify when player lands self.pandaGroundRayJumping = CollisionSphere(0, 0, 1, 1) self.pandaGroundRayNodeJumping = CollisionNode( "playerGroundRayJumping") self.pandaGroundRayNodeJumping.addSolid(self.pandaGroundRayJumping) self.pandaGroundRayNodeJumping.setFromCollideMask(BitMask32.bit(0)) self.pandaGroundRayNodeJumping.setIntoCollideMask(BitMask32.allOff()) self.pandaGroundRayNodepathJumping = self.avatar.objectNP.attachNewNode( self.pandaGroundRayNodeJumping) self.pandaGroundRayNodepathJumping.show() self.collisionNotifier = CollisionHandlerEvent() self.collisionNotifier.addInPattern("%fn-in") self.collisionNotifier.addOutPattern("%fn-out") self.cTrav.addCollider(self.pandaGroundSphereNodepath, self.pandaGroundCollisionHandler) self.cTrav.addCollider(self.pandaGroundRayNodepathJumping, self.collisionNotifier) self.cTrav.addCollider(self.pandaBodySphereNodepath, self.pandaBodyCollisionHandler) def setKey(self, key, value): self.keys[key] = value def zoomCamera(self, direction): Camera.AVATAR_DIST += direction def b(self, hey): self.avatarLanded = True def handleWindowEvent(self, window=None): wp = window.getProperties() self.win_center_x = wp.getXSize() / 2 self.win_center_y = wp.getYSize() / 2 def switchGameMode(self, newGameMode=None): self.cleanupGUI() if self.GAME_MODE == IN_GAME_MENU: if newGameMode == NORMAL: render.clearFog() elif newGameMode == MAIN_MENU: print "bubbles!" elif True: pass self.GAME_MODE = newGameMode self.mode_initialized = False def cleanupGUI(self): for gui_element in self.gui_elements: gui_element.destroy() def evenButtonPositions(self, button_spacing, button_height, num_buttons): center_offset = (button_spacing / (2.0) if (num_buttons % 2 == 0) else 0) button_positions = [] current_pos = center_offset + ((num_buttons - 1) / 2) * button_spacing for i in range(0, num_buttons): button_positions.append(current_pos + (button_height / 2.0)) current_pos -= button_spacing return button_positions def buildInGameMenu(self): props = WindowProperties() props.setCursorHidden(False) base.win.requestProperties(props) resume_button = DirectButton( text="Resume", scale=.1, command=(lambda: self.switchGameMode(NORMAL)), rolloverSound=None) main_menu_button = DirectButton(text="Main Menu", scale=.1, command=self.b, rolloverSound=None) options_button = DirectButton(text="Options", scale=.1, command=self.b, rolloverSound=None) exit_button = DirectButton(text="Exit", scale=.1, command=exit, rolloverSound=None) BUTTON_SPACING = .2 BUTTON_HEIGHT = resume_button.getSy() button_positions = self.evenButtonPositions(BUTTON_SPACING, BUTTON_HEIGHT, 4) resume_button.setPos(Vec3(0, 0, button_positions[0])) main_menu_button.setPos(Vec3(0, 0, button_positions[1])) options_button.setPos(Vec3(0, 0, button_positions[2])) exit_button.setPos(Vec3(0, 0, button_positions[3])) self.gui_elements.append(resume_button) self.gui_elements.append(main_menu_button) self.gui_elements.append(options_button) self.gui_elements.append(exit_button) def buildMainMenu(self): props = WindowProperties() props.setCursorHidden(False) base.win.requestProperties(props) start_game_button = DirectButton(text="Start", scale=.1, command=self.b) select_level_button = DirectButton(text="Select Level", scale=.1, command=self.b) game_options_button = DirectButton(text="Options", scale=.1, command=self.b) exit_button = DirectButton(text="Exit", scale=.1, command=exit) BUTTON_SPACING = .2 BUTTON_HEIGHT = start_game_button.getSy() button_positions = self.evenButtonPositions(BUTTON_SPACING, BUTTON_HEIGHT) start_game_button.setPos(Vec3(0, 0, button_positions[0])) select_level_button.setPos(Vec3(0, 0, button_positions[1])) game_options_button.setPos(Vec3(0, 0, button_positions[2])) exit_button.setPos(Vec3(0, 0, button_positions[3])) self.gui_elements.append(start_game_button) self.gui_elements.append(select_level_button) self.gui_elements.append(game_options_button) self.gui_elements.append(exit_button) def gameLoop(self, task): #Compensate for inconsistent update intervals dt = globalClock.getDt() if self.GAME_MODE == MAIN_MENU: if not self.mode_initialized: self.buildMainMenu() self.mode_initialized = True if self.GAME_MODE == IN_GAME_MENU: #Fog out background if not self.mode_initialized: inGameMenuFogColor = (50, 150, 50) inGameMenuFog = Fog("inGameMenuFog") inGameMenuFog.setMode(Fog.MExponential) inGameMenuFog.setColor(*inGameMenuFogColor) inGameMenuFog.setExpDensity(.01) render.setFog(inGameMenuFog) self.buildInGameMenu() self.mode_initialized = True if self.GAME_MODE == NORMAL: if not self.mode_initialized: props = WindowProperties() props.setCursorHidden(True) base.win.requestProperties(props) self.last_mouse_x = self.win.getPointer(0).getX() self.last_mouse_y = self.win.getPointer(0).getY() self.mode_initialized = True if self.NAVIGATION_MODE == TERRAIN: pass elif self.NAVIGATION_MODE == SPACE: pass print "asssss" print self.NAVIGATION_MODE #Handle keyboard input self.avatar.handleKeys(self.keys) self.avatar.move(dt) ########## Mouse-based viewpoint rotation ########## mouse_pos = self.win.getPointer(0) #Side to side if self.NAVIGATION_MODE == TERRAIN: current_mouse_x = mouse_pos.getX() mouse_shift_x = current_mouse_x - self.last_mouse_x self.last_mouse_x = current_mouse_x if current_mouse_x < 5 or current_mouse_x >= ( self.win_center_x * 1.5): base.win.movePointer(0, self.win_center_x, current_mouse_y) self.last_mouse_x = self.win_center_x yaw_shift = -((mouse_shift_x) * Camera.ROT_RATE[0]) self.avatar.yawRot += yaw_shift #Up and down current_mouse_y = mouse_pos.getY() mouse_shift_y = current_mouse_y - self.last_mouse_y self.last_mouse_y = current_mouse_y if current_mouse_y < 5 or current_mouse_y >= (self.win_center_y * 1.5): base.win.movePointer(0, current_mouse_x, self.win_center_y) self.last_mouse_y = self.win_center_y pitch_shift = -((mouse_shift_y) * Camera.ROT_RATE[1]) self.mainCamera.pitchRot += pitch_shift if self.mainCamera.pitchRot > Camera.FLEX_ROT_MAG[0]: self.mainCamera.pitchRot = Camera.FLEX_ROT_MAG[0] elif self.mainCamera.pitchRot < -Camera.FLEX_ROT_MAG[0]: self.mainCamera.pitchRot = -Camera.FLEX_ROT_MAG[0] xy_plane_cam_dist = Camera.AVATAR_DIST cam_x_adjust = xy_plane_cam_dist * sin(radians(self.avatar.yawRot)) cam_y_adjust = xy_plane_cam_dist * cos(radians(self.avatar.yawRot)) cam_z_adjust = Camera.ELEVATION self.avatar.objectNP.setH(self.avatar.yawRot) self.mainCamera.camObject.setH(self.avatar.yawRot) self.mainCamera.camObject.setP(self.mainCamera.pitchRot) self.mainCamera.camObject.setPos( self.avatar.objectNP.getX() + cam_x_adjust, self.avatar.objectNP.getY() - cam_y_adjust, self.avatar.objectNP.getZ() + cam_z_adjust) #Find collisions self.cTrav.traverse(render) return Task.cont
class World(DirectObject): def __init__(self): self.last_mousex = 0 self.last_mousey = 0 self.zone = None self.zone_reload_name = None self.winprops = WindowProperties( ) # simple console output self.consoleNode = NodePath(PandaNode("console_root")) self.consoleNode.reparentTo(aspect2d) self.console_num_lines = 24 self.console_cur_line = -1 self.console_lines = [] for i in range(0, self.console_num_lines): self.console_lines.append(OnscreenText(text='', style=1, fg=(1,1,1,1), pos=(-1.3, .4-i*.05), align=TextNode.ALeft, scale = .035, parent = self.consoleNode)) # Configuration self.consoleOut('zonewalk v.%s loading configuration' % VERSION) self.configurator = Configurator(self) cfg = self.configurator.config resaveRes = False if 'xres' in cfg: self.xres = int(cfg['xres']) else: self.xres = 1024 resaveRes = True if 'yres' in cfg: self.yres = int(cfg['yres']) else: self.yres = 768 resaveRes = True if resaveRes: self.saveDefaultRes() self.xres_half = self.xres / 2 self.yres_half = self.yres / 2 self.mouse_accum = MouseAccume( lambda: (self.xres_half,self.yres_half)) self.eyeHeight = 7.0 self.rSpeed = 80 self.flyMode = 1 # application window setup base.win.setClearColor(Vec4(0,0,0,1)) self.winprops.setTitle( 'zonewalk') self.winprops.setSize(self.xres, self.yres) base.win.requestProperties( self.winprops ) base.disableMouse() # network test stuff self.login_client = None if 'testnet' in cfg: if cfg['testnet'] == '1': self.doLogin() # Post the instructions self.title = addTitle('zonewalk v.' + VERSION) self.inst0 = addInstructions(0.95, "[FLYMODE][1]") self.inst1 = addInstructions(-0.95, "Camera control with WSAD/mouselook. Press K for hotkey list, ESC to exit.") self.inst2 = addInstructions(0.9, "Loc:") self.inst3 = addInstructions(0.85, "Hdg:") self.error_inst = addInstructions(0, '') self.kh = [] self.campos = Point3(155.6, 41.2, 4.93) base.camera.setPos(self.campos) # Accept the application control keys: currently just esc to exit navgen self.accept("escape", self.exitGame) self.accept("window-event", self.resizeGame) # Create some lighting ambient_level = .6 ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(ambient_level, ambient_level, ambient_level, 1.0)) render.setLight(render.attachNewNode(ambientLight)) direct_level = 0.8 directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(0.0, 0.0, -1.0)) directionalLight.setColor(Vec4(direct_level, direct_level, direct_level, 1)) directionalLight.setSpecularColor(Vec4(direct_level, direct_level, direct_level, 1)) render.setLight(render.attachNewNode(directionalLight)) # create a point light that will follow our view point (the camera for now) # attenuation is set so that this point light has a torch like effect self.plight = PointLight('plight') self.plight.setColor(VBase4(0.8, 0.8, 0.8, 1.0)) self.plight.setAttenuation(Point3(0.0, 0.0, 0.0002)) self.plnp = base.camera.attachNewNode(self.plight) self.plnp.setPos(0, 0, 0) render.setLight(self.plnp) self.cam_light = 1 self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "cam-left":0, \ "cam-right":0, "mouse3":0, "flymode":1 } # setup FOG self.fog_colour = (0.8,0.8,0.8,1.0) self.linfog = Fog("A linear-mode Fog node") self.linfog.setColor(self.fog_colour) self.linfog.setLinearRange(700, 980) # onset, opaque distances as params # linfog.setLinearFallback(45,160,320) base.camera.attachNewNode(self.linfog) render.setFog(self.linfog) self.fog = 1 # camera control self.campos = Point3(0, 0, 0) self.camHeading = 0.0 self.camPitch = 0.0 base.camLens.setFov(65.0) base.camLens.setFar(1200) self.cam_speed = 0 # index into self.camp_speeds self.cam_speeds = [40.0, 80.0, 160.0, 320.0, 640.0] # Collision Detection for "WALKMODE" # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. The ray 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.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0.0, 0.0, 0.0) self.camGroundRay.setDirection(0,0,-1) # straight down self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) # attach the col node to the camCollider dummy node 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.camGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring # self.cTrav.showCollisions(render) # Add the spinCameraTask procedure to the task manager. # taskMgr.add(self.spinCameraTask, "SpinCameraTask") taskMgr.add(self.camTask, "camTask") self.toggleControls(1) # need to step the task manager once to make our fake console work taskMgr.step() # CONSOLE --------------------------------------------------------------------- def consoleScroll(self): for i in range(0, self.console_num_lines-1): self.console_lines[i].setText(self.console_lines[i+1].getText()) def consoleOut(self, text): print text # output to stdout/log too if self.console_cur_line == self.console_num_lines-1: self.consoleScroll() elif self.console_cur_line < self.console_num_lines-1: self.console_cur_line += 1 self.console_lines[self.console_cur_line].setText(text) taskMgr.step() def consoleOn(self): self.consoleNode.show() def consoleOff(self): self.consoleNode.hide() # User controls ----------------------------------------------------------- def toggleControls(self, on): cfg = self.configurator.config if on == 1: self.accept("escape", self.exitGame) self.accept("1", self.setSpeed, ["speed", 0]) self.accept("2", self.setSpeed, ["speed", 1]) self.accept("3", self.setSpeed, ["speed", 2]) self.accept("4", self.setSpeed, ["speed", 3]) self.accept("5", self.setSpeed, ["speed", 4]) self.accept("alt-f", self.fogToggle) self.accept(cfg['control_lighting'], self.camLightToggle) self.accept(cfg['control_help'], self.displayKeyHelp) self.accept(cfg['control_flymode'], self.toggleFlymode) self.accept(cfg['control_reload-zone'], self.reloadZone) # Deactivate this for now #self.accept("z", self.saveDefaultZone) self.accept(cfg['control_cam-left'], self.setKey, ["cam-left",1]) self.accept(cfg['control_cam-right'], self.setKey, ["cam-right",1]) self.accept(cfg['control_forward'], self.setKey, ["forward",1]) # Mouse1 should be for clicking on objects #self.accept("mouse1", self.setKey, ["forward",1]) self.accept("mouse3", self.setKey, ["mouse3",1]) self.accept(cfg['control_backward'], self.setKey, ["backward",1]) self.accept("k-up", self.hideKeyHelp) self.accept(cfg['control_cam-left']+"-up", self.setKey, ["cam-left",0]) self.accept(cfg['control_cam-right']+"-up", self.setKey, ["cam-right",0]) self.accept(cfg['control_forward']+"-up", self.setKey, ["forward",0]) # Mouse1 should be for clicking on objects #self.accept("mouse1-up", self.setKey, ["forward",0]) self.accept("mouse3-up", self.setKey, ["mouse3",0]) self.accept(cfg['control_backward']+"-up", self.setKey, ["backward",0]) else: messenger.clear() def setSpeed(self, key, value): self.cam_speed = value self.setFlymodeText() def fogToggle(self): if self.fog == 1: render.clearFog() base.camLens.setFar(100000) self.fog = 0 else: render.setFog(self.linfog) base.camLens.setFar(1200) self.fog = 1 def camLightToggle(self): if self.cam_light == 0: render.setLight(self.plnp) self.cam_light = 1 else: render.clearLight(self.plnp) self.cam_light = 0 def displayKeyHelp(self): self.kh = [] msg = 'HOTKEYS:' pos = 0.75 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = '------------------' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'W: camera fwd, S: camera bck, A: rotate view left, D: rotate view right' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = '1-5: set camera movement speed' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'F: toggle Flymode/Walkmode' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'L: load a zone' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'ALT-F: toggle FOG and FAR plane on/off' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'T: toggle additional camera "torch" light on/off' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'Z: set currently loaded zone as new startup default' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'ESC: exit zonewalk' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) def hideKeyHelp(self): for n in self.kh: n.removeNode() def setFlymodeText(self): zname = '' if self.zone: zname = self.zone.name if self.flyMode == 0: self.inst0.setText("[WALKMODE][%i] %s" % (self.cam_speed+1, zname)) else: self.inst0.setText("[FLYMODE][%i] %s " % (self.cam_speed+1, zname)) def toggleFlymode(self): zname = '' if self.zone: zname = self.zone.name if self.flyMode == 0: self.flyMode = 1 else: self.flyMode = 0 self.setFlymodeText() # Define a procedure to move the camera. def spinCameraTask(self, task): angleDegrees = task.time * 6.0 angleRadians = angleDegrees * (pi / 180.0) base.camera.setPos(20 * sin(angleRadians), -20.0 * cos(angleRadians), 3) base.camera.setHpr(angleDegrees, 0, 0) return task.cont def camTask(self, task): # query the mouse mouse_dx = 0 mouse_dy = 0 # if we have a mouse and the right button is depressed if base.mouseWatcherNode.hasMouse(): if self.keyMap["mouse3"] != 0: self.mouse_accum.update() else: self.mouse_accum.reset() mouse_dx = self.mouse_accum.dx mouse_dy = self.mouse_accum.dy self.rXSpeed = fabs(self.mouse_accum.dx) * (self.cam_speed+1) * max(5 * 1000/self.xres,3) self.rYSpeed = fabs(self.mouse_accum.dy) * (self.cam_speed+1) * max(3 * 1000/self.yres,1) if (self.keyMap["cam-left"]!=0 or mouse_dx < 0): if self.rSpeed < 160: self.rSpeed += 80 * globalClock.getDt() if mouse_dx != 0: self.camHeading += self.rXSpeed * globalClock.getDt() else: self.camHeading += self.rSpeed * globalClock.getDt() if self.camHeading > 360.0: self.camHeading = self.camHeading - 360.0 elif (self.keyMap["cam-right"]!=0 or mouse_dx > 0): if self.rSpeed < 160: self.rSpeed += 80 * globalClock.getDt() if mouse_dx != 0: self.camHeading -= self.rXSpeed * globalClock.getDt() else: self.camHeading -= self.rSpeed * globalClock.getDt() if self.camHeading < 0.0: self.camHeading = self.camHeading + 360.0 else: self.rSpeed = 80 if mouse_dy > 0: self.camPitch += self.rYSpeed * globalClock.getDt() elif mouse_dy < 0: self.camPitch -= self.rYSpeed * globalClock.getDt() # set camera heading and pitch base.camera.setHpr(self.camHeading, self.camPitch, 0) # viewer position (camera) movement control v = render.getRelativeVector(base.camera, Vec3.forward()) if not self.flyMode: v.setZ(0.0) move_speed = self.cam_speeds[self.cam_speed] if self.keyMap["forward"] == 1: self.campos += v * move_speed * globalClock.getDt() if self.keyMap["backward"] == 1: self.campos -= v * move_speed * globalClock.getDt() # actually move the camera lastPos = base.camera.getPos() base.camera.setPos(self.campos) # self.plnp.setPos(self.campos) # move the point light with the viewer position # WALKMODE: simple collision detection # we simply check a ray from slightly below the "eye point" straight down # for geometry collisions and if there are any we detect the point of collision # and adjust the camera's Z accordingly if self.flyMode == 0: # move the camera to where it would be if it made the move # the colliderNode moves with it # base.camera.setPos(self.campos) # check for collissons self.cTrav.traverse(render) entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) # print 'collision' entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries) > 0): # and (entries[0].getIntoNode().getName() == "terrain"): # print len(entries) self.campos.setZ(entries[0].getSurfacePoint(render).getZ()+self.eyeHeight) else: self.campos = lastPos base.camera.setPos(self.campos) #if (base.camera.getZ() < self.player.getZ() + 2.0): # base.camera.setZ(self.player.getZ() + 2.0) # update loc and hpr display pos = base.camera.getPos() hpr = base.camera.getHpr() self.inst2.setText('Loc: %.2f, %.2f, %.2f' % (pos.getX(), pos.getY(), pos.getZ())) self.inst3.setText('Hdg: %.2f, %.2f, %.2f' % (hpr.getX(), hpr.getY(), hpr.getZ())) return task.cont def exitGame(self): sys.exit(0) def resizeGame(self,win): props = base.win.getProperties() self.xres = props.getXSize() self.yres = props.getYSize() self.xres_half = self.xres / 2 self.yres_half = self.yres / 2 self.saveDefaultRes() #Records the state of the arrow keys # this is used for camera control def setKey(self, key, value): self.keyMap[key] = value # ------------------------------------------------------------------------- # this is the mythical MAIN LOOP :) def update(self): if self.zone_reload_name != None: self.doReload(self.zone_reload_name) self.zone_reload_name = None if self.zone != None: self.zone.update() taskMgr.step() if self.login_client != None: self.login_client.update() # ZONE loading ------------------------------------------------------------ # general zone loader driver # removes existing zone (if any) and load the new one def loadZone(self, name, path): if path[len(path)-1] != '/': path += '/' if self.zone: self.zone.rootNode.removeNode() self.zone = Zone(self, name, path) error = self.zone.load() if error == 0: self.consoleOff() self.setFlymodeText() base.setBackgroundColor(self.fog_colour) def saveDefaultRes(self): cfg = self.configurator.config cfg['xres'] = str(self.xres) cfg['yres'] = str(self.yres) #self.configurator.saveConfig() # initial world load after bootup def load(self): cfg = self.configurator.config if self.login_client != None: return zone_name = cfg['default_zone'] basepath = cfg['basepath'] self.loadZone(zone_name, basepath) # config save user interfacce def saveDefaultZone(self): if self.zone: cfg = self.configurator.config cfg['default_zone'] = self.zone.name #self.configurator.saveConfig() # zone reload user interface # this gets called from our update loop when it detects that zone_reload_name has been set # we do this in this convoluted fashion in order to keep the main loop taskMgr updates ticking # because otherwise our status console output at various stages during the zone load would not # be displayed. Yes, this is hacky. def doReload(self, name): cfg = self.configurator.config basepath = cfg['basepath'] self.loadZone(name, basepath) # form dialog callback # this gets called from the form when the user has entered a something # (hopefully a correct zone short name) def reloadZoneDialogCB(self, name): self.frmDialog.end() self.zone_reload_name = name self.toggleControls(1) # this is called when the user presses "l" # it disables normal controls and fires up our query form dialog def reloadZone(self): base.setBackgroundColor((0,0,0)) self.toggleControls(0) self.consoleOn() self.frmDialog = FileDialog( "Please enter the shortname of the zone you wish to load:", "Examples: qrg, blackburrow, freportn, crushbone etc.", self.reloadZoneDialogCB) self.frmDialog.activate() # relies on the main update loop to run ############################### # EXPERIMENTAL def doLogin(self): self.login_client = UDPClientStream('127.0.0.1', 5998) ##################################### # Custom methods ##################################### # What happens when a user clicks on a model def onModelClick(): # Code adapted freely from http://www.panda3d.org/forums/viewtopic.php?t=12717 global picker, selected_model namedNode, thePoint, rawNode = picker.pick() if namedNode: if "_mesh" not in namedNode.getName(): # rough test to avoid printing infos on global zone mesh (ie: "freporte_mesh") name = namedNode.getName() p = namedNode.getParent() pos = p.getPos() selected_model = namedNode print namedNode.getName() print "Collision Point: ", thePoint namedNode.ls() else: print "Clicked location point (y, x, z):", thePoint #selected_model.setPos(thePoint.getX(), thePoint.getY(), thePoint.getZ()) m.setPos(thePoint.getX(), thePoint.getY(), thePoint.getZ()) print "Moved !" # Handles populating the zone with spawn data from the EQEmu DB # also makes each spawner model pickable def PopulateSpawns(self, cursor, numrows): spawn_coords = list() globals.model_list = list() for x in range(0, numrows): row = cursor.fetchone() point = Point3(long(row["Spawn2Y"]), long(row["Spawn2X"]), long(row["Spawn2Z"])) if point not in spawn_coords: s = loader.loadModel("models/cube.egg") s.reparentTo(render) s.setPos(row["Spawn2Y"], row["Spawn2X"], row["Spawn2Z"]) min,macks= s.getTightBounds() radius = max([macks.getY() - min.getY(), macks.getX() - min.getX()])/2 cs = CollisionSphere(row["Spawn2X"], row["Spawn2Y"], row["Spawn2Z"], radius) csNode = s.attachNewNode(CollisionNode("modelCollide")) csNode.node().addSolid(cs) s.setTag("name", row["name"]) picker.makePickable(s) globals.model_list.append(s) spawn_coords.append(point) # Establishes a connection to the EQEmu database def ConnectToDatabase(self): configurator = Configurator(world) cfg = configurator.config conn = MySQLdb.Connection( host=cfg['host'], user=cfg['user'], passwd=cfg['password'], db=cfg['db']) return conn # Queries the Database in order to get spawn data # (this should be refactored at some point) def GetDbSpawnData(self, connection): cursor = connection.cursor(MySQLdb.cursors.DictCursor) query = """SELECT nt.name, s2.zone, s2.x as Spawn2X, s2.y as Spawn2Y, s2.z as Spawn2Z, sg.name as spawngroup_name,sg.id as Spawngroup_id, sg.min_x as Spawngroup_minX, sg.max_x as Spawngroup_maxX, sg.min_y as Spawngroup_minY, sg.max_y as Spawngroup_maxY, sg.dist as Spawngroup_dist, sg.mindelay as Spawngroup_mindelay, sg.delay as Spawngroup_delay FROM spawn2 s2 JOIN spawngroup sg ON sg.id = s2.spawngroupid JOIN spawnentry se ON se.spawngroupid = sg.id JOIN npc_types nt ON nt.id = se.npcid WHERE s2.zone = 'freporte'""" cursor.execute(query) return cursor # Initializes the camera position upon startup def InitCameraPosition(self): world.campos = Point3(-155.6, 41.2, 4.9 + world.eyeHeight) world.camHeading = 270.0 base.camera.setPos(world.campos) def GetCamera(self): return base.camera
class DynObject(): def __init__(self, render, objid, start_pos, gameclient): self.client = gameclient self.id = objid self.motion_controller = None self.is_player = False # state management self.isAnimating = False self.state = state.IDLE self.render = render # scene graph root # create the panda3d actor: just load a default model for now self.actor = Actor("models/ralph", { "run": "models/ralph-run", "walk": "models/ralph-walk" }) self.actor.reparentTo(render) self.actor.setScale(.2) self.actor.setPos(start_pos) # prepare collision handling self.cTrav = CollisionTraverser() self.GroundRay = CollisionRay() self.GroundRay.setOrigin(0, 0, 1000) self.GroundRay.setDirection(0, 0, -1) self.GroundCol = CollisionNode('actorRay') self.GroundCol.addSolid(self.GroundRay) self.GroundCol.setFromCollideMask(BitMask32.bit(0)) self.GroundCol.setIntoCollideMask(BitMask32.allOff()) self.GroundColNp = self.actor.attachNewNode(self.GroundCol) self.GroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.GroundColNp, self.GroundHandler) def destroy(self): if self.actor != None: self.actor.cleanup() self.actor.removeNode() self.actor = None # called reqularly from a Panda3 task # move the object according to its current state def move(self): actor = self.actor # save our initial position so that we can restore it, # in case we fall off the map or run into something. startpos = actor.getPos() # let the motion_controller determine our new state self.motion_controller.processMove() # evaluate state and move/rotate the actor accordingly if (self.state & state.LEFT): actor.setH(actor.getH() + 300 * globalClock.getDt()) if (self.state & state.RIGHT): actor.setH(actor.getH() - 300 * globalClock.getDt()) if (self.state & state.FORWARD): actor.setY(actor, -25 * globalClock.getDt()) # Simplistic animation control: # If we are moving, loop the run animation. # If we are standing still, stop the animation. if (self.state != state.IDLE): if self.isAnimating is False: actor.loop("run") self.isAnimating = True else: if self.isAnimating: actor.stop() actor.pose("walk", 5) self.isAnimating = False # Now check for collisions. self.cTrav.traverse(render) # Adjust Z coordinate. If the ray hit terrain, # update Z. If it hit anything else, or didn't hit anything, put # us back where we were last frame. entries = [] for i in range(self.GroundHandler.getNumEntries()): entry = self.GroundHandler.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.actor.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.actor.setPos(startpos) # if this is the player avatar: make the camera follow us if self.is_player is True: self.client.world.moveCamera() # convenience getter/setters def setPos(self, pos): self.actor.setPos(pos) def getPos(self): return self.actor.getPos() def getH(self): return self.actor.getH() def getX(self): return self.actor.getX() def getY(self): return self.actor.getY() def getZ(self): return self.actor.getZ()
class DistributedElevator(DistributedObject): notify = directNotify.newCategory('DistributedElevator') def __init__(self, cr): DistributedObject.__init__(self, cr) self.openSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_open.ogg') self.closeSfx = base.loadSfx( 'phase_5/audio/sfx/elevator_door_close.ogg') self.elevatorPoints = ElevatorPoints self.type = ELEVATOR_NORMAL self.countdownTime = ElevatorData[self.type]['countdown'] self.localAvOnElevator = False self.thebldg = None self.bldgDoId = None self.toZoneId = None self.elevatorModel = None self.countdownTextNP = None self.toonsInElevator = [] self.hopOffButton = None self.fsm = ClassicFSM.ClassicFSM('DistributedElevator', [ State.State('off', self.enterOff, self.exitOff), State.State('opening', self.enterOpening, self.exitOpening), State.State('waitEmpty', self.enterWaitEmpty, self.exitWaitEmpty), State.State('waitCountdown', self.enterWaitCountdown, self.exitWaitCountdown), State.State('closing', self.enterClosing, self.exitClosing), State.State('closed', self.enterClosed, self.exitClosed) ], 'off', 'off') self.fsm.enterInitialState() def setElevatorType(self, etype): self.type = etype def getElevatorType(self): return self.type def setBldgDoId(self, doId): self.bldgDoId = doId def getBldgDoId(self): return self.bldgDoId def setToZoneId(self, zoneId): self.toZoneId = zoneId def getToZoneId(self): return self.toZoneId def enterOpening(self, ts=0): self.openDoors.start(ts) def exitOpening(self): self.openDoors.finish() def enterClosing(self, ts=0): if self.localAvOnElevator: self.hideHopOffButton() self.closeDoors.start(ts) def exitClosing(self): self.closeDoors.finish() def enterClosed(self, ts=0): closeDoors(self.getLeftDoor(), self.getRightDoor()) def exitClosed(self): pass def __handleElevatorTrigger(self, entry): if not self.localAvOnElevator: self.cr.playGame.getPlace().fsm.request('stop') self.sendUpdate('requestEnter') def enterWaitEmpty(self, ts=0): if not self.localAvOnElevator: self.acceptOnce('enter' + self.uniqueName('elevatorSphere'), self.__handleElevatorTrigger) openDoors(self.getLeftDoor(), self.getRightDoor()) def exitWaitEmpty(self): self.ignore('enter' + self.uniqueName('elevatorSphere')) def enterWaitCountdown(self, ts=0): if not self.localAvOnElevator: self.acceptOnce('enter' + self.uniqueName('elevatorSphere'), self.__handleElevatorTrigger) openDoors(self.getLeftDoor(), self.getRightDoor()) if self.countdownTextNP: self.countdownTextNP.show() self.countdownTrack = Sequence() time = int(ElevatorData[self.type]['countdown']) for i in range(time): self.countdownTrack.append( Func(self.countdownTextNP.node().setText, str(time - i))) self.countdownTrack.append(Wait(1.0)) self.countdownTrack.start(ts) def exitWaitCountdown(self): if self.countdownTextNP: self.countdownTextNP.hide() self.countdownTrack.finish() del self.countdownTrack def enterOff(self): pass def exitOff(self): pass def getLeftDoor(self): # Can be overridden by inheritors. return self.thebldg.leftDoor def getRightDoor(self): return self.thebldg.rightDoor def startPoll(self): # Start polling for the building taskMgr.add(self.__pollBuilding, self.uniqueName('pollBuilding')) def __pollBuilding(self, task): self.getTheBldg() if self.thebldg: self.postAnnounceGenerate() return task.done return task.cont def stopPoll(self): taskMgr.remove(self.uniqueName('pollBuilding')) def announceGenerate(self): DistributedObject.announceGenerate(self) self.getTheBldg() if not self.thebldg: self.startPoll() return self.postAnnounceGenerate() def postAnnounceGenerate(self): self.leftDoor = self.getLeftDoor() self.rightDoor = self.getRightDoor() self.setupElevator() self.setupCountdownText() self.sendUpdate('requestStateAndTimestamp') def setState(self, state, timestamp): if not self.thebldg: return self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def stateAndTimestamp(self, state, timestamp): self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def setupCountdownText(self): tn = TextNode('countdownText') tn.setFont(CIGlobals.getMickeyFont()) tn.setTextColor(VBase4(0.5, 0.5, 0.5, 1.0)) tn.setAlign(TextNode.ACenter) self.countdownTextNP = self.getElevatorModel().attachNewNode(tn) self.countdownTextNP.setScale(2) self.countdownTextNP.setPos(0, 1, 7) #self.countdownTextNP.setH(180) def setupElevator(self): collisionRadius = ElevatorData[self.type]['collRadius'] self.elevatorSphere = CollisionSphere(0, 5, 0, collisionRadius) self.elevatorSphere.setTangible(0) self.elevatorSphereNode = CollisionNode( self.uniqueName('elevatorSphere')) self.elevatorSphereNode.setIntoCollideMask(CIGlobals.WallBitmask) self.elevatorSphereNode.addSolid(self.elevatorSphere) self.elevatorSphereNodePath = self.getElevatorModel().attachNewNode( self.elevatorSphereNode) self.elevatorSphereNodePath.reparentTo(self.getElevatorModel()) self.openDoors = getOpenInterval(self, self.getLeftDoor(), self.getRightDoor(), self.openSfx, None, self.type) self.closeDoors = getCloseInterval(self, self.getLeftDoor(), self.getRightDoor(), self.closeSfx, None, self.type) self.closeDoors = Sequence(self.closeDoors, Func(self.onDoorCloseFinish)) def disable(self): self.stopPoll() if hasattr(self, 'openDoors'): self.openDoors.pause() if hasattr(self, 'closeDoors'): self.closeDoors.pause() self.ignore('enter' + self.uniqueName('elevatorSphere')) self.elevatorSphereNodePath.removeNode() del self.elevatorSphereNodePath del self.elevatorSphereNode del self.elevatorSphere self.fsm.request('off') self.openSfx = None self.closeSfx = None self.elevatorPoints = None self.type = None self.countdownTime = None self.localAvOnElevator = None self.thebldg = None self.bldgDoId = None self.toZoneId = None self.elevatorModel = None self.toonsInElevator = None self.hopOffButton = None self.leftDoor = None self.rightDoor = None self.openDoors = None self.closeDoors = None if self.countdownTextNP: self.countdownTextNP.removeNode() self.countdownTextNP = None DistributedObject.disable(self) def onDoorCloseFinish(self): if self.localAvOnElevator: base.transitions.fadeScreen(1.0) base.localAvatar.wrtReparentTo(render) loader = 'suitInterior' where = 'suitInterior' how = 'IDK' world = base.cr.playGame.getCurrentWorldName() if self.thebldg.fsm.getCurrentState().getName() == 'bldgComplete': loader = 'townLoader' where = 'street' how = 'elevatorIn' world = CIGlobals.CogTropolis requestStatus = { 'zoneId': self.getToZoneId(), 'hoodId': self.cr.playGame.hood.hoodId, 'where': where, 'avId': base.localAvatar.doId, 'loader': loader, 'shardId': None, 'wantLaffMeter': 1, 'world': world, 'how': how } self.cr.playGame.getPlace().doneStatus = requestStatus messenger.send(self.cr.playGame.getPlace().doneEvent) def doMusic(self): self.elevMusic = base.loadMusic('phase_7/audio/bgm/tt_elevator.ogg') base.playMusic(self.elevMusic, looping=1, volume=0.8) def fillSlot(self, index, avId): toon = self.cr.doId2do.get(avId) if toon: point = ElevatorPoints[index] toon.stopSmooth() toon.wrtReparentTo(self.getElevatorModel()) toon.headsUp(point) track = Sequence() track.append(Func(toon.animFSM.request, 'run')) track.append( LerpPosInterval(toon, duration=0.5, pos=point, startPos=toon.getPos(self.getElevatorModel()))) track.append( LerpHprInterval(toon, duration=0.1, hpr=(180, 0, 0), startHpr=toon.getHpr(self.getElevatorModel()))) track.append(Func(toon.animFSM.request, 'neutral')) if avId == base.localAvatar.doId: self.localAvOnElevator = True track.append(Func(self.showHopOffButton)) base.localAvatar.stopSmartCamera() base.localAvatar.walkControls.setCollisionsActive(0) base.camera.wrtReparentTo(self.getElevatorModel()) cameraBoardTrack = LerpPosHprInterval(camera, 1.5, Point3(0, -16, 5.5), Point3(0, 0, 0)) cameraBoardTrack.start() track.start() def emptySlot(self, index, avId): toon = self.cr.doId2do.get(avId) if toon: OutPoint = ElevatorOutPoints[index] InPoint = ElevatorPoints[index] toon.stopSmooth() toon.headsUp(OutPoint) track = Sequence( Func(toon.animFSM.request, 'run'), LerpPosInterval(toon, duration=0.5, pos=OutPoint, startPos=InPoint), Func(toon.animFSM.request, 'neutral'), Func(toon.startSmooth)) if avId == base.localAvatar.doId: self.localAvOnElevator = False track.append(Func(self.freedom)) track.start() def freedom(self): if self.fsm.getCurrentState().getName() in [ 'waitEmpty', 'waitCountdown' ]: self.acceptOnce('enter' + self.uniqueName('elevatorSphere'), self.__handleElevatorTrigger) base.localAvatar.walkControls.setCollisionsActive(1) self.cr.playGame.getPlace().fsm.request('walk') def setToonsInElevator(self, toonsInElevator): for i in xrange(len(toonsInElevator)): avId = toonsInElevator[i] toon = self.cr.doId2do.get(avId) if toon: toon.reparentTo(self.getElevatorModel()) toon.stopSmooth() point = ElevatorPoints[i] toon.setPos(point) toon.setHpr(180, 0, 0) toon.animFSM.request('neutral') def getTheBldg(self): self.thebldg = self.cr.doId2do.get(self.bldgDoId) def getElevatorModel(self): return self.thebldg.getElevatorModel() def enterRejected(self): self.cr.playGame.getPlace().fsm.request('walk') def showHopOffButton(self): gui = loader.loadModel('phase_3.5/models/gui/inventory_gui.bam') upButton = gui.find('**/InventoryButtonUp') downButton = gui.find('**/InventoryButtonDown') rlvrButton = gui.find('**/InventoryButtonRollover') self.hopOffBtn = DirectButton(relief=None, text="Hop off", text_fg=(0.9, 0.9, 0.9, 1), text_pos=(0, -0.23), text_scale=0.75, image=(upButton, downButton, rlvrButton), image_color=(0.5, 0.5, 0.5, 1), image_scale=(20, 1, 11), pos=(0, 0, 0.8), scale=0.15, command=self.handleHopOffButton) def hideHopOffButton(self): if hasattr(self, 'hopOffBtn'): self.hopOffBtn.destroy() del self.hopOffBtn def handleHopOffButton(self): self.hideHopOffButton() self.sendUpdate('requestExit')
def __init__(self): GameObject.__init__( self, Vec3(0, 0, 0), "Models/PandaChan/act_p3d_chan", { "stand": "Models/PandaChan/a_p3d_chan_idle", "walk": "Models/PandaChan/a_p3d_chan_run" }, 5, 10, "player") self.actor.getChild(0).setH(180) mask = BitMask32() mask.setBit(1) self.collider.node().setIntoCollideMask(mask) mask = BitMask32() mask.setBit(1) self.collider.node().setFromCollideMask(mask) base.pusher.addCollider(self.collider, self.actor) base.cTrav.addCollider(self.collider, base.pusher) self.lastMousePos = Vec2(0, 0) self.groundPlane = Plane(Vec3(0, 0, 1), Vec3(0, 0, 0)) self.ray = CollisionRay(0, 0, 0, 0, 1, 0) rayNode = CollisionNode("playerRay") rayNode.addSolid(self.ray) mask = BitMask32() mask.setBit(2) rayNode.setFromCollideMask(mask) mask = BitMask32() rayNode.setIntoCollideMask(mask) self.rayNodePath = render.attachNewNode(rayNode) self.rayQueue = CollisionHandlerQueue() base.cTrav.addCollider(self.rayNodePath, self.rayQueue) self.beamModel = loader.loadModel("Models/Misc/bambooLaser") self.beamModel.reparentTo(self.actor) self.beamModel.setZ(1.5) self.beamModel.setLightOff() self.beamModel.hide() self.beamHitModel = loader.loadModel("Models/Misc/bambooLaserHit") self.beamHitModel.reparentTo(render) self.beamHitModel.setZ(1.5) self.beamHitModel.setLightOff() self.beamHitModel.hide() self.beamHitPulseRate = 0.15 self.beamHitTimer = 0 self.damagePerSecond = -5.0 self.score = 0 self.scoreUI = OnscreenText(text="0", pos=(-1.3, 0.825), mayChange=True, align=TextNode.ALeft) self.healthIcons = [] for i in range(self.maxHealth): icon = OnscreenImage(image="UI/health.png", pos=(-1.275 + i * 0.075, 0, 0.95), scale=0.04) icon.setTransparency(True) self.healthIcons.append(icon) self.damageTakenModel = loader.loadModel("Models/Misc/playerHit") self.damageTakenModel.setLightOff() self.damageTakenModel.setZ(1.0) self.damageTakenModel.reparentTo(self.actor) self.damageTakenModel.hide() self.damageTakenModelTimer = 0 self.damageTakenModelDuration = 0.15 self.beamHitLight = PointLight("beamHitLight") self.beamHitLight.setColor(Vec4(0.1, 1.0, 0.2, 1)) self.beamHitLight.setAttenuation((1.0, 0.1, 0.5)) self.beamHitLightNodePath = render.attachNewNode(self.beamHitLight) self.yVector = Vec2(0, 1) self.actor.loop("stand")
def makePropAttackTrack(self): prop = BattleProps.globalPropPool.getProp(self.attackProp) propIsActor = True animName = 'throw-paper' x, y, z, h, p, r = (0.1, 0.2, -0.35, 0, 336, 0) if self.attackProp == 'redtape': animName = 'throw-object' x, y, z, h, p, r = (0.24, 0.09, -0.38, -1.152, 86.581, -76.784) propIsActor = False elif self.attackProp == 'newspaper': animName = 'throw-object' propIsActor = False x, y, z, h, p, r = (-0.07, 0.17, -0.13, 161.867, -33.149, -48.086) prop.setScale(4) elif self.attackProp == 'pink-slip': animName = 'throw-paper' propIsActor = False x, y, z, h, p, r = (0.07, -0.06, -0.18, -172.075, -26.715, -89.131) prop.setScale(5) elif self.attackProp == 'power-tie': animName = 'throw-paper' propIsActor = False x, y, z, h, p, r = (1.16, 0.24, 0.63, 171.561, 1.745, -163.443) prop.setScale(4) elif self.attackProp == 'baseball': animName = 'throw-object' propIsActor = False x, y, z, h, p, r = (0.04, 0.03, -0.31, 0, 336, 0) prop.setScale(4) elif self.attackProp == 'teeth': animName = 'throw-object' propIsActor = True x, y, z, h, p, r = -0.05, 0.41, -0.54, 4.465, -3.563, 51.479 prop.setScale(3) elif self.attackProp == 'golf-ball': propIsActor = False x, y, z = self.getGolfStartPoint() h, p, r = 0, 0, 0 prop.setScale(1.5) # Make prop virtual: prop.setColorScale(1.0, 0.0, 0.0, 0.8) prop.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd)) # Prop collisions: colNode = CollisionNode(self.uniqueName('SuitAttack')) colNode.setTag('damage', str(self.attackInfo[1])) bounds = prop.getBounds() center = bounds.getCenter() radius = bounds.getRadius() sphere = CollisionSphere(center.getX(), center.getY(), center.getZ(), radius) sphere.setTangible(0) colNode.addSolid(sphere) colNode.setIntoCollideMask(WallBitmask) prop.attachNewNode(colNode) toonId = self.toon toon = base.cr.doId2do.get(toonId) if not toon: return self.virtualSuit.lookAt(toon) if self.virtualSuit.style.body in ['a', 'b']: throwDelay = 3 elif self.virtualSuit.style.body == 'c': throwDelay = 2.3 else: throwDelay = 2 def throwProp(): if not self.virtualSuit: return toon = self.cr.doId2do.get(toonId) if not toon: self.cleanupProp(prop, propIsActor) self.finishPropAttack() return self.virtualSuit.lookAt(toon) prop.wrtReparentTo(render) hitPos = toon.getPos() + Vec3(0, 0, 2.5) distance = (prop.getPos() - hitPos).length() speed = 50.0 if self.attackProp == 'golf-ball': speed *= 2 if self.attackProp == 'teeth': throwSequence = Sequence( Parallel( prop.posInterval(distance / speed, hitPos), ActorInterval(prop, 'teeth', duration=distance / speed), ), Func(self.cleanupProp, prop, propIsActor), ) else: throwSequence = Sequence( prop.posInterval(distance / speed, hitPos), Func(self.cleanupProp, prop, propIsActor)) throwSequence.start() if self.attackProp == 'golf-ball': club = BattleProps.globalPropPool.getProp('golf-club') club.setScale(1.1) track = Sequence( Parallel( Track( (0.4, Func(club.reparentTo, self.virtualSuit.getRightHand())), (0.0, Func(club.setPosHpr, 0.0, 0.0, 0.0, 63.097, 43.988, -18.435)), (0.0, Func(prop.reparentTo, self.virtualSuit)), (0.0, Func(prop.setPosHpr, x, y, z, h, p, r)), (0.0, Func(self.sayFaceoffTaunt)), (0.1, Sequence( ActorInterval(self.virtualSuit, 'golf-club-swing'), Func(self.virtualSuit.loop, 'neutral', 0))), (4.1, SoundInterval(self.teeOffSfx, node=self.virtualSuit)), (throwDelay + 1.5, Func(throwProp)), (throwDelay + 2, Func(club.removeNode)), (throwDelay + 3, Func(self.finishPropAttack))), ), Func(self.virtualSuit.setHpr, 0, 0, 0), Func(self.virtualSuit.loop, 'walk', 0), ) else: track = Sequence( Parallel( Sequence(ActorInterval(self.virtualSuit, animName), Func(self.virtualSuit.loop, 'neutral', 0)), Track((0.4, Func(prop.reparentTo, self.virtualSuit.getRightHand())), (0.0, Func(prop.setPosHpr, x, y, z, h, p, r)), (0.0, Func(self.sayFaceoffTaunt)), (throwDelay, Func(throwProp)), (throwDelay + 2, Func(self.finishPropAttack))), ), Func(self.virtualSuit.setHpr, 0, 0, 0), Func(self.virtualSuit.loop, 'walk', 0), ) track.prop = prop track.propIsActor = propIsActor return track
class DistributedCogKart(DistributedElevatorExt.DistributedElevatorExt): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedCogKart') JumpOutOffsets = ((6.5, -2, -0.025), (-6.5, -2, -0.025), (3.75, 5, -0.025), (-3.75, 5, -0.025)) def __init__(self, cr): DistributedElevatorExt.DistributedElevatorExt.__init__(self, cr) self.type = ElevatorConstants.ELEVATOR_COUNTRY_CLUB self.kartModelPath = 'phase_12/models/bossbotHQ/Coggolf_cart3.bam' self.leftDoor = None self.rightDoor = None self.fillSlotTrack = None return def generate(self): DistributedElevatorExt.DistributedElevatorExt.generate(self) self.loader = self.cr.playGame.hood.loader if self.loader: self.notify.debug('Loader has been loaded') self.notify.debug(str(self.loader)) else: self.notify.debug('Loader has not been loaded') self.golfKart = render.attachNewNode('golfKartNode') self.kart = loader.loadModel(self.kartModelPath) self.kart.setPos(0, 0, 0) self.kart.setScale(1) self.kart.reparentTo(self.golfKart) self.golfKart.reparentTo(self.loader.geom) self.wheels = self.kart.findAllMatches('**/wheelNode*') self.numWheels = self.wheels.getNumPaths() def announceGenerate(self): DistributedElevatorExt.DistributedElevatorExt.announceGenerate(self) angle = self.startingHpr[0] angle -= 90 radAngle = deg2Rad(angle) unitVec = Vec3(math.cos(radAngle), math.sin(radAngle), 0) unitVec *= 45.0 self.endPos = self.startingPos + unitVec self.endPos.setZ(0.5) dist = Vec3(self.endPos - self.enteringPos).length() wheelAngle = dist / (4.8 * 1.4 * math.pi) * 360 self.kartEnterAnimateInterval = Parallel( LerpHprInterval( self.wheels[0], 5.0, Vec3(self.wheels[0].getH(), wheelAngle, self.wheels[0].getR())), LerpHprInterval( self.wheels[1], 5.0, Vec3(self.wheels[1].getH(), wheelAngle, self.wheels[1].getR())), LerpHprInterval( self.wheels[2], 5.0, Vec3(self.wheels[2].getH(), wheelAngle, self.wheels[2].getR())), LerpHprInterval( self.wheels[3], 5.0, Vec3(self.wheels[3].getH(), wheelAngle, self.wheels[3].getR())), name='CogKartAnimate') trolleyExitTrack1 = Parallel(LerpPosInterval(self.golfKart, 5.0, self.endPos), self.kartEnterAnimateInterval, name='CogKartExitTrack') self.trolleyExitTrack = Sequence(trolleyExitTrack1) self.trolleyEnterTrack = Sequence( LerpPosInterval(self.golfKart, 5.0, self.startingPos, startPos=self.enteringPos)) self.closeDoors = Sequence(self.trolleyExitTrack, Func(self.onDoorCloseFinish)) self.openDoors = Sequence(self.trolleyEnterTrack) def delete(self): DistributedElevatorExt.DistributedElevatorExt.delete(self) if hasattr(self, 'elevatorFSM'): del self.elevatorFSM def setBldgDoId(self, bldgDoId): self.bldg = None self.setupElevatorKart() return def setupElevatorKart(self): collisionRadius = ElevatorConstants.ElevatorData[ self.type]['collRadius'] self.elevatorSphere = CollisionSphere(0, 0, 0, collisionRadius) self.elevatorSphere.setTangible(1) self.elevatorSphereNode = CollisionNode( self.uniqueName('elevatorSphere')) self.elevatorSphereNode.setIntoCollideMask(ToontownGlobals.WallBitmask) self.elevatorSphereNode.addSolid(self.elevatorSphere) self.elevatorSphereNodePath = self.getElevatorModel().attachNewNode( self.elevatorSphereNode) self.elevatorSphereNodePath.hide() self.elevatorSphereNodePath.reparentTo(self.getElevatorModel()) self.elevatorSphereNodePath.stash() self.boardedAvIds = {} self.finishSetup() def setColor(self, r, g, b): pass def getElevatorModel(self): return self.golfKart def enterWaitEmpty(self, ts): DistributedElevatorExt.DistributedElevatorExt.enterWaitEmpty(self, ts) def exitWaitEmpty(self): DistributedElevatorExt.DistributedElevatorExt.exitWaitEmpty(self) def forceDoorsOpen(self): pass def forceDoorsClosed(self): pass def setPosHpr(self, x, y, z, h, p, r): self.startingPos = Vec3(x, y, z) self.enteringPos = Vec3(x, y, z - 10) self.startingHpr = Vec3(h, 0, 0) self.golfKart.setPosHpr(x, y, z, h, 0, 0) def enterClosing(self, ts): if self.localToonOnBoard: elevator = self.getPlaceElevator() if elevator: elevator.fsm.request('elevatorClosing') self.closeDoors.start(ts) def enterClosed(self, ts): self.forceDoorsClosed() self.kartDoorsClosed(self.getZoneId()) def kartDoorsClosed(self, zoneId): if self.localToonOnBoard: hoodId = ZoneUtil.getHoodId(zoneId) doneStatus = { 'loader': 'suitInterior', 'where': 'suitInterior', 'hoodId': hoodId, 'zoneId': zoneId, 'shardId': None } elevator = self.elevatorFSM del self.elevatorFSM elevator.signalDone(doneStatus) return def setCountryClubInteriorZone(self, zoneId): if self.localToonOnBoard: hoodId = self.cr.playGame.hood.hoodId countryClubId = self.countryClubId if bboard.has('countryClubIdOverride'): countryClubId = bboard.get('countryClubIdOverride') doneStatus = { 'loader': 'cogHQLoader', 'where': 'countryClubInterior', 'how': 'teleportIn', 'zoneId': zoneId, 'countryClubId': self.countryClubId, 'hoodId': hoodId } self.cr.playGame.getPlace().elevator.signalDone(doneStatus) def setCountryClubInteriorZoneForce(self, zoneId): place = self.cr.playGame.getPlace() if place: place.fsm.request('elevator', [self, 1]) hoodId = self.cr.playGame.hood.hoodId countryClubId = self.countryClubId if bboard.has('countryClubIdOverride'): countryClubId = bboard.get('countryClubIdOverride') doneStatus = { 'loader': 'cogHQLoader', 'where': 'countryClubInterior', 'how': 'teleportIn', 'zoneId': zoneId, 'countryClubId': self.countryClubId, 'hoodId': hoodId } if hasattr(place, 'elevator') and place.elevator: place.elevator.signalDone(doneStatus) else: self.notify.warning( "setMintInteriorZoneForce: Couldn't find playGame.getPlace().elevator, zoneId: %s" % zoneId) else: self.notify.warning( "setCountryClubInteriorZoneForce: Couldn't find playGame.getPlace(), zoneId: %s" % zoneId) def setCountryClubId(self, countryClubId): self.countryClubId = countryClubId def getZoneId(self): return 0 def fillSlot(self, index, avId, wantBoardingShow=0): self.notify.debug('%s.fillSlot(%s, %s, ... %s)' % (self.doId, index, avId, globalClock.getRealTime())) request = self.toonRequests.get(index) if request: self.cr.relatedObjectMgr.abortRequest(request) del self.toonRequests[index] if avId == 0: pass elif avId not in self.cr.doId2do: func = PythonUtil.Functor(self.gotToon, index, avId) self.toonRequests[index] = self.cr.relatedObjectMgr.requestObjects( [avId], allCallback=func) elif not self.isSetup: self.deferredSlots.append((index, avId, wantBoardingShow)) else: if avId == base.localAvatar.getDoId(): place = base.cr.playGame.getPlace() if not place: return elevator = self.getPlaceElevator() if elevator == None: place.fsm.request('elevator') elevator = self.getPlaceElevator() if not elevator: return self.localToonOnBoard = 1 if hasattr(localAvatar, 'boardingParty') and localAvatar.boardingParty: localAvatar.boardingParty.forceCleanupInviteePanel() localAvatar.boardingParty.forceCleanupInviterPanels() if hasattr(base.localAvatar, 'elevatorNotifier'): base.localAvatar.elevatorNotifier.cleanup() cameraTrack = Sequence() cameraTrack.append( Func(elevator.fsm.request, 'boarding', [self.getElevatorModel()])) cameraTrack.append(Func(elevator.fsm.request, 'boarded')) toon = self.cr.doId2do[avId] toon.stopSmooth() toon.wrtReparentTo(self.golfKart) sitStartDuration = toon.getDuration('sit-start') jumpTrack = self.generateToonJumpTrack(toon, index) track = Sequence(jumpTrack, Func(toon.setAnimState, 'Sit', 1.0), Func(self.clearToonTrack, avId), name=toon.uniqueName('fillElevator'), autoPause=1) if wantBoardingShow: boardingTrack, boardingTrackType = self.getBoardingTrack( toon, index, True) track = Sequence(boardingTrack, track) if avId == base.localAvatar.getDoId(): cameraWaitTime = 2.5 if boardingTrackType == BoardingGroupShow.TRACK_TYPE_RUN: cameraWaitTime = 0.5 cameraTrack = Sequence(Wait(cameraWaitTime), cameraTrack) if self.canHideBoardingQuitBtn(avId): track = Sequence( Func(localAvatar.boardingParty.groupPanel.disableQuitButton ), track) if avId == base.localAvatar.getDoId(): track = Parallel(cameraTrack, track) track.delayDelete = DelayDelete.DelayDelete( toon, 'CogKart.fillSlot') self.storeToonTrack(avId, track) track.start() self.fillSlotTrack = track self.boardedAvIds[avId] = None return def generateToonJumpTrack(self, av, seatIndex): av.pose('sit', 47) hipOffset = av.getHipsParts()[2].getPos(av) def getToonJumpTrack(av, seatIndex): def getJumpDest(av=av, node=self.golfKart): dest = Point3(0, 0, 0) if hasattr(self, 'golfKart') and self.golfKart: dest = Vec3(self.golfKart.getPos(av.getParent())) seatNode = self.golfKart.find('**/seat' + str(seatIndex + 1)) dest += seatNode.getPos(self.golfKart) dna = av.getStyle() dest -= hipOffset if seatIndex < 2: dest.setY(dest.getY() + 2 * hipOffset.getY()) dest.setZ(dest.getZ() + 0.1) else: self.notify.warning( 'getJumpDestinvalid golfKart, returning (0,0,0)') return dest def getJumpHpr(av=av, node=self.golfKart): hpr = Point3(0, 0, 0) if hasattr(self, 'golfKart') and self.golfKart: hpr = self.golfKart.getHpr(av.getParent()) if seatIndex < 2: hpr.setX(hpr.getX() + 180) else: hpr.setX(hpr.getX()) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) else: self.notify.warning( 'getJumpHpr invalid golfKart, returning (0,0,0)') return hpr toonJumpTrack = Parallel( ActorInterval(av, 'jump'), Sequence( Wait(0.43), Parallel( LerpHprInterval(av, hpr=getJumpHpr, duration=0.9), ProjectileInterval(av, endPos=getJumpDest, duration=0.9)))) return toonJumpTrack def getToonSitTrack(av): toonSitTrack = Sequence(ActorInterval(av, 'sit-start'), Func(av.loop, 'sit')) return toonSitTrack toonJumpTrack = getToonJumpTrack(av, seatIndex) toonSitTrack = getToonSitTrack(av) jumpTrack = Sequence( Parallel(toonJumpTrack, Sequence(Wait(1), toonSitTrack))) return jumpTrack def emptySlot(self, index, avId, bailFlag, timestamp, timeSent=0): if self.fillSlotTrack: self.fillSlotTrack.finish() self.fillSlotTrack = None if avId == 0: pass elif not self.isSetup: newSlots = [] for slot in self.deferredSlots: if slot[0] != index: newSlots.append(slot) self.deferredSlots = newSlots elif avId in self.cr.doId2do: if bailFlag == 1 and hasattr(self, 'clockNode'): if timestamp < self.countdownTime and timestamp >= 0: self.countdown(self.countdownTime - timestamp) else: self.countdown(self.countdownTime) toon = self.cr.doId2do[avId] toon.stopSmooth() sitStartDuration = toon.getDuration('sit-start') jumpOutTrack = self.generateToonReverseJumpTrack(toon, index) track = Sequence(jumpOutTrack, Func(self.notifyToonOffElevator, toon), Func(self.clearToonTrack, avId), name=toon.uniqueName('emptyElevator'), autoPause=1) if self.canHideBoardingQuitBtn(avId): track.append( Func( localAvatar.boardingParty.groupPanel.enableQuitButton)) track.append(Func(localAvatar.boardingParty.enableGoButton)) track.delayDelete = DelayDelete.DelayDelete( toon, 'CogKart.emptySlot') self.storeToonTrack(toon.doId, track) track.start() if avId == base.localAvatar.getDoId(): messenger.send('exitElevator') if avId in self.boardedAvIds: del self.boardedAvIds[avId] else: self.notify.warning('toon: ' + str(avId) + " doesn't exist, and" + ' cannot exit the elevator!') return def generateToonReverseJumpTrack(self, av, seatIndex): self.notify.debug('av.getH() = %s' % av.getH()) def getToonJumpTrack(av, destNode): def getJumpDest(av=av, node=destNode): dest = node.getPos(av.getParent()) dest += Vec3(*self.JumpOutOffsets[seatIndex]) return dest def getJumpHpr(av=av, node=destNode): hpr = node.getHpr(av.getParent()) hpr.setX(hpr.getX() + 180) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) return hpr toonJumpTrack = Parallel( ActorInterval(av, 'jump'), Sequence( Wait(0.1), Parallel( ProjectileInterval(av, endPos=getJumpDest, duration=0.9)))) return toonJumpTrack toonJumpTrack = getToonJumpTrack(av, self.golfKart) jumpTrack = Sequence(toonJumpTrack, Func(av.loop, 'neutral'), Func(av.wrtReparentTo, render)) return jumpTrack def startCountdownClock(self, countdownTime, ts): DistributedElevatorExt.DistributedElevatorExt.startCountdownClock( self, countdownTime, ts) self.clock.setH(self.clock.getH() + 180) def rejectBoard(self, avId, reason=0): print('rejectBoard %s' % reason) if hasattr(base.localAvatar, 'elevatorNotifier'): if reason == ElevatorConstants.REJECT_SHUFFLE: base.localAvatar.elevatorNotifier.showMe( TTLocalizer.ElevatorHoppedOff) elif reason == ElevatorConstants.REJECT_MINLAFF: base.localAvatar.elevatorNotifier.showMe( TTLocalizer.KartMinLaff % self.minLaff) elif reason == ElevatorConstants.REJECT_PROMOTION: base.localAvatar.elevatorNotifier.showMe( TTLocalizer.BossElevatorRejectMessage) elif reason == ElevatorConstants.REJECT_NOT_YET_AVAILABLE: base.localAvatar.elevatorNotifier.showMe( TTLocalizer.NotYetAvailable) doneStatus = {'where': 'reject'} elevator = self.getPlaceElevator() if elevator: elevator.signalDone(doneStatus) def getDestName(self): if self.countryClubId == ToontownGlobals.BossbotCountryClubIntA: return TTLocalizer.ElevatorBossBotCourse0 elif self.countryClubId == ToontownGlobals.BossbotCountryClubIntB: return TTLocalizer.ElevatorBossBotCourse1 elif self.countryClubId == ToontownGlobals.BossbotCountryClubIntC: return TTLocalizer.ElevatorBossBotCourse2
class entity(Actor): ''' Base class for any characters Contains methods for movement, collision, model loading ''' #procedure class constructor # NodePath model, ShowBase caller, tuple Pos -> class construction def __init__(self, model: str, base: ShowBase, pos: tuple, physics=True): ''' constructor for entity. attaches model to calling instance renderer also stores size definitions and creates basic collision object ''' Actor.__init__(self) DEFAULT_HEALTH = 50 #reference base for later self.base = base # set health self.health = DEFAULT_HEALTH self.damagedSound = base.loader.loadSfx("sounds/oof.ogg") # speed self.speed = 10 self.turnSpeed = 5 # gravity -- is touching ground? self.isGrounded = False # creates actor object using constructor and parents to passed renderer self.loadModel(model) self.renderer = base.render self.reparentTo(self.renderer) # put at specified location self.setPos(pos) # store dimensions for later # https://discourse.panda3d.org/t/getting-the-height-width-and-length-of-models-solved/6504 # Post describes the output of the Nodepath class's getTightBounds() method. Using this # I am able to get an approximation of the dimensions of an object in the global coordinate space minimum, maximum = self.getTightBounds() # make sure all numbers are positive for best (any) results self.bounds = [abs(num) for num in (minimum - maximum)] self.width, self.length, self.height = self.bounds[0], self.bounds[ 1], self.bounds[2] # COLLISION PROPERTIES # create collision ray that is height of model pointing down (will detect ground collisions) if physics: self.groundRay = CollisionRay() self.groundRay.setOrigin(0, 0, 1000) self.groundRay.setDirection(0, 0, -1) self.groundCol = CollisionNode('groundRay') self.groundCol.addSolid(self.groundRay) self.groundCol.setFromCollideMask(BitMask32.bit(0)) self.groundCol.setIntoCollideMask(BitMask32.allOff()) self.groundColNode = self.attachNewNode(self.groundCol) base.cTrav.addCollider(self.groundColNode, base.groundHandler) #and another one for everything else self.mainCol = CollisionNode('actorCollision' + str(id(self))) # create collision sphere as solid for this collision node self.mainCol.addSolid( CollisionSphere(0, 0, self.height / 2, self.height / 2)) # specify valid collisions for collision node self.mainCol.setFromCollideMask(CollideMask.bit(0)) self.mainCol.setIntoCollideMask(CollideMask.bit( 1)) # accepts incoming objects with collideMask bit(1) # attach collision node to actor self.cNode = self.attachNewNode(self.mainCol) # show #self.cNode.show() # make instance collision traverser aware of this collision node, tell it how to handle (with pusher) base.cTrav.addCollider(self.cNode, base.pusher) # add collision to pusher collision handler; tell pusher which node to associate with which actor IOT push base.pusher.addCollider(self.cNode, self, base.drive.node()) # add to base.entities (since all allies/enemies created through this constructor, makes sense base.entities.append(self) # add as client of entity collision handler # base.cTrav.addCollider(self.cNode,base.entityCollisionHandler) #add to cleanup for deletion later base.cleanup.append(self) #store reference to self #https://discourse.panda3d.org/t/inheriting-from-nodepath/10886/4 #post describes how to set up a reference from nodepath to itself to retrieve custom properties #I use python tags to distinguish collision volume owners self.mainCol.setPythonTag("owner", self) # TODO if no initial collision, enforce gravity until collision #taskMgr.add(self.doGravity, "entityGravity") #procedure update #do all actions that must be done for this object every frame - called from game loop def updateState(self): #by default do gravity for all entities self.doGravity() return #procedure entityGravity # drops entity by gravity if isGrounded is not true (set True by collision with ground) def doGravity(self): dt = globalClock.getDt() #gravity - if not grounded, make it so if not self.isGrounded: self.setZ(self.getZ() - 50 * dt) return else: entries = [] for entry in base.groundHandler.getEntries(): if entry.getFromNodePath().getParent() == self \ or entry.getIntoNodePath().getParent() == self: entries.append(entry) if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"): self.setZ(entries[0].getSurfacePoint(base.render).getZ() + 2) #procedure add Damage #float dmg -> decrement self.health def addDamage(self, sender, dmg): ''' Adds a specified amount to this entity Can be negative or positive If self.health < 0 call delete self ''' #get shooter for scoring purposes shooter = sender.owner # TODO make pretty death self.health -= dmg if self.damagedSound is not None: self.damagedSound.play() if self.health <= 0: #if shooter was player, add to score if shooter is base.player: if shooter.team is self.team: base.player.score -= 15 else: base.player.score += 15 #if player, end game if self is base.player: messenger.send('Leave-Game') self.kill() #procedure kill # destroys object, but fancy-like def kill(self): self.pose('death', 0) taskMgr.add(self.deleteTask, 'deleteTask') #procedure deleteTask #destroys object after five seconds of being in death state def deleteTask(self, task): if task.time < 5.0: return task.cont else: self.delete() return task.done #procedure class deconstructor def delete(self): ''' Class destructor Destroy an object cleanly from instance ''' #also remove from base.entities if self in base.entities: base.entities.remove(self) # remove pythontag from collision self.mainCol.clearPythonTag("owner") # remove collision node from global collider base.cTrav.removeCollider(self.cNode) #destroy actor if not self.is_empty(): self.hide() self.cleanup() #self.detachNode() del self #class deconstructor def __del__(self): self.removeNode()
class World(DirectObject): def freezeGame(): # Pause all of the AI, stop model animations, cease taking inputs, except for reset return 0 def resetGame(self): # Set everything back to its starting position and remove the game over message self.caught.destroy() self.pieDisplay.destroy() self.pieCount = 0 self.pieDisplay = grabPie(self.pieCount) self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0, "run":0, "reset":0} eveStartPos = self.environ.find("**/start_point").getPos() self.gameOver = 0 self.eve.setPos(eveStartPos) self.eateve.setPos(eveStartPos) self.pie.setPos(Vec3(-50, -30, 10)) self.rand.setPos(Vec3(-70, -5, eveStartPos.getZ() + 5)) self.rand2.setPos(Vec3(-70, -5, eveStartPos.getZ() + 10)) # Blue Dragon self.character3.loop('win') self.character3.setPos(-114,11,1.9) self.blueDragonSound.play() # Red Dragon self.character2.loop('win') self.character2.setPos(-108,11,.3) self.redDragonStartPos = self.character2.getPos() self.redDragonCollideCount = 0 self.redDragonSound.play() # Green Dragon self.character.loop('win') self.character.setPos(-118,21,0) self.greenDragonSound.play() self.dragonStartPos = self.character.getPos() self.dragonCollideCount = 0 self.AIbehaviors.pursue(self.eateve, 1) self.AIbehaviorsRand.wander(10,0,47,.5) self.AIbehaviorsRand2.wander(10,0,47,.5) self.AIbehaviors3.pursue(self.rand, 1) self.redDragonChasingEve = 0 self.AIbehaviors2.pursue(self.rand2, 1) self.isMoving = False self.isRunning = False self.isWalking = False base.camera.setPos(self.eve.getX(),self.eve.getY()+10,2) self.fixPieZ() return 0 def __init__(self): # Sound self.collectSoundEffect = loader.loadMusic("sounds/item_collect.mp3") self.footstepSound = loader.loadMusic("sounds/footsteps.mp3") self.footstepSound.setLoop(1); audio3d = Audio3DManager.Audio3DManager(base.sfxManagerList[0], base.camera) self.musicend = loader.loadMusic("sounds/Enchanted-Woods.mp3") # Sky Box starTexture = loader.loadTexture("models/stars.jpg") self.sky = loader.loadModel("models/box.egg") self.sky.setScale(300) self.sky.setPos(-200,-150,0) self.sky.setBin('background', 0) self.sky.setDepthWrite(0) self.sky.setTwoSided(True) self.sky.setTexture(starTexture, 1) self.sky.reparentTo(render) self.sky.set_compass() # allow transparency render.setTransparency(TransparencyAttrib.MAlpha) self.pieCount = 0 self.pieDisplay = grabPie(self.pieCount) self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0, "run":0, "reset":0} base.win.setClearColor(Vec4(0,0,0,1)) self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) self.environ.setPos(0,0,0) # Create the main character eveStartPos = self.environ.find("**/start_point").getPos() self.eve = Actor("models/eve", {"run":"models/eve_run", "walk":"models/eve_walk"}) print(eveStartPos) self.gameOver = 0 self.eve.reparentTo(render) self.eve.setScale(.2) #self.eve.setShear(.5, .5, .5) self.eve.setPos(eveStartPos) self.eateve = Actor("models/eve") self.eateve.reparentTo(render) self.eateve.setScale(.2) self.eateve.setPos(eveStartPos) self.eateve.hide() self.pie = loader.loadModel("models/fruit-pie-slice") self.pie.reparentTo(render) self.pie.setScale(.5) self.pie.setPos(Vec3(-50, -30, 10)) #self.pie.setP(20) self.rand = Actor("models/eve") self.rand.reparentTo(render) self.rand.setScale(.2) self.rand.setPos(Vec3(-70, -5, eveStartPos.getZ() + 5)) self.rand.hide() self.rand2 = Actor("models/eve") self.rand2.reparentTo(render) self.rand2.setScale(.2) self.rand2.setPos(Vec3(-70, -5, eveStartPos.getZ() + 10)) self.rand2.hide() # print(eveStartPos) # Blue Dragon self.character3=Actor('models/nik-dragon') #self.character3.loadModel('models/nik-dragon') self.character3.reparentTo(render) self.character3.loadAnims({'win': 'models/nik-dragon'}) self.character3.loop('win') self.character3.setPlayRate(.5,'win') self.character3.setScale(.23) self.character3.setTransparency(1) #self.character3.setColorScale(0.4,0.2,.4,.7) self.character3.setColorScale(9,9,9,.3) self.character3.setPos(-114,11,1.9) self.blueDragonSound = audio3d.loadSfx("sounds/Snoring Giant.mp3") audio3d.attachSoundToObject(self.blueDragonSound, self.character3) self.blueDragonSound.setLoop(True) self.blueDragonSound.play() # Red Dragon self.character2=Actor() self.character2.loadModel('models/nik-dragon') self.character2.reparentTo(render) self.character2.loadAnims({'win': 'models/nik-dragon'}) self.character2.loop('win') self.character2.setPlayRate(1.5,'win') self.character2.setScale(.06) self.character2.setColorScale(6,0.2,0.2,50) self.character2.setPos(-108,11,.3) self.redDragonStartPos = self.character2.getPos() self.redDragonCollideCount = 0 self.redDragonSound = audio3d.loadSfx("sounds/Velociraptor Call.mp3") audio3d.attachSoundToObject(self.redDragonSound, self.character3) self.redDragonSound.setLoop(True) self.redDragonSound.play() # Green Dragon self.character=Actor() self.character.loadModel('models/nik-dragon') self.character.reparentTo(render) self.character.loadAnims({'win': 'models/nik-dragon'}) self.character.loop('win') self.character.setScale(.1) self.character.setPos(-118,21,0) self.greenDragonSound = audio3d.loadSfx("sounds/Raptor Call.mp3") audio3d.attachSoundToObject(self.greenDragonSound, self.character3) self.greenDragonSound.setLoop(True) self.greenDragonSound.play() self.dragonStartPos = self.character.getPos() self.dragonCollideCount = 0 self.AIworld = AIWorld(render) #self.AIworld.addObstacle(self.environ) self.dragonAI = AICharacter("character", self.character, 100, 0.05, 5) self.AIworld.addAiChar(self.dragonAI) self.AIbehaviors = self.dragonAI.getAiBehaviors() #self.AIbehaviors.seek(self.character2) #self.AIbehaviors.wander(2, 0, 5, .5) self.AIbehaviors.pursue(self.eateve, 1) #self.AIbehaviors.wander(5,0,10,.5) #self.AIbehaviors.evade(self.character3, 10, 20, 300) #self.AIbehaviors.seek(self.eve, .5) #self.AIbehaviors.obstacleAvoidance(1) self.randomChase = AICharacter("rand", self.rand, 50, 20, 20) self.AIworld.addAiChar(self.randomChase) self.AIbehaviorsRand = self.randomChase.getAiBehaviors() self.AIbehaviorsRand.wander(10,0,47,.5) self.randomChase2 = AICharacter("rand2", self.rand2, 50, 20, 20) self.AIworld.addAiChar(self.randomChase2) self.AIbehaviorsRand2 = self.randomChase2.getAiBehaviors() self.AIbehaviorsRand2.wander(10,0,47,.5) self.ghostDragonAI = AICharacter("character3", self.character3, 250, .05, 5) self.AIworld.addAiChar(self.ghostDragonAI) self.AIbehaviors3 = self.ghostDragonAI.getAiBehaviors() self.AIbehaviors3.pursue(self.rand, 1) #self.AIbehaviors3.wander(5,0,10,.5) self.redDragonChasingEve = 0 self.redDragonAI = AICharacter("character2", self.character2, 100, .05, 7) self.AIworld.addAiChar(self.redDragonAI) self.AIbehaviors2 = self.redDragonAI.getAiBehaviors() self.AIbehaviors2.pursue(self.rand2, 1) taskMgr.add(self.AIUpdate, "AIUpdate") # Create a floater object to use for camera management self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Enable Particles base.enableParticles() # 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("space", self.setKey, ["run",1]) self.accept("a", self.setKey, ["cam-left",1]) self.accept("s", self.setKey, ["cam-right",1]) self.accept("r", self.setKey, ["reset",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("space-up", self.setKey, ["run",0]) self.accept("a-up", self.setKey, ["cam-left",0]) self.accept("s-up", self.setKey, ["cam-right",0]) self.accept("r-up", self.setKey, ["reset",0]) taskMgr.add(self.move,"moveTask") # Game state variables self.isMoving = False self.isRunning = False self.isWalking = False # Set up the camera base.disableMouse() base.camera.setPos(self.eve.getX(),self.eve.getY()+10,2) # Collision detection for eve against the ground and against objects # 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 eve'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.eveGroundRay = CollisionRay() self.eveGroundRay.setOrigin(0,0,4.5) self.eveGroundRay.setDirection(0,0,-1) self.eveGroundCol = CollisionNode('eveRay') self.eveGroundCol.addSolid(self.eveGroundRay) self.eveGroundCol.setFromCollideMask(BitMask32.bit(0)) self.eveGroundCol.setIntoCollideMask(BitMask32.allOff()) self.eveGroundColNp = self.eve.attachNewNode(self.eveGroundCol) self.eveGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.eveGroundColNp, self.eveGroundHandler) self.dragonGroundRay = CollisionRay() self.dragonGroundRay.setOrigin(0,0,10) self.dragonGroundRay.setDirection(0,0,-1) self.dragonGroundCol = CollisionNode('dragonRay') self.dragonGroundCol.addSolid(self.dragonGroundRay) self.dragonGroundCol.setFromCollideMask(BitMask32.bit(0)) self.dragonGroundCol.setIntoCollideMask(BitMask32.allOff()) self.dragonGroundColNp = self.character.attachNewNode(self.dragonGroundCol) self.dragonGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.dragonGroundColNp, self.dragonGroundHandler) self.ghostDragonGroundRay = CollisionRay() self.ghostDragonGroundRay.setOrigin(0,0,25) self.ghostDragonGroundRay.setDirection(0,0,-1) self.ghostDragonGroundCol = CollisionNode('ghostDragonRay') self.ghostDragonGroundCol.addSolid(self.ghostDragonGroundRay) self.ghostDragonGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ghostDragonGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ghostDragonGroundColNp = self.character3.attachNewNode(self.ghostDragonGroundCol) self.ghostDragonGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ghostDragonGroundColNp, self.ghostDragonGroundHandler) self.redDragonGroundRay = CollisionRay() self.redDragonGroundRay.setOrigin(0,0,5) self.redDragonGroundRay.setDirection(0,0,-1) self.redDragonGroundCol = CollisionNode('redDragonRay') self.redDragonGroundCol.addSolid(self.redDragonGroundRay) self.redDragonGroundCol.setFromCollideMask(BitMask32.bit(0)) self.redDragonGroundCol.setIntoCollideMask(BitMask32.allOff()) self.redDragonGroundColNp = self.character2.attachNewNode(self.ghostDragonGroundCol) self.redDragonGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.redDragonGroundColNp, self.redDragonGroundHandler) self.pieRay = CollisionRay() self.pieRay.setOrigin(0,0,10) self.pieRay.setDirection(0,0,-1) self.pieCol = CollisionNode('pieRay') self.pieCol.addSolid(self.pieRay) self.pieCol.setFromCollideMask(BitMask32.bit(0)) self.pieCol.setIntoCollideMask(BitMask32.allOff()) self.pieColNp = self.pie.attachNewNode(self.pieCol) self.pieHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.pieColNp, self.pieHandler) 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) # Shows collision rays #self.eveGroundColNp.show() #self.camGroundColNp.show() # Shows collisions #self.cTrav.showCollisions(render) self.fixPieZ() # 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)) #directionalLight.setShadowCaster(True, 512, 512) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) #render.setShaderAuto() # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value def AIUpdate(self, task): self.AIworld.update() return task.cont def fixPieZ(self): self.cTrav.traverse(render) entries = [] for i in range(self.pieHandler.getNumEntries()): entry = self.pieHandler.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.pie.setZ(entries[0].getSurfacePoint(render).getZ() + .5) return False else: return True # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): if (self.gameOver != 1): if math.sqrt((self.eve.getX() - self.pie.getX())**2 + (self.eve.getY() - self.pie.getY())**2) < .6: # particle effect self.p = ParticleEffect() self.p.loadConfig("models/sparkleparticlerenderer.ptf") self.copyPie = self.pie.copyTo(render) self.copyPie.setColor(0.0, 0.0, 0.0, 0.0) self.p.start(parent = self.copyPie, renderParent = render) taskMgr.add(self.timedParticle, "timedParticle") # play collect sounds self.collectSoundEffect.play() # collect pie try: self.pie.setPos(Vec3(random.randrange(-120,-19), random.randrange(-60,51), 10)) while self.fixPieZ(): self.pie.setPos(Vec3(random.randrange(-120,-19), random.randrange(-60,51), 10)) except Exception as ex: print ex raw_input() self.pieDisplay.clearText() self.pieCount = self.pieCount + 1 self.pieDisplay = grabPie(self.pieCount) if math.sqrt((self.eve.getX() - self.character.getX())**2 + (self.eve.getY() - self.character.getY())**2) < 1 and self.gameOver == 0: self.caught = displayGameOver() self.gameOver = 1 if math.sqrt((self.eve.getX() - self.character2.getX())**2 + (self.eve.getY() - self.character2.getY())**2) < 1 and self.gameOver == 0: self.caught = displayGameOver() self.gameOver = 1 if math.sqrt((self.eve.getX() - self.character3.getX())**2 + (self.eve.getY() - self.character3.getY())**2) < 1.3 and self.gameOver == 0: self.caught = displayGameOver() self.gameOver = 1 if math.sqrt((self.eve.getX() - self.character2.getX())**2 + (self.eve.getY() - self.character2.getY())**2) < 12.5 and self.redDragonCollideCount == 0 and self.redDragonChasingEve == 0: self.redDragonChasingEve = 1 self.AIbehaviors2.removeAi("pursue") self.AIbehaviors2.pauseAi("seek") self.AIbehaviors2.pursue(self.eve, 1) # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. base.camera.lookAt(self.eve) 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()) self.pie.setH(self.pie.getH() + 100 * globalClock.getDt()) # save eve's initial position so that we can restore it, # in case she falls off the map or runs into something. startpos = self.eve.getPos() # If a move-key is pressed, move eve in the specified direction. if (self.keyMap["left"]!=0): self.eve.setH(self.eve.getH() + 300 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.eve.setH(self.eve.getH() - 300 * globalClock.getDt()) if (self.keyMap["forward"]!=0): if (self.keyMap["run"] != 0): self.eve.setY(self.eve, -30 * globalClock.getDt()) else: self.eve.setY(self.eve, -10 * globalClock.getDt()) # If eve is moving, loop the run animation. # If she 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: if (self.keyMap["run"] != 0): self.eve.loop("run") self.isMoving = True self.isRunning = True self.isWalking = False self.footstepSound.setPlayRate(1.3) self.footstepSound.play() else: self.eve.loop("walk") self.eve.setPlayRate(2.0, "walk") self.isMoving = True self.isWalking = True self.isRunning = False self.footstepSound.setPlayRate(1.0) self.footstepSound.play() else: if (self.keyMap["run"] != 0 and self.isWalking): self.eve.loop("run" ) self.isRunning = True self.isWalking = False self.footstepSound.setPlayRate(1.3) elif (self.keyMap["run"] == 0 and self.isRunning): self.eve.loop("walk") self.eve.setPlayRate(2.0, "walk") self.isWalking = True self.isRunning = False self.footstepSound.setPlayRate(1.0) else: if self.isMoving: self.eve.stop() self.eve.pose("walk",10) self.isMoving = False self.footstepSound.stop() # If the camera is too far from eve, move it closer. # If the camera is too close to eve, move it farther. camvec = self.eve.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 eve's Z coordinate. If eve's ray hit terrain,s # update her Z. If it hit anything else, or didn't hit anything, put # her back where she was last frame. entries = [] for i in range(self.eveGroundHandler.getNumEntries()): entry = self.eveGroundHandler.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.eve.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.eve.setPos(startpos) # Adjust the dragon's Z coordinate like with eve. Additionally, if # the dragon has hit an object, have it seek a location behind it # temporarily. if self.dragonCollideCount == 0: self.AIbehaviors.resumeAi("pursue") self.AIbehaviors.pauseAi("seek") else: self.dragonCollideCount = self.dragonCollideCount - 1 entries = [] for i in range(self.dragonGroundHandler.getNumEntries()): entry = self.dragonGroundHandler.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.character.setZ(entries[0].getSurfacePoint(render).getZ() + 1) elif (self.dragonCollideCount == 0): try: self.AIbehaviors.pauseAi("pursue") except Exception as ex: print ex raw_input() self.AIbehaviors.seek(Vec3(self.character.getX() + 2000*(-self.character.getX() + self.dragonStartPos.getX()), self.character.getY() + 2000*(-self.character.getY() + self.dragonStartPos.getY()), self.character.getZ() + 2000*(-self.character.getZ() + self.dragonStartPos.getZ())), 20000) #self.AIbehaviors.seek(self.character3) self.dragonCollideCount = 100 #self.AIbehaviors.flee(self.character.getPos(), 1, 10, 10000) #self.character.setPos(dragonStartPos) else: #do nothing self.dragonCollideCount = self.dragonCollideCount if self.redDragonCollideCount == 0 and self.redDragonChasingEve == 0: self.AIbehaviors2.pursue(self.rand2, 1) self.AIbehaviors2.pauseAi("seek") elif self.redDragonChasingEve == 0: self.redDragonCollideCount = self.redDragonCollideCount - 1 # Red dragon z correcting and collision detecting entries = [] for i in range(self.redDragonGroundHandler.getNumEntries()): entry = self.redDragonGroundHandler.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.character2.setZ(entries[0].getSurfacePoint(render).getZ() + .6) elif (self.redDragonCollideCount == 0): try: self.AIbehaviors2.removeAi("pursue") except Exception as ex: print ex raw_input() self.redDragonChasingEve = 0 self.AIbehaviors2.seek(Vec3(self.character2.getX() + 2000*(-self.character2.getX() + self.redDragonStartPos.getX()), self.character2.getY() + 2000*(-self.character2.getY() + self.redDragonStartPos.getY()), self.character2.getZ() + 2000*(-self.character2.getZ() + self.redDragonStartPos.getZ())), 20000) #self.AIbehaviors.seek(self.character3) self.redDragonCollideCount = 100 #self.AIbehaviors.flee(self.character.getPos(), 1, 10, 10000) #self.character.setPos(dragonStartPos) else: #do nothing self.redDragonCollideCount = self.redDragonCollideCount # Adjust the ghost dragon's Z coordinate like with eve. # Additionally, if the ghost dragon has hit an object, have it # seek a location behind it temporarily. #if self.ghostDragonCollideCount == 0: # self.AIbehaviors.resumeAi("wander") # self.AIbehaviors3.pauseAi("seek") #else: # self.ghostDragonCollideCount = self.dragonCollideCount - 1 entries = [] for i in range(self.ghostDragonGroundHandler.getNumEntries()): entry = self.ghostDragonGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: ghostDragonCmp(x,y)) if (len(entries)>0): self.character3.setZ(entries[0].getSurfacePoint(render).getZ() + 2.5) #elif (self.ghostDragonCollideCount == 0): # self.AIbehaviors3.pauseAi("wander") # self.AIbehaviors3.seek(Vec3(self.character.getX() + 2000*(-self.character.getX() + self.dragonStartPos.getX()), self.character.getY() + 2000*(-self.character.getY() + self.dragonStartPos.getY()), self.character.getZ() + 2000*(-self.character.getZ() + self.dragonStartPos.getZ())), 20000) #self.AIbehaviors.seek(self.character3) # self.ghostDragonCollideCount = 100 #self.AIbehaviors.flee(self.character.getPos(), 1, 10, 10000) #self.character.setPos(dragonStartPos) #else: #do nothing # self.ghostDragonCollideCount = self.ghostDragonCollideCount # Keep the camera at one foot above the terrain, # or two feet above eve, 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.eve.getZ() + 2.0): base.camera.setZ(self.eve.getZ() + 2.0) # The camera should look in eve's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above eve's head. self.floater.setPos(self.eve.getPos()) self.floater.setZ(self.eve.getZ() + 2.0) base.camera.lookAt(self.floater) self.eateve.setPos(self.eve.getX(), self.eve.getY(), self.eve.getZ() + 1) self.dragonStartPos = self.character.getPos() self.redDragonStartPos = self.character2.getPos() return task.cont else: self.eve.stop() self.isMoving = False self.footstepSound.stop() self.character.stop() self.AIbehaviors.pauseAi("wander") self.AIbehaviors.pauseAi("seek") self.AIbehaviors.pauseAi("pursue") self.character2.stop() self.AIbehaviors2.pauseAi("wander") self.AIbehaviors2.pauseAi("seek") self.AIbehaviors2.pauseAi("pursue") self.character3.stop() self.AIbehaviors3.pauseAi("wander") self.AIbehaviors3.pauseAi("seek") self.AIbehaviors3.pauseAi("pursue") self.greenDragonSound.stop() self.redDragonSound.stop() self.blueDragonSound.stop() if self.musicend.status() != self.musicend.PLAYING: self.musicend.setLoop(1) self.musicend.play() if (self.keyMap["reset"] == 1): self.gameOver = 0 self.musicend.stop() self.resetGame() # Fill in all of the things return task.cont def timedParticle(self, task): if task.time < 1.0: return task.cont self.p.disable() self.copyPie.removeNode() return task.done
class BallInMazeDemo(ShowBase): def __init__(self): global action # Initialize the ShowBase class from which we inherit, which will # create a window and set up everything we need for rendering into it. action = "start" ShowBase.__init__(self) winProps = WindowProperties() winProps.setTitle("LASO Simulation - (RLP 2019-2020)") base.win.requestProperties(winProps) if not base.win.getGsg().getSupportsBasicShaders(): print( "Error: Video driver reports that depth textures are not supported." ) return if not base.win.getGsg().getSupportsDepthTexture(): print( "Error: Video driver reports that depth textures are not supported." ) return self.accept("escape", finalitzar) # Escape quits # Disable default mouse-based camera control. This is a method on the # ShowBase class from which we inherit. #self.disableMouse() # Place the camera camera.setPosHpr(0, 0, 80, 0, -90, 0) base.trackball.node().set_pos(0, 200, 0) base.trackball.node().set_hpr(0, 60, 0) #camera.setPosHpr(0, 0, 25, 0, -90, 0) #base.camLens.setNearFar(200, 600) #self.enableMouse() # Load the maze and place it in the scene #self.maze = loader.loadModel("models/maze") self.skybox = loader.loadModel("models/skybox") self.skybox.reparentTo(render) self.skybox.setPosHpr(0, 0, 45 + MAZE_OFFSETS[CURR_MAZE], 0, -180, 0) #self.skybox.setScale(2.54) self.taula = loader.loadModel("models/taula") self.taula.reparentTo(render) self.taula.setPosHpr(0, 0, -53.6 + MAZE_OFFSETS[CURR_MAZE], 0, 0, 0) self.taula.setScale(1.8) self.laso_box = loader.loadModel("models/laso_box") self.laso_box.reparentTo(render) self.laso_box.setPosHpr(0, 0, MAZE_OFFSETS[CURR_MAZE], 0, 0, 0) self.laso_ax = loader.loadModel("models/laso_ax") self.laso_ax.reparentTo(self.laso_box) self.laso_ax.setPosHpr(0, 0, MAZE_HEIGHT, 0, 0, 0) self.maze_i = CURR_MAZE self.maze = loader.loadModel("models/" + MAZES_NAME[self.maze_i]) self.maze.reparentTo(render) self.maze.setPosHpr(0, 0, MAZE_HEIGHT, 0, 0, 0) #self.maze.setScale(2.54) # Load custom maze #self.maze2 = loader.loadModel("models/lab4") #self.maze2.reparentTo(render) # Most times, you want collisions to be tested against invisible geometry # rather than every polygon. This is because testing against every polygon # in the scene is usually too slow. You can have simplified or approximate # geometry for the solids and still get good results. # # Sometimes you'll want to create and position your own collision solids in # code, but it's often easier to have them built automatically. This can be # done by adding special tags into an egg file. Check maze.egg and ball.egg # and look for lines starting with <Collide>. The part is brackets tells # Panda exactly what to do. Polyset means to use the polygons in that group # as solids, while Sphere tells panda to make a collision sphere around them # Keep means to keep the polygons in the group as visable geometry (good # for the ball, not for the triggers), and descend means to make sure that # the settings are applied to any subgroups. # # Once we have the collision tags in the models, we can get to them using # NodePath's find command # Find the collision node named wall_collide #self.walls = self.maze.find("**/wall_collide") self.walls = self.maze.find("**/wall_col") # Collision objects are sorted using BitMasks. BitMasks are ordinary numbers # with extra methods for working with them as binary bits. Every collision # solid has both a from mask and an into mask. Before Panda tests two # objects, it checks to make sure that the from and into collision masks # have at least one bit in common. That way things that shouldn't interact # won't. Normal model nodes have collision masks as well. By default they # are set to bit 20. If you want to collide against actual visable polygons, # set a from collide mask to include bit 20 # # For this example, we will make everything we want the ball to collide with # include bit 0 self.walls.node().setIntoCollideMask(BitMask32.bit(0)) # CollisionNodes are usually invisible but can be shown. Uncomment the next # line to see the collision walls #self.walls.show() # Show wall colliders # We will now find the triggers for the holes and set their masks to 0 as # well. We also set their names to make them easier to identify during # collisions self.loseTriggers = [] #for i in range(6): for i in range(3): #trigger = self.maze.find("**/hole_collide" + str(i)) trigger = self.maze.find("**/hole" + str(i + 1) + "_col") trigger.node().setIntoCollideMask(BitMask32.bit(0)) trigger.node().setName("loseTrigger") self.loseTriggers.append(trigger) # Uncomment this line to see the triggers #trigger.show() # Show lose triggers colliders # Ground_collide is a single polygon on the same plane as the ground in the # maze. We will use a ray to collide with it so that we will know exactly # what height to put the ball at every frame. Since this is not something # that we want the ball itself to collide with, it has a different # bitmask. #self.mazeGround = self.maze.find("**/ground_collide") self.mazeGround = self.maze.find("**/ground_col") self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1)) # Load the ball and attach it to the scene # It is on a root dummy node so that we can rotate the ball itself without # rotating the ray that will be attached to it self.ballRoot = render.attachNewNode("ballRoot") self.ball = loader.loadModel("models/bball") self.ball.reparentTo(self.ballRoot) # Find the collison sphere for the ball which was created in the egg file # Notice that it has a from collision mask of bit 0, and an into collison # mask of no bits. This means that the ball can only cause collisions, not # be collided into self.ballSphere = self.ball.find("**/ball") self.ballSphere.node().setFromCollideMask(BitMask32.bit(0)) self.ballSphere.node().setIntoCollideMask(BitMask32.allOff()) # No we create a ray to start above the ball and cast down. This is to # Determine the height the ball should be at and the angle the floor is # tilting. We could have used the sphere around the ball itself, but it # would not be as reliable self.ballGroundRay = CollisionRay() # Create the ray self.ballGroundRay.setOrigin(0, 0, 10) # Set its origin self.ballGroundRay.setDirection(0, 0, -1) # And its direction # Collision solids go in CollisionNode # Create and name the node self.ballGroundCol = CollisionNode('groundRay') self.ballGroundCol.addSolid(self.ballGroundRay) # Add the ray self.ballGroundCol.setFromCollideMask( BitMask32.bit(1)) # Set its bitmasks self.ballGroundCol.setIntoCollideMask(BitMask32.allOff()) # Attach the node to the ballRoot so that the ray is relative to the ball # (it will always be 10 feet over the ball and point down) self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol) # Uncomment this line to see the ray #self.ballGroundColNp.show() # Show ball collision ray # Finally, we create a CollisionTraverser. CollisionTraversers are what # do the job of walking the scene graph and calculating collisions. # For a traverser to actually do collisions, you need to call # traverser.traverse() on a part of the scene. Fortunately, ShowBase # has a task that does this for the entire scene once a frame. By # assigning it to self.cTrav, we designate that this is the one that # it should call traverse() on each frame. self.cTrav = CollisionTraverser() # Collision traversers tell collision handlers about collisions, and then # the handler decides what to do with the information. We are using a # CollisionHandlerQueue, which simply creates a list of all of the # collisions in a given pass. There are more sophisticated handlers like # one that sends events and another that tries to keep collided objects # apart, but the results are often better with a simple queue self.cHandler = CollisionHandlerQueue() # Now we add the collision nodes that can create a collision to the # traverser. The traverser will compare these to all others nodes in the # scene. There is a limit of 32 CollisionNodes per traverser # We add the collider, and the handler to use as a pair self.cTrav.addCollider(self.ballSphere, self.cHandler) self.cTrav.addCollider(self.ballGroundColNp, self.cHandler) # Collision traversers have a built in tool to help visualize collisions. # Uncomment the next line to see it. #self.cTrav.showCollisions(render) # Show traveser collisions # This section deals with lighting for the ball. Only the ball was lit # because the maze has static lighting pregenerated by the modeler self.alightColor = 0.1 ambientLight = AmbientLight("ambientLight") ambientLight.setColor( (self.alightColor, self.alightColor, self.alightColor, 1)) #ambientLight.setColor((1, 0, 0, 1)) self.ambientL = render.attachNewNode(ambientLight) render.setLight(self.ambientL) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(LVector3(0, 1, 0)) #directionalLight.setColor((0.375, 0.375, 0.375, 1)) directionalLight.setColor((1, 1, 1, 1)) directionalLight.setSpecularColor((1, 1, 1, 1)) #self.directL = render.attachNewNode(directionalLight) #render.setLight(self.directL) """ self.teapot = loader.loadModel('teapot') self.teapot.reparentTo(render) self.teapot.setPos(0, 0, 0) self.teapotMovement = self.teapot.hprInterval(50, LPoint3(0, 360, 360)) self.teapotMovement.loop() """ self.lightColor = 1000 self.light = render.attachNewNode(Spotlight("Spot")) self.light.node().setScene(render) self.light.node().setShadowCaster(True, 1024, 1024) self.light.node().setAttenuation((1, 0, 1)) #self.light.node().showFrustum() self.light.node().getLens().setFov(48) self.light.node().getLens().setNearFar(5, 500) #self.light.node().setColor((100000, 100000, 100000, 1)) self.light.node().setColor( (self.lightColor, self.lightColor, self.lightColor, 1)) self.light.setPos(0, 0, 100) self.light.setHpr(LVector3(0, -90, 0)) render.setLight(self.light) plight = PointLight('plight') plight.setColor((0.8, 0.8, 0.8, 1)) plnp = render.attachNewNode(plight) plnp.setPos(0, 0, 80) render.setLight(plnp) render.setShaderAuto() #self.maze2.setPos(0, 0, 10) #self.ballRoot.setLight(render.attachNewNode(ambientLight)) #self.ballRoot.setLight(render.attachNewNode(directionalLight)) # Maze 2 light #self.maze2.setLight(self.light) #self.maze2.setLight(self.ambientL) #self.maze2.hide() #self.maze.hide() # This section deals with adding a specular highlight to the ball to make # it look shiny. Normally, this is specified in the .egg file. m = Material() m.setSpecular((1, 1, 1, 1)) m.setShininess(96) self.ball.setMaterial(m, 1) #self.maze2.setMaterial(m,1) # Set maze rotation speed self.mazeSpeed = 10 self.mazeVoiceSpeed = 8 # Set maze max rotation self.mazeMaxRotation = 10 self.mazeVoiceMaxRotation = 10 # Distància minima per passar al següent punt self.minDist = 25 # Pas per saltar punts del path self.pas = 25 base.setBackgroundColor(0.2, 0.2, 0.2) self.camera2_buffer = base.win.makeTextureBuffer("c2buffer", PI_CAMERA_RES, PI_CAMERA_RES, to_ram=True) #mytexture.write("text1.png") # print(mytexture) # cv2.imshow("Texure1", mytexture) #self.camera2_buffer.setSort(-100) self.camera2 = base.makeCamera(self.camera2_buffer) self.camera2.reparentTo(render) self.camera2.setPosHpr(0, 0, PI_CAMERA_H, 0, -90, 0) self.camera2.node().getLens().setFov(PI_CAMERA_FOV) self.camera2.node().getLens().setFilmSize(1, 1) self.digitizer = Digitizer() self.aStar = aStar() self.path = None self.ready_to_solve = False # Finally, we call start for more initialization self.start() def start(self): # The maze model also has a locator in it for where to start the ball # To access it we use the find command #startPos = self.maze.find("**/start").getPos() startPos = (MAZES_START_POS[self.maze_i][0], MAZES_START_POS[self.maze_i][1], MAZE_HEIGHT + BALL_OFFSET) self.ballRoot.setPos(startPos) if not self.ready_to_solve: self.ballRoot.hide() self.pid = pid(startPos[0], startPos[1]) # INICIALITZAR A* AMB LABERINT HARDCODEJAT, S'HA DE CANVIAR # ----------- self.path_matrix, self.path = self.aStar.a_star(laberint, 26, 10, 465, 448, 89, 461) ----------------- self.indexPuntActual = 0 self.ballV = LVector3(0, 0, 0) # Initial velocity is 0 self.accelV = LVector3(0, 0, 0) # Initial acceleration is 0 # Create the movement task, but first make sure it is not already # running taskMgr.remove("rollTask") self.mainLoop = taskMgr.add(self.rollTask, "rollTask") # This function handles the collision between the ray and the ground # Information about the interaction is passed in colEntry def groundCollideHandler(self, colEntry): # Set the ball to the appropriate Z value for it to be exactly on the # ground newZ = colEntry.getSurfacePoint(render).getZ() #self.ballRoot.setZ(newZ + .4) self.ballRoot.setZ(newZ + 1.4) # Find the acceleration direction. First the surface normal is crossed with # the up vector to get a vector perpendicular to the slope norm = colEntry.getSurfaceNormal(render) accelSide = norm.cross(LVector3.up()) # Then that vector is crossed with the surface normal to get a vector that # points down the slope. By getting the acceleration in 3D like this rather # than in 2D, we reduce the amount of error per-frame, reducing jitter self.accelV = norm.cross(accelSide) # This function handles the collision between the ball and a wall def wallCollideHandler(self, colEntry): # First we calculate some numbers we need to do a reflection norm = colEntry.getSurfaceNormal(render) * -1 # The normal of the wall curSpeed = self.ballV.length() # The current speed inVec = self.ballV / curSpeed # The direction of travel velAngle = norm.dot(inVec) # Angle of incidance hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos() hitDir.normalize() # The angle between the ball and the normal hitAngle = norm.dot(hitDir) # Ignore the collision if the ball is either moving away from the wall # already (so that we don't accidentally send it back into the wall) # and ignore it if the collision isn't dead-on (to avoid getting caught on # corners) if velAngle > 0 and hitAngle > .995: # Standard reflection equation reflectVec = (norm * norm.dot(inVec * -1) * 2) + inVec # This makes the velocity half of what it was if the hit was dead-on # and nearly exactly what it was if this is a glancing blow self.ballV = reflectVec * (curSpeed * (((1 - velAngle) * .5) + .5)) # Since we have a collision, the ball is already a little bit buried in # the wall. This calculates a vector needed to move it so that it is # exactly touching the wall disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) newPos = self.ballRoot.getPos() + disp self.ballRoot.setPos(newPos) def rotateMaze(self, p, r): maxRot = self.mazeMaxRotation maxVel = self.mazeSpeed if voice_solving: maxRot = self.mazeVoiceMaxRotation maxVel = self.mazeVoiceSpeed if self.ready_to_solve: dt = globalClock.getDt() if r != 0 or p != 0: self.maze.setR(self.maze, r * maxVel * dt) self.maze.setP(self.maze, p * maxVel * dt) # Check bounds if self.maze.getR() > maxRot: self.maze.setR(maxRot) elif self.maze.getR() < -maxRot: self.maze.setR(-maxRot) if self.maze.getP() > maxRot: self.maze.setP(maxRot) elif self.maze.getP() < -maxRot: self.maze.setP(-maxRot) self.laso_ax.setP(self.maze.getP()) self.maze.setH(0) self.laso_ax.setH(0) self.laso_ax.setR(0) def solve(self): # PI CAMERA PHOTO screenshot = self.camera2_buffer.getScreenshot() if screenshot: img = np.asarray(screenshot.getRamImage(), dtype=np.uint8).copy() img = img.reshape( (screenshot.getYSize(), screenshot.getXSize(), 4)) img = img[::-1] img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) self.digitizer.set_src_img(img) self.digitizer.digitize_source() print("solve!!") trobat = False radi = 30 m_seg = 20 while trobat == False: trobat, self.pm, self.path = self.aStar.a_star( self.digitizer.source_mask.copy(), radi, int(m_seg), self.digitizer.startPos[1], self.digitizer.startPos[0], self.digitizer.endPos[1], self.digitizer.endPos[0]) radi = max(radi - 1, 0) m_seg = max(m_seg - 0.5, 0) print(radi, m_seg) #print(self.pm) self.pathFollowed = np.zeros(self.pm.shape) check_result = cv2.addWeighted( self.digitizer.source_img_g.astype('uint8'), 0.5, np.clip(self.pm * 255, 0, 255).astype('uint8'), 0.5, 1) cv2.imshow("laberint resolt sobre original", check_result) self.ready_to_solve = True self.ballRoot.show() # cv2.imshow('img', img) # cv2.waitKey(0) def get_ball_position(self): # PI CAMERA PHOTO #startTime = time.time() screenshot = self.camera2_buffer.getScreenshot() if screenshot: #v = memoryview(screenshot.getRamImage()).tolist() img = np.asarray(screenshot.getRamImage(), dtype=np.uint8).copy() img = img.reshape( (screenshot.getYSize(), screenshot.getXSize(), 4)) img = img[::-1] img = img[:, :, :3] #self.camera2_buffer.saveScreenshot("ts.jpg") #img = cv2.imread("ts.jpg", 1) #img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) pos = self.digitizer.get_ball_pos(img) if pos is not False: pos = pos.astype(np.int32) self.pathFollowed[pos[0] - 1:pos[0] + 2, pos[1] - 1:pos[1] + 2] = 1 img[self.pm == 1] = 0 img[self.pm == 1, 2] = 255 img[self.pathFollowed == 1] = 0 img[self.pathFollowed == 1, 1] = 255 #print(pos) img[pos[0] - 2:pos[0] + 3, pos[1] - 2:pos[1] + 3] = 0 posActual = self.path[self.indexPuntActual] img[posActual[0] - 2:posActual[0] + 3, posActual[1] - 2:posActual[1] + 3] = 255 cv2.imshow('img', img) if cv2.waitKey(1) & 0xFF == ord('q'): pass #if pos is not None: #print("BALL POSITION: ", pos) #check_res = cv2.circle(self.digitizer.source_img, (int(pos[0]), int(pos[1])), 24, (0, 0, 255)) #cv2.imshow("BALL POS RES", check_res) return pos # This is the task that deals with making everything interactive def rollTask(self, task): # Standard technique for finding the amount of time since the last # frame #print("\r",self.maze.getR(), self.maze.getP(), self.ballRoot.getPos(), end="") dt = globalClock.getDt() print("\r{:.3} fps ".format(1 / dt), end="") # If dt is large, then there has been a # hiccup that could cause the ball # to leave the field if this functions runs, so ignore the frame if dt > .2: return Task.cont #print(action) if action == "start": a = 1 elif action == "stop": while action == "stop": a = 0 # elif action == "restart": in Line 531 elif action == "coord": a = 1 #ALGUNA CRIDA A METODE DE NARCIS/MARC key_down = base.mouseWatcherNode.is_button_down if self.ready_to_solve: if key_down(KeyboardButton.ascii_key('d')): screenshot = self.camera2_buffer.getScreenshot() if screenshot: v = memoryview(screenshot.getRamImage()).tolist() img = np.array(v, dtype=np.uint8) img = img.reshape( (screenshot.getYSize(), screenshot.getXSize(), 4)) img = img[::-1] #self.digitizer.set_src_img(img) #self.digitizer.digitalize_source() cv2.imshow('img', img) #cv2.waitKey(0) if key_down(KeyboardButton.ascii_key('s')): print("Screenshot!") self.camera2_buffer.saveScreenshot("screenshot.jpg") # The collision handler collects the collisions. We dispatch which function # to handle the collision based on the name of what was collided into for i in range(self.cHandler.getNumEntries()): entry = self.cHandler.getEntry(i) name = entry.getIntoNode().getName() if action == "restart": self.loseGame(entry) if name == "wall_col": self.wallCollideHandler(entry) elif name == "ground_col": self.groundCollideHandler(entry) elif name == "loseTrigger": vr.restart = 1 global th th = threading.Thread(target=listenVoice) th.start() self.loseGame(entry) # Read the mouse position and tilt the maze accordingly # Rotation axes use (roll, pitch, heave) """ if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() # get the mouse position self.maze.setP(mpos.getY() * -10) self.maze.setR(mpos.getX() * 10) """ ballPos = self.get_ball_position() #print("BALL POS: ", ballPos) posFPixel = self.path[self.indexPuntActual] xFinal = posFPixel[1] #posFPixel[1]/np.shape(laberint)[0]*13 - 6.5 yFinal = posFPixel[ 0] #-(posFPixel[0]/np.shape(laberint)[1]*13.5 - 6.8) dist = math.sqrt((xFinal - ballPos[1])**2 + (yFinal - ballPos[0])**2) if (dist < self.minDist): if (self.indexPuntActual == len(self.path) - 1): print("SOLVED!!", end="") while (self.aStar.distance( (ballPos[0], ballPos[1]), self.path[self.indexPuntActual]) < self.pas): if (self.indexPuntActual < len(self.path) - 1): self.indexPuntActual += 1 else: break # ball pos (y,x) #print("END POS: ", self.digitizer.endPos) if voice_solving: p_rotation = dir_veu[0] r_rotation = dir_veu[1] if p_rotation == 0 and r_rotation == 0 and ballPos is not None: p_rotation, r_rotation = self.pid.getPR( ballPos[1], ballPos[0], ballPos[1], ballPos[0], self.maze.getP(), self.maze.getR(), dt) else: p_rotation = 0 r_rotation = 0 #print(ballPos, dist) #print(ballPos) if ballPos is not None: p_rotation, r_rotation = self.pid.getPR( ballPos[1], ballPos[0], xFinal, yFinal, self.maze.getP(), self.maze.getR(), dt) #print(p_rotation, r_rotation) if key_down(KeyboardButton.up()): p_rotation = -1 elif key_down(KeyboardButton.down()): p_rotation = 1 if key_down(KeyboardButton.left()): r_rotation = -1 elif key_down(KeyboardButton.right()): r_rotation = 1 self.rotateMaze(p_rotation, r_rotation) # Finally, we move the ball # Update the velocity based on acceleration self.ballV += self.accelV * dt * ACCEL # Clamp the velocity to the maximum speed if self.ballV.lengthSquared() > MAX_SPEED_SQ: self.ballV.normalize() self.ballV *= MAX_SPEED # Update the position based on the velocity self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV * dt)) #print(self.ballRoot.getPos()) # This block of code rotates the ball. It uses something called a quaternion # to rotate the ball around an arbitrary axis. That axis perpendicular to # the balls rotation, and the amount has to do with the size of the ball # This is multiplied on the previous rotation to incrimentally turn it. prevRot = LRotationf(self.ball.getQuat()) axis = LVector3.up().cross(self.ballV) newRot = LRotationf(axis, 45.5 * dt * self.ballV.length()) self.ball.setQuat(prevRot * newRot) elif key_down(KeyboardButton.ascii_key('1')): self.solve() if key_down(KeyboardButton.ascii_key('i')): self.light.setY(self.light.getY() + 10 * dt) elif key_down(KeyboardButton.ascii_key('k')): self.light.setY(self.light.getY() - 10 * dt) if key_down(KeyboardButton.ascii_key('j')): self.light.setX(self.light.getX() - 10 * dt) elif key_down(KeyboardButton.ascii_key('l')): self.light.setX(self.light.getX() + 10 * dt) if key_down(KeyboardButton.ascii_key('u')): self.lightColor += 10000 * dt self.light.node().setColor( (self.lightColor, self.lightColor, self.lightColor, 1)) elif key_down(KeyboardButton.ascii_key('o')): self.lightColor -= 10000 * dt self.light.node().setColor( (self.lightColor, self.lightColor, self.lightColor, 1)) if key_down(KeyboardButton.ascii_key('8')): self.alightColor += 1 * dt self.ambientL.node().setColor( (self.alightColor, self.alightColor, self.alightColor, 1)) elif key_down(KeyboardButton.ascii_key('9')): self.alightColor -= 1 * dt self.ambientL.node().setColor( (self.alightColor, self.alightColor, self.alightColor, 1)) if key_down(KeyboardButton.ascii_key('r')): base.trackball.node().set_pos(0, 200, 0) base.trackball.node().set_hpr(0, 60, 0) return Task.cont # Continue the task indefinitely # If the ball hits a hole trigger, then it should fall in the hole. # This is faked rather than dealing with the actual physics of it. def loseGame(self, entry): # The triggers are set up so that the center of the ball should move to the # collision point to be in the hole global action action = "start" toPos = entry.getInteriorPoint(render) taskMgr.remove('rollTask') # Stop the maze task self.pathFollowed = np.zeros(self.pm.shape) self.maze.setP(0) self.maze.setR(0) # Move the ball into the hole over a short sequence of time. Then wait a # second and call start to reset the game Sequence( Parallel( LerpFunc(self.ballRoot.setX, fromData=self.ballRoot.getX(), toData=toPos.getX(), duration=.1), LerpFunc(self.ballRoot.setY, fromData=self.ballRoot.getY(), toData=toPos.getY(), duration=.1), LerpFunc(self.ballRoot.setZ, fromData=self.ballRoot.getZ(), toData=self.ballRoot.getZ() - .9, duration=.2)), Wait(1), Func(self.start)).start() def toggleInterval(self, ival): if ival.isPlaying(): ival.pause() else: ival.resume() def shaderSupported(self): return base.win.getGsg().getSupportsBasicShaders() and \ base.win.getGsg().getSupportsDepthTexture() and \ base.win.getGsg().getSupportsShadowFilter()
def makeCrunchTrack(self): toonId = self.toon toon = base.cr.doId2do.get(toonId) if not toon: return self.virtualSuit.lookAt(toon) if self.virtualSuit.style.body in ['a', 'b']: throwDelay = 3 elif self.virtualSuit.style.body == 'c': throwDelay = 2.3 else: throwDelay = 2 numberNames = ['one', 'two', 'three', 'four', 'five', 'six'] BattleParticles.loadParticles() numberSpill1 = BattleParticles.createParticleEffect(file='numberSpill') numberSpill2 = BattleParticles.createParticleEffect(file='numberSpill') spillTexture1 = random.choice(numberNames) spillTexture2 = random.choice(numberNames) BattleParticles.setEffectTexture(numberSpill1, 'audit-' + spillTexture1) BattleParticles.setEffectTexture(numberSpill2, 'audit-' + spillTexture2) numberSpillTrack1 = getPartTrack(numberSpill1, 1.1, 2.2, [numberSpill1, self.virtualSuit, 0]) numberSpillTrack2 = getPartTrack(numberSpill2, 1.5, 1.0, [numberSpill2, self.virtualSuit, 0]) numberSprayTracks = Parallel() numOfNumbers = random.randint(5, 9) for i in xrange(0, numOfNumbers - 1): nextSpray = BattleParticles.createParticleEffect( file='numberSpray') nextTexture = random.choice(numberNames) BattleParticles.setEffectTexture(nextSpray, 'audit-' + nextTexture) nextStartTime = random.random() * 0.6 + 3.03 nextDuration = random.random() * 0.4 + 1.4 nextSprayTrack = getPartTrack(nextSpray, nextStartTime, nextDuration, [nextSpray, self.virtualSuit, 0]) numberSprayTracks.append(nextSprayTrack) def throwProp(prop): if not self.virtualSuit: return toon = self.cr.doId2do.get(toonId) if not toon: self.cleanupProp(prop, False) self.finishPropAttack() return self.virtualSuit.lookAt(toon) prop.wrtReparentTo(render) hitPos = toon.getPos() + Vec3(0, 0, 2.5) distance = (prop.getPos() - hitPos).length() speed = 50.0 throwSequence = Sequence( prop.posInterval(distance / speed, hitPos), Func(self.cleanupProp, prop, False)) throwSequence.start() numberTracks = Parallel() for i in xrange(0, numOfNumbers): texture = random.choice(numberNames) next = copyProp(BattleParticles.getParticle('audit-' + texture)) next.reparentTo(self.virtualSuit.getRightHand()) next.setScale(0.01, 0.01, 0.01) next.setColor(Vec4(0.0, 0.0, 0.0, 1.0)) next.setPos(random.random() * 0.6 - 0.3, random.random() * 0.6 - 0.3, random.random() * 0.6 - 0.3) next.setHpr(VBase3(-1.15, 86.58, -76.78)) # Make prop virtual: next.setColorScale(1.0, 0.0, 0.0, 0.8) next.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd)) # Prop collisions: colNode = CollisionNode(self.uniqueName('SuitAttack')) colNode.setTag('damage', str(self.attackInfo[1])) bounds = next.getBounds() center = bounds.getCenter() radius = bounds.getRadius() sphere = CollisionSphere(center.getX(), center.getY(), center.getZ(), radius) sphere.setTangible(0) colNode.addSolid(sphere) colNode.setIntoCollideMask(WallBitmask) next.attachNewNode(colNode) numberTrack = Sequence( Wait(throwDelay), Parallel( LerpScaleInterval(next, 0.6, Point3(1.0, 1.0, 1.0)), Func(throwProp, next), ), ) numberTracks.append(numberTrack) suitTrack = Parallel( Func(self.sayFaceoffTaunt), Sequence(ActorInterval(self.virtualSuit, 'throw-object'), ActorInterval(self.virtualSuit, 'neutral')), ) return Sequence( Parallel(suitTrack, numberSpillTrack1, numberSpillTrack2, numberTracks, numberSprayTracks), Func(self.virtualSuit.loop, 'walk', 0), Func(self.virtualSuit.setHpr, 0, 0, 0), )
class BallInMazeDemo(ShowBase): def __init__(self): # Initialize the ShowBase class from which we inherit, which will # create a window and set up everything we need for rendering into it. ShowBase.__init__(self) base.setBackgroundColor(0, 0, 0) self.accept("escape", sys.exit) # Escape quits self.disableMouse() camera.setPosHpr(0, 0, 0, 0, 0, 0) lens = PerspectiveLens() lens.setFov(90, 60) lens.setNear(0.01) lens.setFar(100000) self.cam.node().setLens(lens) self.ballSize = 0.025 self.cueLength = 0.2 # self.ballRoot = render.attachNewNode("ballRoot") # #self.ball = loader.loadModel("models/ball") # self.ball = loader.loadModel("models/ball_0_center.egg") # #self.ball = loader.loadModel("models/ball.dae") # self.ball.setScale(ballSize, ballSize, ballSize) # self.ball.reparentTo(self.ballRoot) # #print(self.ball.getBounds()) # #exit(1) # #self.ballSphere = self.ball.find("**/ball") # #print(self.ball.getScale()[0]) # cs = CollisionSphere(0, 0, 0, 1) # self.ballSphere = self.ball.attachNewNode(CollisionNode('ball')) # self.ballSphere.node().addSolid(cs) # self.ballSphere.node().setFromCollideMask(BitMask32.bit(0)) # self.ballSphere.node().setIntoCollideMask(BitMask32.bit(1)) self.sceneIndex = 2 self.planeInfo = PlaneScene(self.sceneIndex) self.planeScene = self.planeInfo.generateEggModel() self.planeScene.setTwoSided(True) self.planeScene.reparentTo(render) self.planeScene.hide() planeTriangles, horizontalPlaneTriangles, self.gravityDirection = self.planeInfo.getPlaneTriangles( ) self.ballRoots = [] self.balls = [] self.ballSpheres = [] self.ballGroundRays = [] for ballIndex in xrange(3): ballRoot = render.attachNewNode("ballRoot_" + str(ballIndex)) ball = loader.loadModel("models/ball_" + str(ballIndex) + "_center.egg") ball.setScale(self.ballSize, self.ballSize, self.ballSize) cs = CollisionSphere(0, 0, 0, 1) ballSphere = ball.attachNewNode( CollisionNode('ball_' + str(ballIndex))) ballSphere.node().addSolid(cs) ballSphere.node().setFromCollideMask( BitMask32.bit(0) | BitMask32.bit(1) | BitMask32.bit(3) | BitMask32.bit(4)) ballSphere.node().setIntoCollideMask(BitMask32.bit(1)) ball.reparentTo(ballRoot) self.ballRoots.append(ballRoot) self.balls.append(ball) self.ballSpheres.append(ballSphere) ballGroundRay = CollisionRay() # Create the ray ballGroundRay.setOrigin(0, 0, 0) # Set its origin ballGroundRay.setDirection( self.gravityDirection[0], self.gravityDirection[1], self.gravityDirection[2]) # And its direction # Collision solids go in CollisionNode # Create and name the node ballGroundCol = CollisionNode('ball_ray_' + str(ballIndex)) ballGroundCol.addSolid(ballGroundRay) # Add the ray ballGroundCol.setFromCollideMask( BitMask32.bit(2)) # Set its bitmasks ballGroundCol.setIntoCollideMask(BitMask32.allOff()) # Attach the node to the ballRoot so that the ray is relative to the ball # (it will always be 10 feet over the ball and point down) ballGroundColNp = ballRoot.attachNewNode(ballGroundCol) self.ballGroundRays.append(ballGroundColNp) ballRoot.hide() continue # Finally, we create a CollisionTraverser. CollisionTraversers are what # do the job of walking the scene graph and calculating collisions. # For a traverser to actually do collisions, you need to call # traverser.traverse() on a part of the scene. Fortunately, ShowBase # has a task that does this for the entire scene once a frame. By # assigning it to self.cTrav, we designate that this is the one that # it should call traverse() on each frame. self.cTrav = CollisionTraverser() # Collision traversers tell collision handlers about collisions, and then # the handler decides what to do with the information. We are using a # CollisionHandlerQueue, which simply creates a list of all of the # collisions in a given pass. There are more sophisticated handlers like # one that sends events and another that tries to keep collided objects # apart, but the results are often better with a simple queue self.cHandler = CollisionHandlerQueue() # Now we add the collision nodes that can create a collision to the # traverser. The traverser will compare these to all others nodes in the # scene. There is a limit of 32 CollisionNodes per traverser # We add the collider, and the handler to use as a pair #self.cTrav.addCollider(self.ballSphere, self.cHandler) for ballSphere in self.ballSpheres: self.cTrav.addCollider(ballSphere, self.cHandler) continue for ballGroundRay in self.ballGroundRays: self.cTrav.addCollider(ballGroundRay, self.cHandler) continue #self.cTrav.addCollider(self.ballGroundColNp, self.cHandler) # Collision traversers have a built in tool to help visualize collisions. # Uncomment the next line to see it. #self.cTrav.showCollisions(render) # This section deals with lighting for the ball. Only the ball was lit # because the maze has static lighting pregenerated by the modeler ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.55, .55, .55, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(LVector3(0, 0, -1)) directionalLight.setColor((0.375, 0.375, 0.375, 1)) directionalLight.setSpecularColor((1, 1, 1, 1)) for ballRoot in self.ballRoots: ballRoot.setLight(render.attachNewNode(ambientLight)) ballRoot.setLight(render.attachNewNode(directionalLight)) continue # This section deals with adding a specular highlight to the ball to make # it look shiny. Normally, this is specified in the .egg file. m = Material() m.setSpecular((1, 1, 1, 1)) m.setShininess(96) for ball in self.balls: ball.setMaterial(m, 1) continue self.original = False if self.original: camera.setPosHpr(0, 0, 25, 0, -90, 0) self.maze = loader.loadModel("models/maze") self.maze.reparentTo(render) self.walls = self.maze.find("**/wall_collide") self.walls.node().setIntoCollideMask(BitMask32.bit(0)) self.walls.show() pass #planeTriangles, planeNormals = self.planeInfo.getPlaneGeometries() self.triNPs = [] for triangleIndex, triangle in enumerate(planeTriangles): #print(triangleIndex) #for triangle in triangles: #print(triangle) tri = CollisionPolygon( Point3(triangle[0][0], triangle[0][1], triangle[0][2]), Point3(triangle[1][0], triangle[1][1], triangle[1][2]), Point3(triangle[2][0], triangle[2][1], triangle[2][2])) triNP = render.attachNewNode( CollisionNode('tri_' + str(triangleIndex))) triNP.node().setIntoCollideMask(BitMask32.bit(0)) triNP.node().addSolid(tri) self.triNPs.append(triNP) #triNP.show() continue #print(horizontalPlaneTriangles) for triangleIndex, triangle in enumerate(horizontalPlaneTriangles): #print(triangleIndex) #for triangle in triangles: #print(triangle) tri = CollisionPolygon( Point3(triangle[0][0], triangle[0][1], triangle[0][2]), Point3(triangle[1][0], triangle[1][1], triangle[1][2]), Point3(triangle[2][0], triangle[2][1], triangle[2][2])) triNP = render.attachNewNode( CollisionNode('ground_' + str(triangleIndex))) triNP.node().setIntoCollideMask(BitMask32.bit(2)) triNP.node().addSolid(tri) self.triNPs.append(triNP) #triNP.show() continue # tri = CollisionPolygon(Point3(-1, 4, -1), Point3(2, 4, -1), Point3(2, 4, 2)) # triNP = render.attachNewNode(CollisionNode('tri')) # triNP.node().setIntoCollideMask(BitMask32.bit(0)) # triNP.node().addSolid(tri) # triNP.show() #self.planeScene.node().setIntoCollideMask(BitMask32.bit(0)) # roomRootNP = self.planeScene # roomRootNP.flattenLight() # mesh = BulletTriangleMesh() # polygons = roomRootNP.findAllMatches("**/+GeomNode") # # p0 = Point3(-10, 4, -10) # # p1 = Point3(-10, 4, 10) # # p2 = Point3(10, 4, 10) # # p3 = Point3(10, 4, -10) # # mesh.addTriangle(p0, p1, p2) # # mesh.addTriangle(p1, p2, p3) # print(polygons) # for polygon in polygons: # geom_node = polygon.node() # #geom_node.reparentTo(self.render) # #print(geom_node.getNumGeoms()) # ts = geom_node.getTransform() # #print(ts) # for geom in geom_node.getGeoms(): # mesh.addGeom(geom, ts) # continue # continue # #self.scene = roomRootNP # shape = BulletTriangleMeshShape(mesh, dynamic=False) # #shape = BulletPlaneShape(Vec3(0, 0, 1), 1) # room = BulletRigidBodyNode('scene') # room.addShape(shape) # #room.setLinearDamping(0.0) # #room.setFriction(0.0) # print(shape) # room.setDeactivationEnabled(False) # roomNP = render.attachNewNode(room) # roomNP.setPos(0, 0, 0) # roomNP.node().setIntoCollideMask(BitMask32.bit(0)) # self.world = BulletWorld() # self.world.setGravity(Vec3(0, 0, 0)) # self.world.attachRigidBody(roomNP.node()) #room.setRestitution(1) #self.roomNP = self.scene self.cueRoot = render.attachNewNode("cueRoot") self.cue = loader.loadModel("models/cue_center.egg") self.cue.setScale(self.cueLength * 3, self.cueLength * 3, self.cueLength) self.cue.reparentTo(self.cueRoot) self.cuePos = (10, 0, 0) 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 separate it self.pickerNode.setFromCollideMask(BitMask32.bit(2)) self.pickerNode.setIntoCollideMask(BitMask32.allOff()) 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.cTrav.addCollider(self.pickerNP, self.cHandler) self.accept("mouse1", self.hit) # left-click grabs a piece self.holeLength = 0.06 holePos, holeHpr = self.planeInfo.getHolePos() self.holeRoot = render.attachNewNode("holeRoot") #self.hole = loader.loadModel("models/hole_horizontal_center.egg") self.hole = loader.loadModel("models/hole_color.egg") #self.hole = loader.loadModel("models/billiards_hole_center.egg") self.hole.setScale(self.holeLength, self.holeLength, self.holeLength) self.hole.reparentTo(self.holeRoot) self.hole.setTwoSided(True) self.holeRoot.setPos(holePos[0], holePos[1], holePos[2]) self.holeRoot.setHpr(holeHpr[0], holeHpr[1], holeHpr[2]) #tex = loader.loadTexture('models/Black_Hole.jpg') #self.hole.setTexture(tex, 1) self.holeRoot.hide() ct = CollisionTube(0, 0, 0, 0, 0.001, 0, 0.5) self.holeTube = self.hole.attachNewNode(CollisionNode('hole')) self.holeTube.node().addSolid(ct) self.holeTube.node().setFromCollideMask(BitMask32.allOff()) self.holeTube.node().setIntoCollideMask(BitMask32.bit(4)) #self.holeTube.show() inPortalPos, inPortalHpr, outPortalPos, outPortalHpr, self.portalNormal = self.planeInfo.getPortalPos( ) self.portalLength = 0.06 self.inPortalRoot = render.attachNewNode("inPortalRoot") self.inPortal = loader.loadModel("models/portal_2_center.egg") self.inPortal.setScale(self.portalLength, self.portalLength, self.portalLength) self.inPortal.reparentTo(self.inPortalRoot) self.inPortalRoot.setPos(inPortalPos[0], inPortalPos[1], inPortalPos[2]) self.inPortalRoot.setHpr(inPortalHpr[0], inPortalHpr[1], inPortalHpr[2]) self.inPortalRoot.hide() ct = CollisionTube(0, 0, 0, 0, 0.001, 0, 1) self.inPortalTube = self.inPortal.attachNewNode( CollisionNode('portal_in')) self.inPortalTube.node().addSolid(ct) self.inPortalTube.node().setFromCollideMask(BitMask32.allOff()) self.inPortalTube.node().setIntoCollideMask(BitMask32.bit(3)) #self.inPortalTube.hide() self.outPortalRoot = render.attachNewNode("outPortalRoot") self.outPortal = loader.loadModel("models/portal_2_center.egg") self.outPortal.setScale(self.portalLength, self.portalLength, self.portalLength) self.outPortal.reparentTo(self.outPortalRoot) self.outPortalRoot.setPos(outPortalPos[0], outPortalPos[1], outPortalPos[2]) self.outPortalRoot.setHpr(outPortalHpr[0], outPortalHpr[1], outPortalHpr[2]) self.outPortalRoot.hide() ct = CollisionTube(0, 0, 0, 0, 0.001, 0, 1) self.outPortalTube = self.outPortal.attachNewNode( CollisionNode('portal_out')) self.outPortalTube.node().addSolid(ct) self.outPortalTube.node().setFromCollideMask(BitMask32.allOff()) self.outPortalTube.node().setIntoCollideMask(BitMask32.bit(3)) #self.outPortalTube.hide() #self.inPortalTube.show() #self.outPortalTube.show() #self.holeTube.show() #self.cTrav.addCollider(self.holeTube, self.cHandler) background_image = loader.loadTexture('dump/' + str(self.sceneIndex) + '_image.png') cm = CardMaker('background') cm.setHas3dUvs(True) info = np.load('dump/' + str(self.sceneIndex) + '_info.npy') #self.camera = getCameraFromInfo(self.info) depth = 10.0 sizeU = info[2] / info[0] * depth sizeV = info[6] / info[5] * depth cm.setFrame(Point3(-sizeU, depth, -sizeV), Point3(sizeU, depth, -sizeV), Point3(sizeU, depth, sizeV), Point3(-sizeU, depth, sizeV)) self.card = self.render.attachNewNode(cm.generate()) self.card.setTransparency(True) self.card.setTexture(background_image) self.card.hide() self.ballGroundMap = {} self.ballBouncing = np.full(len(self.balls), 3) self.started = False self.start() self.hitIndex = 0 self.showing = 'none' self.showingProgress = 0 partsScene = PartsScene(self.sceneIndex) self.planeNPs, self.planeCenters = partsScene.generateEggModel() return def start(self): #startPos = self.maze.find("**/start").getPos() #self.ballRoot.setPos(0.5, 0, 0) #self.ballV = LVector3(0, 0.5, 0) # Initial velocity is 0 #self.accelV = LVector3(0, 0, 0) # Initial acceleration is 0 self.ballVs = [] self.accelVs = [] for ballIndex in xrange(len(self.balls)): self.ballVs.append(LVector3(0, 0, 0)) self.accelVs.append(LVector3(0, 0, 0)) continue self.ballRoots[0].setPos(0.2, 1.05, -0.1) #self.ballVs[0] = LVector3(0, 0.0, 0) self.ballRoots[1].setPos(0.32, 1.2, -0.1) #self.ballRoots[2].setHpr(0, 0, 90) self.ballRoots[2].setPos(-0.4, 1.1, 0.4) axis = LVector3.up() prevRot = LRotationf(self.balls[2].getQuat()) newRot = LRotationf(axis, 90) self.balls[2].setQuat(prevRot * newRot) # Create the movement task, but first make sure it is not already # running taskMgr.remove("rollTask") #taskMgr.remove("mouseTask") self.mainLoop = taskMgr.add(self.rollTask, "rollTask") #self.mainLoop = taskMgr.add(self.mouseTask, "mouseTask") return def hit(self): if self.cuePos[0] < 5: cueDirection = self.ballRoots[0].getPos() - LVector3( self.cuePos[0], self.cuePos[1], self.cuePos[2]) #power = cueDirection.length() cueDirection = cueDirection / cueDirection.length() if self.hitIndex < 0: self.ballVs[0] = cueDirection * self.cuePower * 8 elif self.hitIndex == 0: self.ballVs[0] = LVector3(0.5, 0.47, 0) self.hitIndex += 1 elif self.hitIndex == 1: self.ballVs[0] = LVector3(0.072, 0.62, 0) self.hitIndex += 1 elif self.hitIndex == 2: self.ballVs[0] = LVector3(0.7, 0.0, 0) self.hitIndex += 1 pass self.started = True print('hit', cueDirection) self.ballBouncing = np.full(len(self.balls), 3) pass # This function handles the collision between the ball and a wall def planeCollideHandler(self, colEntry): #return ballName = colEntry.getFromNode().getName() ballIndex = int(ballName[5:]) # First we calculate some numbers we need to do a reflection # print(colEntry) # name = colEntry.getIntoNode().getName() # triangleIndex = int(name[4:]) # print(triangleIndex) # print(self.planeNormals[triangleIndex]) # print(colEntry.getSurfaceNormal(render)) # exit(1) norm = colEntry.getSurfaceNormal(render) * -1 # The normal of the wall norm.normalize() curSpeed = self.ballVs[ballIndex].length() # The current speed inVec = self.ballVs[ballIndex] / curSpeed # The direction of travel velAngle = norm.dot(inVec) # Angle of incidance hitDir = colEntry.getSurfacePoint( render) - self.ballRoots[ballIndex].getPos() hitDir.normalize() # The angle between the ball and the normal hitAngle = norm.dot(hitDir) # Ignore the collision if the ball is either moving away from the wall # already (so that we don't accidentally send it back into the wall) # and ignore it if the collision isn't dead-on (to avoid getting caught on # corners) #print(velAngle, hitAngle) if velAngle > 0 and hitAngle > .995: print('plane', ballName, velAngle) # Standard reflection equation reflectVec = (norm * norm.dot(inVec * -1) * 2) + inVec # This makes the velocity half of what it was if the hit was dead-on # and nearly exactly what it was if this is a glancing blow #self.ballVs[ballIndex] = reflectVec * (curSpeed * (((1 - velAngle) * .5) + .5)) self.ballVs[ballIndex] = reflectVec * curSpeed # Since we have a collision, the ball is already a little bit buried in # the wall. This calculates a vector needed to move it so that it is # exactly touching the wall disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) newPos = self.ballRoots[ballIndex].getPos() + disp self.ballRoots[ballIndex].setPos(newPos) pass return # This function handles the collision between the ball and a wall def portal(self, colEntry): ballName = colEntry.getFromNode().getName() print('portal', ballName) ballIndex = int(ballName[5:]) #norm = colEntry.getSurfaceNormal(render) * -1 # The normal of the wall norm = LVector3(self.portalNormal[0], self.portalNormal[1], self.portalNormal[2]) norm.normalize() curSpeed = self.ballVs[ballIndex].length() # The current speed inVec = self.ballVs[ballIndex] / curSpeed # The direction of travel velAngle = norm.dot(inVec) # Angle of incidance hitDir = colEntry.getSurfacePoint( render) - self.ballRoots[ballIndex].getPos() hitDir.normalize() # The angle between the ball and the normal #print(colEntry.getSurfacePoint(render), self.ballRoots[ballIndex].getPos()) #print(norm, hitDir) hitAngle = norm.dot(hitDir) # Ignore the collision if the ball is either moving away from the wall # already (so that we don't accidentally send it back into the wall) # and ignore it if the collision isn't dead-on (to avoid getting caught on # corners) #print(velAngle, hitAngle) #print(velAngle, hitAngle) if velAngle > 0: print(colEntry.getIntoNode().getName()) if '_in' in colEntry.getIntoNode().getName(): self.ballRoots[ballIndex].setPos(self.outPortalRoot.getPos()) else: self.ballRoots[ballIndex].setPos(self.inPortalRoot.getPos()) pass print(self.ballVs[ballIndex], ((norm * norm.dot(inVec * -1) * 2) + inVec) * curSpeed, norm) #exit(1) self.ballVs[ballIndex] = ( (norm * norm.dot(inVec * -1) * 2) + inVec) * curSpeed #self.ballVs[ballIndex] *= -1 pass return # This function handles the collision between the ball and a wall def ballCollideHandler(self, colEntry): # First we calculate some numbers we need to do a reflection fromBallName = colEntry.getFromNode().getName() fromBallIndex = int(fromBallName[5:]) #if fromBallIndex != 0: #return intoBallName = colEntry.getIntoNode().getName() intoBallIndex = int(intoBallName[5:]) print('ball', fromBallName, intoBallName) norm = colEntry.getSurfaceNormal(render) * -1 # The normal of the wall norm = norm / norm.length() curSpeed = self.ballVs[fromBallIndex].length() # The current speed inVec = self.ballVs[fromBallIndex] / curSpeed # The direction of travel velAngle = norm.dot(inVec) # Angle of incidance hitDir = colEntry.getSurfacePoint( render) - self.ballRoots[fromBallIndex].getPos() hitDir.normalize() # The angle between the ball and the normal hitAngle = norm.dot(hitDir) # print(norm) # print(self.ballVs[fromBallIndex]) # print(velAngle, hitAngle) # print(self.ballRoots[fromBallIndex].getPos()) # print(self.ballRoots[intoBallIndex].getPos()) # exit(1) #print(fromBallIndex, intoBallIndex) #exit(1) # Ignore the collision if the ball is either moving away from the wall # already (so that we don't accidentally send it back into the wall) # and ignore it if the collision isn't dead-on (to avoid getting caught on # corners) #print(velAngle, hitAngle) if velAngle > 0 and hitAngle > .995: # Standard reflection equation self.ballVs[fromBallIndex] = ( (norm * norm.dot(inVec * -1)) + inVec) * curSpeed disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) newPos = self.ballRoots[fromBallIndex].getPos() + disp self.ballRoots[fromBallIndex].setPos(newPos) self.ballVs[intoBallIndex] = norm * norm.dot(inVec) * curSpeed pass return def groundCollideHandler(self, colEntry): # Set the ball to the appropriate Z value for it to be exactly on the # ground ballName = colEntry.getFromNode().getName() if 'mouseRay' in ballName: for v in self.ballVs: if v.length() > 1e-4: self.cuePos = (10, 0, 0) return continue #print(self.mouseWatcherNode.hasMouse()) norm = colEntry.getSurfaceNormal(render) norm.normalize() touchPoint = colEntry.getSurfacePoint(render) cuePoint = touchPoint + norm * self.ballSize cueDirection = self.ballRoots[0].getPos() - cuePoint self.cuePower = cueDirection.length() cueDirection = cueDirection / cueDirection.length() cuePoint = self.ballRoots[0].getPos( ) - cueDirection * self.cueLength self.cuePos = cuePoint #self.cueRoot.setH(np.rad2deg(np.arctan2(cueDirection[1], cueDirection[0])) + 90) self.cueRoot.setH( np.rad2deg(np.arctan2(cueDirection[1], cueDirection[0])) + 90) self.cueRoot.setP(-np.rad2deg(np.arcsin(cueDirection[2])) + 90) #self.cueRoot.setP(90) #print(np.rad2deg(np.arctan2(cueDirection[1], cueDirection[0])), np.rad2deg(np.arcsin(cueDirection[2]))) # prevRot = LRotationf(self.cue.getQuat()) # axis = LVector3.up().cross(self.ballVs[ballIndex]) # newRot = LRotationf(axis, 45.5 * dt * self.ballVs[ballIndex].length()) # self.balls[ballIndex].setQuat(prevRot * newRot) return #print('ground', ballName) #print(ballName, colEntry.getIntoNode().getName()) #print(colEntry.getFromNode().getBitMask(), colEntry.getIntoNode().getBitMask()) ballIndex = int(ballName[9:]) groundName = colEntry.getIntoNode().getName() groundIndex = int(groundName[7:]) #print(groundIndex) #print(self.ballGroundMap) if ballIndex == 0 and False: print(groundIndex, self.ballGroundMap) pass if ballIndex not in self.ballGroundMap or self.ballGroundMap[ ballIndex][0] != groundIndex: return norm = -colEntry.getSurfaceNormal(render) norm = norm / norm.length() curSpeed = self.ballVs[ballIndex].length() # The current speed inVec = self.ballVs[ballIndex] / max(curSpeed, 1e-4) # The direction of travel velAngle = norm.dot(inVec) # Angle of incidance hitDir = colEntry.getSurfacePoint( render) - self.ballRoots[ballIndex].getPos() hitDir.normalize() # The angle between the ball and the normal hitAngle = norm.dot(hitDir) surfacePos = colEntry.getSurfacePoint(render) ballPos = self.ballRoots[ballIndex].getPos() surfacePos = ballPos + norm * norm.dot(surfacePos - ballPos) distance = norm.dot(surfacePos - ballPos) if distance < 0: return if distance < self.ballSize + 1e-3: self.ballRoots[ballIndex].setPos(surfacePos - norm * self.ballSize) if self.ballVs[ballIndex].length() > 1e-2: self.ballVs[ballIndex] = (-norm * velAngle + inVec) * curSpeed #self.ballVs[ballIndex] = -norm.cross(norm.cross(self.ballVs[ballIndex])) self.accelVs[ballIndex] = -self.ballVs[ ballIndex] / self.ballVs[ballIndex].length() * 0.0025 else: self.ballVs[ballIndex] = LVector3(0, 0, 0) self.accelVs[ballIndex] = LVector3(0, 0, 0) pass else: self.accelVs[ ballIndex] = self.accelVs[ballIndex] - norm * norm.dot( self.accelVs[ballIndex]) + norm * 0.05 pass return # if self.started: # if abs(distance - self.ballSize) > 0.001 and abs(distance - self.ballSize) < self.ballSize: # self.ballRoots[ballIndex].setPos(surfacePos - norm * self.ballSize) # pass # self.ballVs[ballIndex] = -norm.cross(norm.cross(self.ballVs[ballIndex])) # if self.ballVs[ballIndex].length() > 1e-3: # self.accelVs[ballIndex] = -self.ballVs[ballIndex] / self.ballVs[ballIndex].length() * 0.015 # else: # self.ballVs[ballIndex] = LVector3(0, 0, 0) # self.accelVs[ballIndex] = LVector3(0, 0, 0) # pass # #print(self.ballVs[ballIndex], self.accelVs[ballIndex]) # #print(surfacePos - norm * self.ballSize) # return if ballIndex == 0: print('distance_1', self.started, distance, velAngle, self.ballVs[ballIndex], self.accelVs[ballIndex]) if distance < self.ballSize: self.ballRoots[ballIndex].setPos(surfacePos - norm * self.ballSize) if velAngle > 0 and hitAngle > .995: if abs(velAngle * curSpeed) < 0.2: if ((-norm * velAngle + inVec) * curSpeed).length() < 0.02: self.ballVs[ballIndex] = LVector3(0, 0, 0) self.accelVs[ballIndex] = LVector3(0, 0, 0) pass pass else: if self.ballBouncing[ballIndex] > 0: if ballIndex == 0: print('bouncing') pass self.ballVs[ballIndex] = ( -norm * velAngle + inVec ) * curSpeed * 0.5 - norm * velAngle * curSpeed * 0.25 self.accelVs[ballIndex] = LVector3(0, 0, 0) self.ballBouncing[ballIndex] -= 1 else: self.ballVs[ballIndex] = (-norm * velAngle + inVec) * curSpeed self.accelVs[ballIndex] = LVector3(0, 0, 0) pass pass pass pass if (distance - self.ballSize) > 0.001: self.accelVs[ ballIndex] = self.accelVs[ballIndex] - norm * norm.dot( self.accelVs[ballIndex]) + norm * 0.1 # print(self.accelVs[ballIndex] - norm * norm.dot(self.accelVs[ballIndex])) # print(norm) # print(inVec) # print(velAngle) # print(-norm * velAngle + inVec) # print(norm * 0.01) # exit(1) elif distance - self.ballSize > -0.001: if self.ballVs[ballIndex].length() < 0.001: #print('stop', self.ballVs[ballIndex], self.accelVs[ballIndex]) self.ballVs[ballIndex] = LVector3(0, 0, 0) self.accelVs[ballIndex] = LVector3(0, 0, 0) self.started = False else: if abs(velAngle) < 1e-3: self.ballVs[ballIndex] = (-norm * velAngle + inVec) * curSpeed #self.ballVs[ballIndex] = -norm.cross(norm.cross(self.ballVs[ballIndex])) self.accelVs[ballIndex] = -self.ballVs[ ballIndex] / self.ballVs[ballIndex].length() * 0.01 #print('speed', self.ballVs[ballIndex], self.accelVs[ballIndex]) pass pass pass # #print(distance - self.ballSize) # if (distance - self.ballSize) > 0.01: # self.accelVs[ballIndex] = self.accelVs[ballIndex] - norm * norm.dot(self.accelVs[ballIndex]) + norm * 0.01 # #if ballIndex == 0: # #print(velAngle, self.ballVs[ballIndex], self.accelVs[ballIndex], norm) # #pass # print('fall', self.accelVs[ballIndex], distance) # # print(self.accelVs[ballIndex] - norm * norm.dot(self.accelVs[ballIndex])) # # print(norm) # # print(inVec) # # print(velAngle) # # print(-norm * velAngle + inVec) # # print(norm * 0.01) # # exit(1) # else: # #hitAngle > .995 # #print(velAngle) # #print(norm) # #self.ballRoots[ballIndex].setPos(surfacePos - norm * self.ballSize) # if curSpeed > 1e-1: # print('angle', velAngle, norm) # self.norm = norm # pass # if velAngle > 1e-3: # if curSpeed < 1e-3: # self.ballVs[ballIndex] = LVector3(0, 0, 0) # self.accelVs[ballIndex] = LVector3(0, 0, 0) # self.ballRoots[ballIndex].setPos(surfacePos - norm * self.ballSize) # else: # self.ballVs[ballIndex] = (-norm * velAngle + inVec) * curSpeed * 0.9 - norm * velAngle * curSpeed * 0.25 # self.accelVs[ballIndex] = LVector3(0, 0, 0) # pass # #print((-norm * velAngle + inVec) * curSpeed * 0.9, norm * velAngle * curSpeed * 0.25) # #print(curSpeed, norm.dot(self.ballVs[ballIndex]) / self.ballVs[ballIndex].length(), self.ballVs[ballIndex], self.accelVs[ballIndex]) # #print(norm.dot(self.ballVs[ballIndex]) / self.ballVs[ballIndex].length(), norm.dot(self.accelVs[ballIndex]) / self.accelVs[ballIndex].length(), self.ballVs[ballIndex], self.accelVs[ballIndex]) # elif velAngle > -1e-3: # if self.ballVs[ballIndex].length() < 0.001: # #self.ballVs[ballIndex] = LVector3(0, 0, 0) # #self.accelVs[ballIndex] = LVector3(0, 0, 0) # #print('stop', self.ballVs[ballIndex], self.accelVs[ballIndex]) # pass # else: # #self.ballVs[ballIndex] = (-norm * velAngle + inVec) * curSpeed * 0.9 # #print(self.ballVs[ballIndex], self.accelVs[ballIndex]) # self.accelVs[ballIndex] = -(-norm * velAngle + inVec) * 0.1 # print('accel', self.accelVs[ballIndex]) # pass # pass # else: # #print('stop', self.ballVs[ballIndex], self.accelVs[ballIndex]) # #self.ballVs[ballIndex] = LVector3(0, 0, 0) # #self.accelVs[ballIndex] = LVector3(0, 0, 0) # pass # pass return # This is the task that deals with making everything interactive def rollTask(self, task): # Standard technique for finding the amount of time since the last # frame dt = globalClock.getDt() # If dt is large, then there has been a # hiccup that could cause the ball # to leave the field if this functions runs, so ignore the frame if dt > .2: return Task.cont # if base.mouseWatcherNode.is_button_down('a'): # self.holeRoot.setH(self.holeRoot.getH() + 1) # print(self.holeRoot.getHpr()) # pass # if base.mouseWatcherNode.is_button_down('s'): # self.holeRoot.setP(self.holeRoot.getP() + 1) # print(self.holeRoot.getHpr()) # pass # if base.mouseWatcherNode.is_button_down('d'): # self.holeRoot.setR(self.holeRoot.getR() + 1) # print(self.holeRoot.getHpr()) # pass if base.mouseWatcherNode.is_button_down( 'space') and self.showing == 'none': self.showing = 'parts' #self.showingProgress = 0 pass #print(self.showing) #print(self.showing) if self.showing == 'none': return Task.cont if self.showing == 'parts': self.showingProgress += 0.01 #self.showingProgress += 1 print(self.showingProgress) scale = 2 - self.showingProgress scaleY = 1 + (scale - 1) * 0.5 for planeIndex, planeNP in enumerate(self.planeNPs): center = self.planeCenters[planeIndex] planeNP.setPos(center[0] * scale, center[1] * scaleY, center[2] * scale) planeNP.reparentTo(self.render) planeNP.setTwoSided(True) continue if self.showingProgress > 1: self.showing = 'moving' for planeIndex, planeNP in enumerate(self.planeNPs): planeNP.removeNode() continue self.planeScene.show() self.showingProgress = 0 return Task.cont if self.showing == 'moving': self.showingProgress += 0.005 #self.showingProgress += 1 #print(self.showingProgress, np.sign(self.showingProgress - 0.5) * min(self.showingProgress % 0.5, 0.5 - self.showingProgress % 0.5) * 4) self.camera.setPos( np.sign(self.showingProgress - 0.5) * min(self.showingProgress % 0.5, 0.5 - self.showingProgress % 0.5) * 3, 0, 0) #self.camera.setHpr(angleDegrees, 0, 0) #self.camera.lookAt(0, 0, 0) self.camera.lookAt(0, 3, 0) if self.showingProgress > 1: self.showing = 'geometry' self.camera.setPos(0, 0, 0) #self.planeScene.removeNode() # for triNP in self.triNPs: # triNP.show() # continue self.showingProgress = 1 return Task.cont if self.showing == 'geometry': self.showingProgress += 0.02 if self.showingProgress > 1: #self.showing = 'image' self.showing = 'placement' self.showingProgress = 0 self.holeRoot.show() self.inPortalRoot.show() self.outPortalRoot.show() self.inPortalTube.show() self.outPortalTube.show() for ballRoot in self.ballRoots: ballRoot.show() continue self.showingProgress = 0 pass return Task.cont # if self.showing == 'placement': # self.showingProgress += 0.005 # continue if self.mouseWatcherNode.hasMouse(): mpos = self.mouseWatcherNode.getMouse() self.mpos = mpos self.pickerRay.setFromLens(self.camNode, mpos.getX(), mpos.getY()) pass if base.mouseWatcherNode.is_button_down( 'space') and self.showing == 'placement': self.card.show() self.planeScene.removeNode() self.showing = 'image' pass # if base.mouseWatcherNode.is_button_down('space') and self.showing == 'image': # for triNP in self.triNPs: # triNP.hide() # continue # self.showing = 'start' # pass # The collision handler collects the collisions. We dispatch which function # to handle the collision based on the name of what was collided into self.ballGroundMap = {} for i in range(self.cHandler.getNumEntries()): entry = self.cHandler.getEntry(i) ballName = entry.getFromNode().getName() groundName = entry.getIntoNode().getName() if 'ball_ray_' not in ballName: continue if 'ground_' not in groundName: continue ballIndex = int(ballName[9:]) groundIndex = int(groundName[7:]) norm = -entry.getSurfaceNormal(render) if norm.length() == 0: continue norm = norm / norm.length() distance = norm.dot( entry.getSurfacePoint(render) - self.ballRoots[ballIndex].getPos()) #print(distance) if distance < 0: continue if ballIndex not in self.ballGroundMap or distance < self.ballGroundMap[ ballIndex][1]: self.ballGroundMap[ballIndex] = (groundIndex, distance) pass continue for i in range(self.cHandler.getNumEntries()): entry = self.cHandler.getEntry(i) fromName = entry.getFromNode().getName() #if 'mouseRay' in fromName: #continue name = entry.getIntoNode().getName() #if name == "plane_collide": if 'tri_' in name: self.planeCollideHandler(entry) #elif name == "wall_collide": #self.wallCollideHandler(entry) #elif name == "ground_collide": #self.groundCollideHandler(entry) elif 'ball_' in name: self.ballCollideHandler(entry) elif 'ground_' in name: self.groundCollideHandler(entry) elif 'hole' in name: self.score(entry) elif 'portal_' in name: self.portal(entry) pass continue # Read the mouse position and tilt the maze accordingly if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() # get the mouse position #self.maze.setP(mpos.getY() * -10) #self.maze.setR(mpos.getX() * 10) pass # if base.mouseWatcherNode.is_button_down('mouse1'): # print(base.mouseWatcherNode.getMouseX()) # print(base.mouseWatcherNode.getMouseY()) # exit(1) # Finally, we move the ball # Update the velocity based on acceleration for ballIndex in xrange(len(self.balls)): if self.ballVs[ballIndex].length( ) < 1e-4 and self.ballVs[ballIndex].dot( self.accelVs[ballIndex]) < -1e-4: self.ballVs[ballIndex] = LVector3(0, 0, 0) self.accelVs[ballIndex] = LVector3(0, 0, 0) else: self.ballVs[ballIndex] += self.accelVs[ballIndex] * dt * ACCEL pass #print('current speed', self.ballVs[ballIndex], self.accelVs[ballIndex]) # Clamp the velocity to the maximum speed if self.ballVs[ballIndex].lengthSquared() > MAX_SPEED_SQ: self.ballVs[ballIndex].normalize() self.ballVs[ballIndex] *= MAX_SPEED pass #print(self.ballVs[ballIndex], self.accelVs[ballIndex], self.ballRoots[ballIndex].getPos()) # Update the position based on the velocity self.ballRoots[ballIndex].setPos( self.ballRoots[ballIndex].getPos() + (self.ballVs[ballIndex] * dt)) # This block of code rotates the ball. It uses something called a quaternion # to rotate the ball around an arbitrary axis. That axis perpendicular to # the balls rotation, and the amount has to do with the size of the ball # This is multiplied on the previous rotation to incrimentally turn it. prevRot = LRotationf(self.balls[ballIndex].getQuat()) axis = LVector3.up().cross(self.ballVs[ballIndex]) newRot = LRotationf( axis, np.rad2deg(dt * self.ballVs[ballIndex].length() / self.ballSize)) self.balls[ballIndex].setQuat(prevRot * newRot) continue self.cueRoot.setPos(self.cuePos[0], self.cuePos[1], self.cuePos[2]) return Task.cont # Continue the task indefinitely def score(self, colEntry): ballName = colEntry.getFromNode().getName() if 'ball_' not in ballName: return print('score', ballName) ballIndex = int(ballName[5:]) self.ballRoots[ballIndex].removeNode() del self.ballRoots[ballIndex] del self.balls[ballIndex] del self.ballSpheres[ballIndex] del self.ballGroundRays[ballIndex] del self.ballVs[ballIndex] del self.accelVs[ballIndex] for otherIndex in xrange(ballIndex, len(self.balls)): self.ballSpheres[otherIndex].setName('ball_' + str(otherIndex)) self.ballGroundRays[otherIndex].setName('ball_ray_' + str(otherIndex)) continue return # If the ball hits a hole trigger, then it should fall in the hole. # This is faked rather than dealing with the actual physics of it. def loseGame(self, entry): # The triggers are set up so that the center of the ball should move to the # collision point to be in the hole toPos = entry.getInteriorPoint(render) taskMgr.remove('rollTask') # Stop the maze task # Move the ball into the hole over a short sequence of time. Then wait a # second and call start to reset the game Sequence( Parallel( LerpFunc(self.ballRoot.setX, fromData=self.ballRoot.getX(), toData=toPos.getX(), duration=.1), LerpFunc(self.ballRoot.setY, fromData=self.ballRoot.getY(), toData=toPos.getY(), duration=.1), LerpFunc(self.ballRoot.setZ, fromData=self.ballRoot.getZ(), toData=self.ballRoot.getZ() - .9, duration=.2)), Wait(1), Func(self.start)).start()
class GameContainer(ShowBase): def __init__(self): ShowBase.__init__(self) ########## Window configuration ######### wp = WindowProperties() wp.setSize(1024, 860) wp.setTitle("") wp.setOrigin(-2, -2) self.win.requestProperties(wp) self.win.movePointer(0, wp.getXSize() / 2, wp.getYSize() / 2) print wp.getXSize() / 2, wp.getYSize() / 2 ########## Gameplay settings ######### self.gameMode = {"display": PLAY, "play": TERRAIN} self.level = 1.5 self.mode_initialized = False ######### Camera ######### self.disableMouse() self.mainCamera = Camera(self.camera) self.mainCamera.camObject.setHpr(0, 0, 0) self.loadLevel() ######### Events ######### self.taskMgr.add(self.gameLoop, "gameLoop", priority=35) self.keys = {"w": 0, "s": 0, "a": 0, "d": 0, "space": 0, "escape": 0} self.accept("w", self.setKey, ["w", 1]) self.accept("w-up", self.setKey, ["w", 0]) self.accept("s", self.setKey, ["s", 1]) self.accept("s-up", self.setKey, ["s", 0]) self.accept("a", self.setKey, ["a", 1]) self.accept("a-up", self.setKey, ["a", 0]) self.accept("d", self.setKey, ["d", 1]) self.accept("d-up", self.setKey, ["d", 0]) self.accept("space", self.setKey, ["space", 1]) self.accept("space-up", self.setKey, ["space", 0]) self.accept("escape", self.setKey, ["escape", 1]) self.accept("escape-up", self.setKey, ["escape", 0]) self.accept("wheel_up", self.zoomCamera, [-1]) self.accept("wheel_down", self.zoomCamera, [1]) self.accept("window-event", self.handleWindowEvent) ######### GUI ######### #self.fonts = {"failure" : loader.loadFont('myfont.ttf')} self.guiElements = [] self._GCLK = None self._FT = None #Trigger game chain #self.enableParticles() #self.buildMainMenu() def setKey(self, key, value): self.keys[key] = value def zoomCamera(self, direction): if self.gameMode["play"] == TERRAIN: Camera.AVATAR_DIST += direction def toggleCursor(self, state): props = WindowProperties() props.setCursorHidden(state) base.win.requestProperties(props) def handleWindowEvent(self, window=None): wp = window.getProperties() self.win_center_x = wp.getXSize() / 2 self.win_center_y = wp.getYSize() / 2 def processKeys(self): if self.keys["escape"]: if self.gameMode["display"] == PLAY: self.switchDisplayMode(IN_GAME_MENU) elif self.gameMode["display"] == IN_GAME_MENU: self.switchDisplayMode(PLAY) self.setKey("escape", 0) ######### Level specific features ######### def maintainTurrets(self): pass def switchDisplayMode(self, newGameMode): self.cleanupGUI() if self.gameMode["display"] == MAIN_MENU: pass elif self.gameMode["display"] == IN_GAME_MENU: if newGameMode == PLAY: render.clearFog() self.togglePhysicsPause() elif newGameMode == MAIN_MENU: pass elif self.gameMode["display"] == PLAY: if newGameMode == IN_GAME_MENU: self.togglePhysicsPause() self.gameMode["display"] = newGameMode self.mode_initialized = False def advanceLevel(self): self.level += .5 self.loadLevel() def evenButtonPositions(self, button_spacing, button_height, num_buttons): centerOffset = (button_spacing / (2.0) if (num_buttons % 2 == 0) else 0) buttonPositions = [] current_pos = centerOffset + ((num_buttons - 1) / 2) * button_spacing for i in range(0, num_buttons): buttonPositions.append(current_pos + (button_height / 2.0)) current_pos -= button_spacing return buttonPositions def buildInGameMenu(self): self.toggleCursor(False) resume_button = DirectButton( text="Resume", scale=.1, command=(lambda: self.switchDisplayMode(PLAY)), rolloverSound=None) main_menu_button = DirectButton(text="Main Menu", scale=.1, command=None, rolloverSound=None) options_button = DirectButton(text="Settings", scale=.1, command=None, rolloverSound=None) exit_button = DirectButton(text="Exit", scale=.1, command=exit, rolloverSound=None) BUTTON_SPACING = .2 BUTTON_HEIGHT = resume_button.getSy() button_positions = self.evenButtonPositions(BUTTON_SPACING, BUTTON_HEIGHT, 4) resume_button.setPos(Vec3(0, 0, button_positions[0])) main_menu_button.setPos(Vec3(0, 0, button_positions[1])) options_button.setPos(Vec3(0, 0, button_positions[2])) exit_button.setPos(Vec3(0, 0, button_positions[3])) self.guiElements.append(resume_button) self.guiElements.append(main_menu_button) self.guiElements.append(options_button) self.guiElements.append(exit_button) def buildMainMenu(self): self.toggleCursor(False) start_game_button = DirectButton(text="Start", scale=.1, command=None) select_level_button = DirectButton(text="Select Level", scale=.1, command=None) game_options_button = DirectButton(text="Settings", scale=.1, command=None) exit_button = DirectButton(text="Exit", scale=.1, command=exit) BUTTON_SPACING = .2 BUTTON_HEIGHT = start_game_button.getSy() button_positions = self.evenButtonPositions(BUTTON_SPACING, BUTTON_HEIGHT, 4) start_game_button.setPos(Vec3(0, 0, button_positions[0])) select_level_button.setPos(Vec3(0, 0, button_positions[1])) game_options_button.setPos(Vec3(0, 0, button_positions[2])) exit_button.setPos(Vec3(0, 0, button_positions[3])) self.guiElements.append(start_game_button) self.guiElements.append(select_level_button) self.guiElements.append(game_options_button) self.guiElements.append(exit_button) particles = Particles() particles.setPoolSize(1000) particles.setBirthRate(.1) particles.setLitterSize(10) particles.setLitterSpread(3) particles.setFactory("PointParticleFactory") particles.setRenderer("PointParticleRenderer") particles.setEmitter("SphereVolumeEmitter") particles.enable() self.effect = ParticleEffect("peffect", particles) self.effect.reparentTo(render) #self.effect.setPos(self.avatar.objectNP.getX(), self.avatar.objectNP.getY(), self.avatar.objectNP.getZ() + 5) self.effect.setPos(-1, 0, 0) self.effect.enable() def buildDeathScreen(self): self.toggleCursor(False) backFrame = DirectFrame(frameColor=(1, 0, 0, .7), frameSize=(-.5, .5, -.3, .3), pos=(0, 0, 0)) deadMessage = DirectLabel(text="MISSION FAILURE", scale=.1, pos=(0, 0, .16), relief=None, text_font=None) restartButton = DirectButton(text="Restart", scale=.1, pos=(0, 0, -.1), command=self.resetLevel) deadMessage.reparentTo(backFrame) restartButton.reparentTo(backFrame) self.guiElements.append(backFrame) self.guiElements.append(deadMessage) self.guiElements.append(restartButton) def cleanupGUI(self): for guiElement in self.guiElements: guiElement.destroy() def loadSpaceTexture(self, level): if level < 10: return 'textures/space#.jpg' elif level < 15: pass def resetLevel(self): self.switchDisplayMode(PLAY) self.loadLevel(True) def loadLevel(self, reset=False): #Resets self.avatarActor = Actor("models/panda", {"walk": "models/panda-walk"}) self.avatarActor.setScale(.5, .5, .5) self.avatarActor.setHpr(180, 0, 0) self.avatarActor.setCollideMask(BitMask32.allOff()) self.asteroidManager = AsteroidManager() self.cTrav = CollisionTraverser() #Alternate modes if int(self.level) == self.level: self.gameMode["play"] = TERRAIN else: self.gameMode["play"] = SPACE #Specifics if self.gameMode["play"] == SPACE: if reset: self.avatar.reset() else: self.avatar = Avatar(self.avatarActor, self.level) self.avatar.objectNP.reparentTo(render) ########## Sky ######### cubeMap = loader.loadCubeMap(self.loadSpaceTexture(self.level)) self.spaceSkyBox = loader.loadModel('models/box') self.spaceSkyBox.setScale(100) self.spaceSkyBox.setBin('background', 0) self.spaceSkyBox.setDepthWrite(0) self.spaceSkyBox.setTwoSided(True) self.spaceSkyBox.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldCubeMap) self.spaceSkyBox.setTexture(cubeMap, 1) parentNP = render.attachNewNode('parent') self.spaceSkyBox.reparentTo(parentNP) self.spaceSkyBox.setPos(-self.spaceSkyBox.getSx() / 2, -self.spaceSkyBox.getSy() / 2, -self.spaceSkyBox.getSz() / 2) ########## Collisions ######### bound = self.avatarActor.getBounds() self.pandaBodySphere = CollisionSphere( bound.getCenter()[0] / self.avatar.objectNP.getSx() - self.avatar.objectNP.getX(), bound.getCenter()[1] / self.avatar.objectNP.getSx() - self.avatar.objectNP.getY(), bound.getCenter()[2] / self.avatar.objectNP.getSx() - self.avatar.objectNP.getZ(), 5) self.pandaBodySphere.setRadius(bound.getRadius() + 1) self.pandaBodySphereNode = CollisionNode("playerBodyRay") self.pandaBodySphereNode.addSolid(self.pandaBodySphere) self.pandaBodySphereNode.setFromCollideMask(BitMask32.bit(0)) self.pandaBodySphereNode.setIntoCollideMask(BitMask32.allOff()) self.pandaBodySphereNodepath = self.avatar.objectNP.attachNewNode( self.pandaBodySphereNode) self.pandaBodySphereNodepath.show() self.collisionNotifier = CollisionHandlerEvent() self.collisionNotifier.addInPattern("%fn-in") self.collisionNotifier.addOutPattern("%fn-out") self.cTrav.addCollider(self.pandaBodySphereNodepath, self.collisionNotifier) self.accept("playerGroundRayJumping-in", self.avatar.handleCollisionEvent, ["in"]) self.accept("playerGroundRayJumping-out", self.avatar.handleCollisionEvent, ["out"]) self.accept("playerBodyRay-in", self.avatar.handleCollisionEvent, ["in"]) self.asteroidManager.initialize(self.level) elif self.gameMode["play"] == TERRAIN: ########## Terrain ######### #self.environ = loader.loadModel("../mystuff/test.egg") self.environ = loader.loadModel("models/environment") self.environ.setName("terrain") self.environ.reparentTo(render) self.environ.setPos(0, 0, 0) self.environ.setCollideMask(BitMask32.bit(0)) ######### Physics ######### self.enableParticles() gravityForce = LinearVectorForce(0, 0, -9.81) gravityForce.setMassDependent(False) gravityFN = ForceNode("world-forces") gravityFN.addForce(gravityForce) render.attachNewNode(gravityFN) base.physicsMgr.addLinearForce(gravityForce) self.avatarPhysicsActorNP = render.attachNewNode( ActorNode("player")) self.avatarPhysicsActorNP.node().getPhysicsObject().setMass(50.) self.avatarActor.reparentTo(self.avatarPhysicsActorNP) base.physicsMgr.attachPhysicalNode( self.avatarPhysicsActorNP.node()) self.avatarPhysicsActorNP.setPos(15, 10, 5) ######### Game objects ######### self.avatar = Avatar(self.avatarPhysicsActorNP, self.level) ######### Collisions ######### self.pandaBodySphere = CollisionSphere(0, 0, 4, 3) self.pandaBodySphereNode = CollisionNode("playerBodySphere") self.pandaBodySphereNode.addSolid(self.pandaBodySphere) self.pandaBodySphereNode.setFromCollideMask(BitMask32.bit(0)) self.pandaBodySphereNode.setIntoCollideMask(BitMask32.allOff()) self.pandaBodySphereNodepath = self.avatar.objectNP.attachNewNode( self.pandaBodySphereNode) self.pandaBodySphereNodepath.show() self.pandaBodyCollisionHandler = PhysicsCollisionHandler() self.pandaBodyCollisionHandler.addCollider( self.pandaBodySphereNodepath, self.avatar.objectNP) #Keep player on ground self.pandaGroundSphere = CollisionSphere(0, 0, 1, 1) self.pandaGroundSphereNode = CollisionNode("playerGroundRay") self.pandaGroundSphereNode.addSolid(self.pandaGroundSphere) self.pandaGroundSphereNode.setFromCollideMask(BitMask32.bit(0)) self.pandaGroundSphereNode.setIntoCollideMask(BitMask32.allOff()) self.pandaGroundSphereNodepath = self.avatar.objectNP.attachNewNode( self.pandaGroundSphereNode) self.pandaGroundSphereNodepath.show() self.pandaGroundCollisionHandler = PhysicsCollisionHandler() self.pandaGroundCollisionHandler.addCollider( self.pandaGroundSphereNodepath, self.avatar.objectNP) #Notify when player lands self.pandaGroundRayJumping = CollisionSphere(0, 0, 1, 1) self.pandaGroundRayNodeJumping = CollisionNode( "playerGroundRayJumping") self.pandaGroundRayNodeJumping.addSolid(self.pandaGroundRayJumping) self.pandaGroundRayNodeJumping.setFromCollideMask(BitMask32.bit(0)) self.pandaGroundRayNodeJumping.setIntoCollideMask( BitMask32.allOff()) self.pandaGroundRayNodepathJumping = self.avatar.objectNP.attachNewNode( self.pandaGroundRayNodeJumping) self.pandaGroundRayNodepathJumping.show() self.collisionNotifier = CollisionHandlerEvent() self.collisionNotifier.addInPattern("%fn-in") self.collisionNotifier.addOutPattern("%fn-out") self.cTrav.addCollider(self.pandaGroundSphereNodepath, self.pandaGroundCollisionHandler) self.cTrav.addCollider(self.pandaGroundRayNodepathJumping, self.collisionNotifier) self.cTrav.addCollider(self.pandaBodySphereNodepath, self.pandaBodyCollisionHandler) self.accept("playerGroundRayJumping-in", self.avatar.handleCollisionEvent, ["in"]) self.accept("playerGroundRayJumping-out", self.avatar.handleCollisionEvent, ["out"]) self.accept("playerBodyRay-in", self.avatar.handleCollisionEvent, ["in"]) def togglePhysicsPause(self): if (self._GCLK == None): self.disableParticles() self._GCLK = ClockObject.getGlobalClock() self._FT = self._GCLK.getFrameTime() self._GCLK.setMode(ClockObject.MSlave) else: self._GCLK.setRealTime(self._FT) self._GCLK.setMode(ClockObject.MNormal) self.enableParticles() self._GCLK = None def gameLoop(self, task): dt = globalClock.getDt() self.processKeys() if self.gameMode["display"] == MAIN_MENU: if not self.mode_initialized: self.buildMainMenu() self.mode_initialized = True if self.gameMode["display"] == IN_GAME_MENU: if not self.mode_initialized: #Fog out background inGameMenuFogColor = (50, 150, 50) inGameMenuFog = Fog("inGameMenuFog") inGameMenuFog.setMode(Fog.MExponential) inGameMenuFog.setColor(*inGameMenuFogColor) inGameMenuFog.setExpDensity(.01) render.setFog(inGameMenuFog) self.buildInGameMenu() self.mode_initialized = True if self.gameMode["display"] == DEAD: if not self.mode_initialized: self.buildDeathScreen() self.mode_initialized = True if self.gameMode["display"] == PLAY: alive = self.avatar.states["alive"] if not self.mode_initialized: self.toggleCursor(True) self.last_mouse_x = self.win.getPointer(0).getX() self.last_mouse_y = self.win.getPointer(0).getY() self.mode_initialized = True if self.gameMode["play"] == TERRAIN: if alive: self.maintainTurrets() self.avatar.move(dt) else: self.switchDisplayMode(DEAD) elif self.gameMode["play"] == SPACE: if alive: self.asteroidManager.maintainAsteroidField( self.avatar.objectNP.getPos(), self.avatar.speed, Camera.AVATAR_DIST, dt) else: self.switchDisplayMode(DEAD) if alive: #Handle keyboard input self.avatar.handleKeys(self.keys, self.gameMode["play"]) ########## Mouse-based viewpoint rotation ########## mouse_pos = self.win.getPointer(0) current_mouse_x = mouse_pos.getX() current_mouse_y = mouse_pos.getY() #Side to side if self.gameMode["play"] == TERRAIN: mouse_shift_x = current_mouse_x - self.last_mouse_x self.last_mouse_x = current_mouse_x if current_mouse_x < 5 or current_mouse_x >= ( self.win_center_x * 1.5): base.win.movePointer(0, self.win_center_x, current_mouse_y) self.last_mouse_x = self.win_center_x yaw_shift = -((mouse_shift_x) * Camera.ROT_RATE[0]) self.avatar.yawRot += yaw_shift self.avatar.objectNP.setH(self.avatar.yawRot) #Up and down mouse_shift_y = current_mouse_y - self.last_mouse_y self.last_mouse_y = current_mouse_y if current_mouse_y < 5 or current_mouse_y >= ( self.win_center_y * 1.5): base.win.movePointer(0, current_mouse_x, self.win_center_y) self.last_mouse_y = self.win_center_y pitch_shift = -((mouse_shift_y) * Camera.ROT_RATE[1]) self.mainCamera.pitchRot += pitch_shift if self.mainCamera.pitchRot > Camera.FLEX_ROT_BOUND[0]: self.mainCamera.pitchRot = Camera.FLEX_ROT_BOUND[0] elif self.mainCamera.pitchRot < -Camera.FLEX_ROT_BOUND[0]: self.mainCamera.pitchRot = -Camera.FLEX_ROT_BOUND[0] xy_plane_cam_dist = Camera.AVATAR_DIST cam_x_adjust = xy_plane_cam_dist * sin( radians(self.avatar.yawRot)) cam_y_adjust = xy_plane_cam_dist * cos( radians(self.avatar.yawRot)) cam_z_adjust = Camera.ELEVATION self.mainCamera.camObject.setH(self.avatar.yawRot) self.mainCamera.camObject.setP(self.mainCamera.pitchRot) self.mainCamera.camObject.setPos( self.avatar.objectNP.getX() + cam_x_adjust, self.avatar.objectNP.getY() - cam_y_adjust, self.avatar.objectNP.getZ() + cam_z_adjust) #Find collisions self.cTrav.traverse(render) return Task.cont
class DistributedPartyTrampolineActivity(DistributedPartyActivity): notify = DirectNotifyGlobal.directNotify.newCategory( 'DistributedPartyTrampolineActivity') def __init__(self, cr, doJellyBeans=True, doTricks=False, texture=None): DistributedPartyTrampolineActivity.notify.debug('__init__') DistributedPartyActivity.__init__( self, cr, PartyGlobals.ActivityIds.PartyTrampoline, PartyGlobals.ActivityTypes.GuestInitiated, wantLever=False, wantRewardGui=True) self.doJellyBeans = doJellyBeans self.doTricks = doTricks self.texture = texture self.toon = None self.trampHeight = 3.6 self.trampK = 400.0 self.normalTrampB = 2.5 self.leavingTrampB = 8.0 self.trampB = self.normalTrampB self.g = -32.0 self.jumpBoost = 330.0 self.beginningBoost = 500.0 self.beginningBoostThreshold = self.trampHeight + 1.5 self.earlyJumpThreshold = 75.0 self.boingThreshold = 300.0 self.turnFactor = 120.0 self.stepDT = 0.001 self.targetCameraPos = Point3(0.0, 40.0, 10.0) self.cameraSpeed = 2.0 self.hopOffPos = Point3(16.0, 0.0, 0.0) self.indicatorFactor = 0.0095 self.dropShadowCutoff = 15.0 self.minHeightForText = 15.0 self.heightTextOffset = -0.065 self.beanOffset = 0.5 self.guiBeanOffset = -0.02 self.jumpTextShown = False self.toonJumped = False self.turnLeft = False self.turnRight = False self.leavingTrampoline = False self.toonVelocity = 0.0 self.topHeight = 0.0 self.lastPeak = 0.0 self.beginRoundInterval = None self.hopOnAnim = None self.hopOffAnim = None self.flashTextInterval = None self.numJellyBeans = PartyGlobals.TrampolineNumJellyBeans self.jellyBeanBonus = PartyGlobals.TrampolineJellyBeanBonus self.jellyBeanStartHeight = 20.0 self.jellyBeanStopHeight = 90.0 self.jellyBeanColors = [ VBase4(1.0, 0.5, 0.5, 1.0), VBase4(0.5, 1.0, 0.5, 1.0), VBase4(0.5, 1.0, 1.0, 1.0), VBase4(1.0, 1.0, 0.4, 1.0), VBase4(0.4, 0.4, 1.0, 1.0), VBase4(1.0, 0.5, 1.0, 1.0) ] delta = (self.jellyBeanStopHeight - self.jellyBeanStartHeight) / (self.numJellyBeans - 1) self.jellyBeanPositions = [ self.jellyBeanStartHeight + n * delta for n in xrange(self.numJellyBeans) ] self.doSimulateStep = False def load(self): DistributedPartyTrampolineActivity.notify.debug('load') DistributedPartyActivity.load(self) self.loadModels() self.loadCollision() self.loadGUI() self.loadSounds() self.loadIntervals() self.activityFSM = TrampolineActivityFSM(self) self.activityFSM.request('Idle') self.animFSM = TrampolineAnimFSM(self) self.setBestHeightInfo('', 0) def loadModels(self): self.tramp = self.root.attachNewNode(self.uniqueName('tramp')) self.trampActor = Actor( 'phase_13/models/parties/trampoline_model', {'emptyAnim': 'phase_13/models/parties/trampoline_anim'}) self.trampActor.reparentTo(self.tramp) if self.texture: reskinNode = self.tramp.find( '**/trampoline/__Actor_modelRoot/-GeomNode') reskinNode.setTexture(loader.loadTexture(self.texture), 100) self.surface = NodePath(self.uniqueName('trampSurface')) self.surface.reparentTo(self.tramp) self.surface.setZ(self.trampHeight) self.trampActor.controlJoint(self.surface, 'modelRoot', 'trampoline_joint1') self.sign.setPos(PartyGlobals.TrampolineSignOffset) self.beans = [ loader.loadModelCopy('phase_4/models/props/jellybean4') for i in xrange(self.numJellyBeans) ] for bean in self.beans: bean.find('**/jellybean').setP(-35.0) bean.setScale(3.0) bean.setTransparency(True) bean.reparentTo(self.tramp) bean.stash() self.beans[-1].setScale(8.0) def loadCollision(self): collTube = CollisionTube(0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 5.4) collTube.setTangible(True) self.trampolineCollision = CollisionNode( self.uniqueName('TrampolineCollision')) self.trampolineCollision.addSolid(collTube) self.trampolineCollision.setCollideMask(OTPGlobals.CameraBitmask | OTPGlobals.WallBitmask) self.trampolineCollisionNP = self.tramp.attachNewNode( self.trampolineCollision) collSphere = CollisionSphere(0.0, 0.0, 0.0, 7.0) collSphere.setTangible(False) self.trampolineTrigger = CollisionNode( self.uniqueName('TrampolineTrigger')) self.trampolineTrigger.addSolid(collSphere) self.trampolineTrigger.setIntoCollideMask(OTPGlobals.WallBitmask) self.trampolineTriggerNP = self.tramp.attachNewNode( self.trampolineTrigger) self.accept('enter%s' % self.uniqueName('TrampolineTrigger'), self.onTrampolineTrigger) def loadGUI(self): self.gui = loader.loadModel('phase_13/models/parties/trampolineGUI') self.gui.reparentTo(base.a2dTopLeft) self.gui.setPos(0.115, 0, -1) self.gui.hide() self.toonIndicator = self.gui.find('**/trampolineGUI_MovingBar') jumpLineLocator = self.gui.find('**/jumpLine_locator') guiBean = self.gui.find('**/trampolineGUI_GreenJellyBean') self.gui.find('**/trampolineGUI_GreenJellyBean').stash() self.guiBeans = [ guiBean.instanceUnderNode(jumpLineLocator, self.uniqueName('guiBean%d' % i)) for i in xrange(self.numJellyBeans) ] self.guiBeans[-1].setScale(1.5) heightTextNode = TextNode( self.uniqueName('TrampolineActivity.heightTextNode')) heightTextNode.setFont(ToontownGlobals.getSignFont()) heightTextNode.setAlign(TextNode.ALeft) heightTextNode.setText('0.0') heightTextNode.setShadow(0.05, 0.05) heightTextNode.setShadowColor(0.0, 0.0, 0.0, 1.0) heightTextNode.setTextColor(1.0, 1.0, 1.0, 1.0) self.heightText = jumpLineLocator.attachNewNode(heightTextNode) self.heightText.setX(0.15) self.heightText.setScale(0.1) self.heightText.setAlphaScale(0.0) self.quitEarlyButtonModels = loader.loadModel( 'phase_3.5/models/gui/inventory_gui') quitEarlyUp = self.quitEarlyButtonModels.find('**//InventoryButtonUp') quitEarlyDown = self.quitEarlyButtonModels.find( '**/InventoryButtonDown') quitEarlyRollover = self.quitEarlyButtonModels.find( '**/InventoryButtonRollover') self.quitEarlyButton = DirectButton( parent=base.a2dTopRight, relief=None, text=TTLocalizer.PartyTrampolineQuitEarlyButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.7, image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(-0.183, 0, -0.4), scale=0.09, command=self.leaveTrampoline) self.quitEarlyButton.stash() self.flashText = OnscreenText(text='', pos=(0.0, -0.45), scale=0.2, fg=(1.0, 1.0, 0.65, 1.0), align=TextNode.ACenter, font=ToontownGlobals.getSignFont(), mayChange=True) self.timer = PartyUtils.getNewToontownTimer() self.timer.posInTopRightCorner() def loadSounds(self): self.jellyBeanSound = base.loader.loadSfx( 'phase_4/audio/sfx/sparkly.ogg') self.boingSound = base.loader.loadSfx( 'phase_4/audio/sfx/target_trampoline_2.ogg') self.whistleSound = base.loader.loadSfx( 'phase_4/audio/sfx/AA_sound_whistle.ogg') def loadIntervals(self): def prepareHeightText(): self.heightText.node().setText( TTLocalizer.PartyTrampolineGetHeight % int(self.toon.getZ())) self.heightText.setZ(self.indicatorFactor * self.toon.getZ() + self.heightTextOffset) self.heightTextInterval = Sequence( Func(prepareHeightText), LerpFunc(self.heightText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0)) def unload(self): DistributedPartyTrampolineActivity.notify.debug('unload') if self.hopOnAnim and self.hopOnAnim.isPlaying(): self.hopOnAnim.finish() if self.hopOffAnim and self.hopOffAnim.isPlaying(): self.hopOffAnim.finish() if self.beginRoundInterval and self.beginRoundInterval.isPlaying(): self.beginRoundInterval.finish() if self.flashTextInterval and self.flashTextInterval.isPlaying(): self.flashTextInterval.finish() if self.heightTextInterval and self.heightTextInterval.isPlaying(): self.heightTextInterval.finish() self.timer.stop() DistributedPartyActivity.unload(self) taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask')) taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask')) self.ignoreAll() del self.heightTextInterval del self.beginRoundInterval del self.hopOnAnim del self.hopOffAnim del self.flashTextInterval if hasattr(self, 'beanAnims'): self.cleanupJellyBeans() self.quitEarlyButton.destroy() del self.quitEarlyButton del self.gui del self.activityFSM del self.animFSM def setBestHeightInfo(self, toonName, height): self.bestHeightInfo = (toonName, height) DistributedPartyTrampolineActivity.notify.debug( '%s has the best height of %d' % (toonName, height)) if height > 0: self.setSignNote(TTLocalizer.PartyTrampolineBestHeight % self.bestHeightInfo) else: self.setSignNote(TTLocalizer.PartyTrampolineNoHeightYet) def leaveTrampoline(self): if self.toon != None and self.toon.doId == base.localAvatar.doId: self._showFlashMessage(TTLocalizer.PartyTrampolineTimesUp) self.leavingTrampoline = True self.timer.reset() self.trampB = self.leavingTrampB self.ignore(base.JUMP) self.quitEarlyButton.stash() self.gui.hide() def requestAnim(self, request): self.animFSM.request(request) def b_requestAnim(self, request): self.requestAnim(request) self.sendUpdate('requestAnim', [request]) def requestAnimEcho(self, request): if self.toon != None and self.toon.doId != base.localAvatar.doId: self.requestAnim(request) def removeBeans(self, beansToRemove): for i in beansToRemove: height, bean, guiBean, beanAnim = self.beanDetails[i] guiBean.stash() if i in self.beansToCollect: self.beansToCollect.remove(i) else: self.notify.warning( 'removeBeans avoided a crash, %d not in self.beansToCollect' % i) self.poofBean(bean, beanAnim) def b_removeBeans(self, beansToRemove): self.removeBeans(beansToRemove) self.sendUpdate('removeBeans', [beansToRemove]) def removeBeansEcho(self, beansToRemove): if self.toon != None and self.toon.doId != base.localAvatar.doId: self.removeBeans(beansToRemove) return def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyActivityDefaultJoinDeny) base.cr.playGame.getPlace().fsm.request('walk') def exitRequestDenied(self, reason): DistributedPartyActivity.exitRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyActivityDefaultExitDeny) def setState(self, newState, timestamp): DistributedPartyTrampolineActivity.notify.debug( 'setState( newState=%s, ... )' % newState) DistributedPartyActivity.setState(self, newState, timestamp) self.activityFSM.request(newState) def startIdle(self): DistributedPartyTrampolineActivity.notify.debug('startIdle') def finishIdle(self): DistributedPartyTrampolineActivity.notify.debug('finishIdle') def startRules(self): DistributedPartyTrampolineActivity.notify.debug('startRules') if self.doJellyBeans: self.setupJellyBeans() if self.toon != None and self.toon.doId == base.localAvatar.doId: self.acquireToon() def startActive(self): DistributedPartyTrampolineActivity.notify.debug('startActive') if self.toon != None and self.toon.doId == base.localAvatar.doId: base.setCellsActive(base.bottomCells, True) self.accept(base.MOVE_LEFT, self.onLeft) self.accept(base.MOVE_LEFT + '-up', self.onLeftUp) self.accept(base.MOVE_RIGHT, self.onRight) self.accept(base.MOVE_RIGHT + '-up', self.onRightUp) self.beginRoundInterval = Sequence( Func(self._showFlashMessage, TTLocalizer.PartyTrampolineReady), Wait(1.2), Func(self.flashMessage, TTLocalizer.PartyTrampolineGo), Func(self.beginRound)) self.beginRoundInterval.start() def finishActive(self): DistributedPartyTrampolineActivity.notify.debug('finishActive') if self.doJellyBeans: self.cleanupJellyBeans() def setupJellyBeans(self): self.beanAnims = [] self.beansToCollect = [] self.beanDetails = [] self.numBeansCollected = 0 for i in xrange(self.numJellyBeans): bean = self.beans[i] guiBean = self.guiBeans[i] height = self.jellyBeanPositions[i] color = random.choice(self.jellyBeanColors) bean.find('**/jellybean').setColor(color) if self.toon.doId == base.localAvatar.doId: bean.setAlphaScale(1.0) else: bean.setAlphaScale(0.5) guiBean.setColor(color) bean.setZ(height + self.toon.getHeight() + self.beanOffset) guiBean.setZ(height * self.indicatorFactor + self.guiBeanOffset) bean.setH(0.0) bean.unstash() guiBean.unstash() beanAnim = bean.hprInterval( 1.5, VBase3((i % 2 * 2 - 1) * 360.0, 0.0, 0.0)) beanAnim.loop() self.beanAnims.append(beanAnim) self.beanDetails.append((height, bean, guiBean, beanAnim)) self.beansToCollect = range(self.numJellyBeans) def cleanupJellyBeans(self): for bean in self.beans: bean.stash() for guiBean in self.guiBeans: guiBean.stash() if hasattr(self, 'beanAnims'): for beanAnim in self.beanAnims: beanAnim.finish() del self.beanAnims del self.beansToCollect def beginRound(self): base.playSfx(self.whistleSound) self.timer.setTime(PartyGlobals.TrampolineDuration) self.timer.countdown(PartyGlobals.TrampolineDuration) self.timer.show() self.gui.show() self.quitEarlyButton.unstash() self.notify.debug('Accepting contorl') self.accept(base.JUMP, self.onJump) self.notify.debug('setting simulate step to true') self.doSimulateStep = True def acquireToon(self): self.toon.disableSmartCameraViews() self.toon.stopUpdateSmartCamera() camera.wrtReparentTo(render) self.toon.dropShadow.reparentTo(hidden) self.toon.startPosHprBroadcast(period=0.2) self.toonAcceleration = 0.0 self.toonVelocity = 0.0 self.topHeight = 0.0 self.trampB = self.normalTrampB self.leavingTrampoline = False self.hopOnAnim = Sequence( Func(self.toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, Point3(0.0, 0.0, self.trampHeight), 5.0, self.tramp), Func(self.postHopOn)) self.hopOnAnim.start() def postHopOn(self): self.toon.setH(self.toon.getH() + 90.0) self.toon.dropShadow.reparentTo(self.surface) self.timeLeftToSimulate = 0.0 self.doSimulateStep = False taskMgr.add(self.updateTask, self.uniqueName('TrampolineActivity.updateTask')) base.setCellsActive(base.leftCells, False) base.setCellsActive(base.bottomCells, False) DistributedPartyActivity.startRules(self) def releaseToon(self): self._hideFlashMessage() self.ignore(base.MOVE_LEFT) self.ignore(base.MOVE_LEFT + '-up') self.ignore(base.MOVE_RIGHT) self.ignore(base.MOVE_RIGHT + '-up') taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask')) self.hopOffAnim = Sequence( self.toon.hprInterval(0.5, VBase3(-90.0, 0.0, 0.0), other=self.tramp), Func(self.toon.b_setAnimState, 'jump', 1.0), Func(self.toon.dropShadow.reparentTo, hidden), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, self.hopOffPos, 5.0, self.tramp), Func(self.postHopOff)) self.hopOffAnim.start() def postHopOff(self): base.setCellsActive(base.leftCells, True) self.timer.stop() self.timer.hide() self.toon.dropShadow.reparentTo(self.toon.getShadowJoint()) self.toon.dropShadow.setAlphaScale(1.0) self.toon.dropShadow.setScale(1.0) self.b_requestAnim('Off') camera.reparentTo(base.localAvatar) base.localAvatar.startUpdateSmartCamera() base.localAvatar.enableSmartCameraViews() base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex) place = base.cr.playGame.getPlace() if self.doJellyBeans: self.sendUpdate('awardBeans', [self.numBeansCollected, int(self.topHeight)]) if int(self.topHeight) > self.bestHeightInfo[1]: self.sendUpdate('reportHeightInformation', [int(self.topHeight)]) self.d_toonExitDemand() def onTrampolineTrigger(self, collEntry): if self.activityFSM.state == 'Idle' and self.toon == None and base.cr.playGame.getPlace( ).fsm.getCurrentState().getName() == 'walk': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() else: self.flashMessage(TTLocalizer.PartyTrampolineActivityOccupied, duration=2.0) def onJump(self): self.notify.debug('got onJump') if self.toon != None and self.toon.getZ() < self.trampHeight: self.toonJumped = True self.b_requestAnim('Jump') else: self.notify.debug('z is less than tramp height') def onLeft(self): self.turnLeft = True def onLeftUp(self): self.turnLeft = False def onRight(self): self.turnRight = True def onRightUp(self): self.turnRight = False def handleToonJoined(self, toonId): DistributedPartyTrampolineActivity.notify.debug('handleToonJoined') self.toon = self.getAvatar(toonId) if self.toon != None and not self.toon.isEmpty(): self.oldJumpSquatPlayRate = self.toon.getPlayRate('jump-squat') self.oldJumpLandPlayRate = self.toon.getPlayRate('jump-land') self.toon.setPlayRate(2.5, 'jump-squat') self.toon.setPlayRate(2.0, 'jump-land') self.turnLeft = False self.turnRight = False self.activityFSM.request('Rules') if self.toon.doId != base.localAvatar.doId: taskMgr.add( self.remoteUpdateTask, self.uniqueName('TrampolineActivity.remoteUpdateTask')) else: self.notify.warning('handleToonJoined could not get toon %d' % toonId) def handleToonExited(self, toonId): DistributedPartyTrampolineActivity.notify.debug('handleToonExited') if self.toon != None: if self.toon.doId != base.localAvatar.doId: taskMgr.remove( self.uniqueName('TrampolineActivity.remoteUpdateTask')) self.surface.setZ(self.trampHeight) self.toon.setPlayRate(self.oldJumpSquatPlayRate, 'jump-squat') self.toon.setPlayRate(self.oldJumpLandPlayRate, 'jump-land') self.toon = None def handleToonDisabled(self, toonId): DistributedPartyTrampolineActivity.notify.debug('handleToonDisabled') DistributedPartyTrampolineActivity.notify.debug('avatar ' + str(toonId) + ' disabled') if base.localAvatar.doId == toonId: self.releaseToon() def handleRulesDone(self): self.sendUpdate('toonReady') self.finishRules() def getTitle(self): if self.doJellyBeans: return TTLocalizer.PartyTrampolineJellyBeanTitle elif self.doTricks: return TTLocalizer.PartyTrampolineTricksTitle else: return DistributedPartyActivity.getTitle(self) def getInstructions(self): return TTLocalizer.PartyTrampolineActivityInstructions def updateTask(self, task): z = self.toon.getZ() dt = globalClock.getDt() if self.doSimulateStep: self.timeLeftToSimulate += dt while self.timeLeftToSimulate >= self.stepDT: z, a = self.simulateStep(z) self.timeLeftToSimulate -= self.stepDT self.toon.setZ(z) if z <= self.trampHeight: self.surface.setZ(z) else: self.surface.setZ(self.trampHeight) self.toonIndicator.setZ((z - self.trampHeight) * self.indicatorFactor) if self.turnLeft: self.toon.setH(self.toon.getH() + self.turnFactor * dt) if self.turnRight: self.toon.setH(self.toon.getH() - self.turnFactor * dt) currentPos = base.camera.getPos(self.toon) vec = self.targetCameraPos - currentPos newPos = currentPos + vec * (dt * self.cameraSpeed) base.camera.setPos(self.toon, newPos) base.camera.lookAt(self.toon) #if z > self.trampHeight: # heightFactor = 1.0 - min(1.0, (z - self.trampHeight) / self.dropShadowCutoff) # self.toon.dropShadow.setAlphaScale(heightFactor) # self.toon.dropShadow.setScale(max(0.1, heightFactor)) #else: # self.toon.dropShadow.setAlphaScale(1.0) # self.toon.dropShadow.setScale(1.0) if self.leavingTrampoline and z < self.trampHeight and abs(a) < 0.1: self.releaseToon() return Task.cont def simulateStep(self, z): if z >= self.trampHeight: a = self.g self.toonJumped = False else: a = self.g + self.trampK * (self.trampHeight - z) - self.trampB * self.toonVelocity if self.toonJumped: if self.lastPeak > self.earlyJumpThreshold or self.toonVelocity >= -300000.0: a += self.jumpBoost if self.lastPeak < self.beginningBoostThreshold: a += self.beginningBoost lastVelocity = self.toonVelocity self.toonVelocity += a * self.stepDT if lastVelocity > 0.0 and self.toonVelocity <= 0.0: topOfJump = True bottomOfJump = False elif lastVelocity < 0.0 and self.toonVelocity >= 0.0: topOfJump = False bottomOfJump = True else: topOfJump = False bottomOfJump = False newZ = z + self.toonVelocity * self.stepDT if newZ > self.topHeight: self.topHeight = newZ if self.doJellyBeans: self.collectJellyBeans(newZ) if topOfJump: self.lastPeak = newZ if newZ >= self.minHeightForText: self.heightTextInterval.start() if topOfJump: if newZ > self.trampHeight + 20.0: self.b_requestAnim('Falling') elif self.animFSM.state == 'Jump': self.b_requestAnim('Falling') if newZ <= self.trampHeight and z > self.trampHeight: if self.animFSM.state == 'Falling': self.b_requestAnim('Land') elif self.animFSM.state != 'Neutral': self.b_requestAnim('Neutral') if bottomOfJump and a > self.boingThreshold: base.playSfx(self.boingSound) return (newZ, a) def collectJellyBeans(self, z): beansToRemove = [] for i in self.beansToCollect: height = self.beanDetails[i][0] if height <= z: beansToRemove.append(i) if len(beansToRemove) > 0: base.playSfx(self.jellyBeanSound) self.numBeansCollected += len(beansToRemove) self.b_removeBeans(beansToRemove) def remoteUpdateTask(self, task): if self.toon != None and not self.toon.isEmpty(): z = self.toon.getZ() if z <= self.trampHeight: self.surface.setZ(z) else: self.surface.setZ(self.trampHeight) return Task.cont def poofBean(self, bean, beanAnim): if bean == None: self.notify.warning( 'poofBean, returning immediately as bean is None') return if bean.isEmpty(): self.notify.warning( 'poofBean, returning immediately as bean is empty') return currentAlpha = bean.getColorScale()[3] currentScale = bean.getScale() poofAnim = Sequence( Parallel( LerpFunc(bean.setAlphaScale, fromData=currentAlpha, toData=0.0, duration=0.25), LerpFunc(bean.setScale, fromData=currentScale, toData=currentScale * 5.0, duration=0.25)), Func(bean.stash), Func(beanAnim.finish), Func(bean.setAlphaScale, currentAlpha), Func(bean.setScale, currentScale)) poofAnim.start() def _showFlashMessage(self, message): if self.isDisabled(): return if self.flashTextInterval is not None and self.flashTextInterval.isPlaying( ): self.flashTextInterval.finish() self.flashText.setText(message) self.flashText.setAlphaScale(1.0) self.flashText.unstash() def _hideFlashMessage(self, duration=0.0): if self.isDisabled(): pass self.flashTextInterval = Sequence( Wait(duration), LerpFunc(self.flashText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0), Func(self.flashText.stash)) self.flashTextInterval.start() def flashMessage(self, message, duration=0.5): self._showFlashMessage(message) self._hideFlashMessage(duration)
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 CogThief(DirectObject): notify = directNotify.newCategory('CogThief') DefaultSpeedWalkAnim = 4.0 CollisionRadius = 1.25 MaxFriendsVisible = 4 Infinity = 100000.0 SeparationDistance = 6.0 MinUrgency = 0.5 MaxUrgency = 0.75 def __init__(self, cogIndex, suitType, game, cogSpeed): self.cogIndex = cogIndex self.suitType = suitType self.game = game self.cogSpeed = cogSpeed suit = Suit.Suit() d = SuitDNA.SuitDNA() d.newSuit(suitType) suit.setDNA(d) suit.pose('walk', 0) self.suit = suit self.goal = CTGG.NoGoal self.goalId = CTGG.InvalidGoalId self.lastLocalTimeStampFromAI = 0 self.lastPosFromAI = Point3(0, 0, 0) self.lastThinkTime = 0 self.doneAdjust = False self.barrel = CTGG.NoBarrelCarried self.signalledAtReturnPos = False self.defaultPlayRate = 1.0 self.netTimeSentToStartByHit = 0 self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) self.bodyLength = self.CollisionRadius * 2 self.cruiseDistance = 2 * self.bodyLength self.maxVelocity = self.cogSpeed self.maxAcceleration = 5.0 self.perceptionRange = 6 self.notify.debug('cogSpeed=%s' % self.cogSpeed) self.kaboomSound = loader.loadSfx( 'phase_4/audio/sfx/MG_cannon_fire_alt.mp3') self.kaboom = loader.loadModel( 'phase_4/models/minigames/ice_game_kaboom') self.kaboom.setScale(2.0) self.kaboom.setBillboardPointEye() self.kaboom.hide() self.kaboomTrack = None splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound( 'AA_wholepie_only.mp3') return def destroy(self): self.ignoreAll() self.suit.delete() self.game = None return def uniqueName(self, baseStr): return baseStr + '-' + str(self.game.doId) def handleEnterSphere(self, collEntry): intoNp = collEntry.getIntoNodePath() self.notify.debug('handleEnterSphere suit %d hit %s' % (self.cogIndex, intoNp)) if self.game: self.game.handleEnterSphere(collEntry) def gameStart(self, gameStartTime): self.gameStartTime = gameStartTime self.initCollisions() self.startWalkAnim() def gameEnd(self): self.moveIval.pause() del self.moveIval self.shutdownCollisions() self.suit.loop('neutral') def initCollisions(self): self.collSphere = CollisionSphere(0, 0, 0, 1.25) self.collSphere.setTangible(1) name = 'CogThiefSphere-%d' % self.cogIndex self.collSphereName = self.uniqueName(name) self.collNode = CollisionNode(self.collSphereName) self.collNode.setIntoCollideMask(CTGG.BarrelBitmask | ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.suit.attachNewNode(self.collNode) self.accept('enter' + self.collSphereName, self.handleEnterSphere) self.pieCollSphere = CollisionTube(0, 0, 0, 0, 0, 4, self.CollisionRadius) self.pieCollSphere.setTangible(1) name = 'CogThiefPieSphere-%d' % self.cogIndex self.pieCollSphereName = self.uniqueName(name) self.pieCollNode = CollisionNode(self.pieCollSphereName) self.pieCollNode.setIntoCollideMask(ToontownGlobals.PieBitmask) self.pieCollNode.addSolid(self.pieCollSphere) self.pieCollNodePath = self.suit.attachNewNode(self.pieCollNode) def shutdownCollisions(self): self.ignore(self.uniqueName('enter' + self.collSphereName)) del self.collSphere self.collNodePath.removeNode() del self.collNodePath del self.collNode def updateGoal(self, timestamp, inResponseClientStamp, goalType, goalId, pos): self.notify.debug('self.netTimeSentToStartByHit =%s' % self.netTimeSentToStartByHit) if not self.game: self.notify.debug('updateGoal self.game is None, just returning') return if not self.suit: self.notify.debug('updateGoal self.suit is None, just returning') return if self.goal == CTGG.NoGoal: self.startWalkAnim() if goalType == CTGG.NoGoal: self.notify.debug('updateGoal setting position to %s' % pos) self.suit.setPos(pos) self.lastThinkTime = 0 self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) if goalType == CTGG.RunAwayGoal: pass if inResponseClientStamp < self.netTimeSentToStartByHit and self.goal == CTGG.NoGoal and goalType == CTGG.RunAwayGoal: self.notify.warning( 'ignoring newGoal %s as cog %d was recently hit responsetime=%s hitTime=%s' % (CTGG.GoalStr[goalType], self.cogIndex, inResponseClientStamp, self.netTimeSentToStartByHit)) else: self.lastLocalTimeStampFromAI = globalClockDelta.networkToLocalTime( timestamp, bits=32) self.goal = goalType self.goalId = goalId self.lastPosFromAI = pos self.doneAdjust = False self.signalledAtReturnPos = False def startWalkAnim(self): if self.suit: self.suit.loop('walk') speed = self.cogSpeed self.defaultPlayRate = float(self.cogSpeed / self.DefaultSpeedWalkAnim) self.suit.setPlayRate(self.defaultPlayRate, 'walk') def think(self): if self.goal == CTGG.ToonGoal: self.thinkAboutCatchingToon() elif self.goal == CTGG.BarrelGoal: self.thinkAboutGettingBarrel() elif self.goal == CTGG.RunAwayGoal: self.thinkAboutRunAway() def thinkAboutCatchingToon(self): if not self.game: return av = self.game.getAvatar(self.goalId) if av: if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime avPos = av.getPos() myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.notify.debug( 'thinkAboutCatchingToon not doneAdjust setting pos %s' % myPos) self.doneAdjust = True self.suit.setPos(myPos) if self.game.isToonPlayingHitTrack(self.goalId): self.suit.headsUp(av) self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) else: self.commonMove() newPos = self.suit.getPos() self.adjustPlayRate(newPos, myPos, diffTime) self.lastThinkTime = globalClock.getFrameTime() def convertNetworkStampToGameTime(self, timestamp): localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) gameTime = self.game.local2GameTime(localStamp) return gameTime def respondToToonHit(self, timestamp): localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) if self.netTimeSentToStartByHit < timestamp: self.clearGoal() self.showKaboom() startPos = CTGG.CogStartingPositions[self.cogIndex] oldPos = self.suit.getPos() self.suit.setPos(startPos) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug( 'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToToonHit' % (localStamp, self.lastLocalTimeStampFromAI)) self.notify.debug( 'respondToToonHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearGoal(self): self.goal = CTGG.NoGoal self.goalId = CTGG.InvalidGoalId def thinkAboutGettingBarrel(self): if not self.game: return if not hasattr(self.game, 'barrels'): return if self.goalId not in range(len(self.game.barrels)): return if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime barrel = self.game.barrels[self.goalId] barrelPos = barrel.getPos() myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.notify.debug( 'thinkAboutGettingBarrel not doneAdjust setting position to %s' % myPos) self.suit.setPos(myPos) self.doneAdjust = True displacement = barrelPos - myPos distanceToToon = displacement.length() self.suit.headsUp(barrel) lengthTravelled = diffTime * self.cogSpeed if lengthTravelled > distanceToToon: lengthTravelled = distanceToToon displacement.normalize() dirVector = displacement dirVector *= lengthTravelled newPos = myPos + dirVector newPos.setZ(0) self.suit.setPos(newPos) self.adjustPlayRate(newPos, myPos, diffTime) self.lastThinkTime = globalClock.getFrameTime() def stopWalking(self, timestamp): localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) if localStamp > self.lastLocalTimeStampFromAI: self.suit.loop('neutral') self.clearGoal() def thinkAboutRunAway(self): if not self.game: return if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime returnPos = CTGG.CogReturnPositions[self.goalId] myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.suit.setPos(myPos) self.doneAdjust = True displacement = returnPos - myPos distanceToToon = displacement.length() tempNp = render.attachNewNode('tempRet') tempNp.setPos(returnPos) self.suit.headsUp(tempNp) tempNp.removeNode() lengthTravelled = diffTime * self.cogSpeed if lengthTravelled > distanceToToon: lengthTravelled = distanceToToon displacement.normalize() dirVector = displacement dirVector *= lengthTravelled newPos = myPos + dirVector newPos.setZ(0) self.suit.setPos(newPos) self.adjustPlayRate(newPos, myPos, diffTime) if (self.suit.getPos() - returnPos).length() < 0.0001: if not self.signalledAtReturnPos and self.barrel >= 0: self.game.sendCogAtReturnPos(self.cogIndex, self.barrel) self.signalledAtReturnPos = True self.lastThinkTime = globalClock.getFrameTime() def makeCogCarryBarrel(self, timestamp, inResponseClientStamp, barrelModel, barrelIndex, cogPos): if not self.game: return localTimeStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) self.lastLocalTimeStampFromAI = localTimeStamp inResponseGameTime = self.convertNetworkStampToGameTime( inResponseClientStamp) self.notify.debug('inResponseGameTime =%s timeSentToStart=%s' % (inResponseGameTime, self.netTimeSentToStartByHit)) if inResponseClientStamp < self.netTimeSentToStartByHit and self.goal == CTGG.NoGoal: self.notify.warning('ignoring makeCogCarrybarrel') else: barrelModel.setPos(0, -1.0, 1.5) barrelModel.reparentTo(self.suit) self.suit.setPos(cogPos) self.barrel = barrelIndex def makeCogDropBarrel(self, timestamp, inResponseClientStamp, barrelModel, barrelIndex, barrelPos): localTimeStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) self.lastLocalTimeStampFromAI = localTimeStamp barrelModel.reparentTo(render) barrelModel.setPos(barrelPos) self.barrel = CTGG.NoBarrelCarried def respondToPieHit(self, timestamp): localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) if self.netTimeSentToStartByHit < timestamp: self.clearGoal() self.showSplat() startPos = CTGG.CogStartingPositions[self.cogIndex] oldPos = self.suit.getPos() self.suit.setPos(startPos) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug( 'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToPieHit' % (localStamp, self.lastLocalTimeStampFromAI)) self.notify.debug( 'respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def cleanup(self): self.clearGoal() self.ignoreAll() self.suit.delete() if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.suit = None self.game = None return def adjustPlayRate(self, newPos, oldPos, diffTime): lengthTravelled = (newPos - oldPos).length() if diffTime: speed = lengthTravelled / diffTime else: speed = self.cogSpeed rateMult = speed / self.cogSpeed newRate = rateMult * self.defaultPlayRate self.suit.setPlayRate(newRate, 'walk') def commonMove(self): if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() dt = globalClock.getFrameTime() - self.lastThinkTime self.oldpos = self.suit.getPos() pos = self.suit.getPos() pos += self.velocity * dt self.suit.setPos(pos) self.seeFriends() acc = Vec3(0, 0, 0) self.accumulate(acc, self.getTargetVector()) if self.numFlockmatesSeen > 0: keepDistanceVector = self.keepDistance() oldAcc = Vec3(acc) self.accumulate(acc, keepDistanceVector) if self.cogIndex == 0: pass if acc.length() > self.maxAcceleration: acc.normalize() acc *= self.maxAcceleration self.oldVelocity = self.velocity self.velocity += acc if self.velocity.length() > self.maxVelocity: self.velocity.normalize() self.velocity *= self.maxVelocity forwardVec = Vec3(1, 0, 0) heading = rad2Deg(math.atan2(self.velocity[1], self.velocity[0])) heading -= 90 self.suit.setH(heading) def getTargetVector(self): targetPos = Point3(0, 0, 0) if self.goal == CTGG.ToonGoal: av = self.game.getAvatar(self.goalId) if av: targetPos = av.getPos() elif self.goal == CTGG.BarrelGoal: barrel = self.game.barrels[self.goalId] targetPos = barrel.getPos() elif self.goal == CTGG.RunAwayGoal: targetPos = CTGG.CogReturnPositions[self.goalId] targetPos.setZ(0) myPos = self.suit.getPos() diff = targetPos - myPos if diff.length() > 1.0: diff.normalize() diff *= 1.0 return diff def accumulate(self, accumulator, valueToAdd): accumulator += valueToAdd return accumulator.length() def seeFriends(self): self.clearVisibleList() for cogIndex in self.game.cogInfo.keys(): if cogIndex == self.cogIndex: continue if self.sameGoal(cogIndex): dist = self.canISee(cogIndex) if dist != self.Infinity: self.addToVisibleList(cogIndex) if dist < self.distToNearestFlockmate: self.nearestFlockmate = cogIndex self.distToNearestFlockmate = dist return self.numFlockmatesSeen def clearVisibleList(self): self.visibleFriendsList = [] self.numFlockmatesSeen = 0 self.nearestFlockmate = None self.distToNearestFlockmate = self.Infinity return def addToVisibleList(self, cogIndex): if self.numFlockmatesSeen < self.MaxFriendsVisible: self.visibleFriendsList.append(cogIndex) self.numFlockmatesSeen += 1 if self.cogIndex == 0: pass def canISee(self, cogIndex): if self.cogIndex == cogIndex: return self.Infinity cogThief = self.game.getCogThief(cogIndex) distance = self.suit.getDistance(cogThief.suit) if distance < self.perceptionRange: return distance return self.Infinity def sameGoal(self, cogIndex): cogThief = self.game.getCogThief(cogIndex) result = cogThief.goalId == self.goalId and cogThief.goal == self.goal return result def keepDistance(self): ratio = self.distToNearestFlockmate / self.SeparationDistance nearestThief = self.game.getCogThief(self.nearestFlockmate) change = nearestThief.suit.getPos() - self.suit.getPos() if ratio < self.MinUrgency: ratio = self.MinUrgency if ratio > self.MaxUrgency: ratio = self.MaxUrgency if self.distToNearestFlockmate < self.SeparationDistance: change.normalize() change *= -(1 - ratio) elif self.distToNearestFlockmate > self.SeparationDistance: change.normalize() change *= ratio else: change = Vec3(0, 0, 0) return change def showKaboom(self): if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboom.reparentTo(render) self.kaboom.setPos(self.suit.getPos()) self.kaboom.setZ(3) self.kaboomTrack = Parallel( SoundInterval(self.kaboomSound, volume=0.5), Sequence( Func(self.kaboom.showThrough), LerpScaleInterval(self.kaboom, duration=0.5, scale=Point3(10, 10, 10), startScale=Point3(1, 1, 1), blendType='easeOut'), Func(self.kaboom.hide))) self.kaboomTrack.start() def showSplat(self): if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.splat.reparentTo(render) self.splat.setPos(self.suit.getPos()) self.splat.setZ(3) self.kaboomTrack = Parallel( SoundInterval(self.pieHitSound, volume=1.0), Sequence( Func(self.splat.showThrough), LerpScaleInterval(self.splat, duration=0.5, scale=1.75, startScale=Point3(0.1, 0.1, 0.1), blendType='easeOut'), Func(self.splat.hide))) self.kaboomTrack.start()
class World(DirectObject): cfg = None def __init__(self): self.last_mousex = 0 self.last_mousey = 0 self.zone = None self.zone_reload_name = None self.winprops = WindowProperties( ) # simple console output self.consoleNode = NodePath(PandaNode("console_root")) self.consoleNode.reparentTo(aspect2d) self.console_num_lines = 24 self.console_cur_line = -1 self.console_lines = [] for i in range(0, self.console_num_lines): self.console_lines.append(OnscreenText(text='', style=1, fg=(1,1,1,1), pos=(-1.3, .4-i*.05), align=TextNode.ALeft, scale = .035, parent = self.consoleNode)) # Configuration self.consoleOut('World Forge v.%s loading configuration' % VERSION) self.configurator = Configurator(self) cfg = self.configurator.config resaveRes = False if 'xres' in cfg: self.xres = int(cfg['xres']) else: self.xres = 1024 resaveRes = True if 'yres' in cfg: self.yres = int(cfg['yres']) else: self.yres = 768 resaveRes = True if resaveRes: self.saveDefaultRes() self.xres_half = self.xres / 2 self.yres_half = self.yres / 2 self.mouse_accum = MouseAccume( lambda: (self.xres_half,self.yres_half)) self.eyeHeight = 7.0 self.rSpeed = 80 self.flyMode = 1 # application window setup base.win.setClearColor(Vec4(0,0,0,1)) self.winprops.setTitle( 'World Forge') self.winprops.setSize(self.xres, self.yres) base.win.requestProperties( self.winprops ) base.disableMouse() # Post the instructions self.title = addTitle('World Forge v.' + VERSION) self.inst0 = addInstructions(0.95, "[FLYMODE][1]") self.inst1 = addInstructions(-0.95, "Camera control with WSAD/mouselook. Press K for hotkey list, ESC to exit.") self.inst2 = addInstructions(0.9, "Loc:") self.inst3 = addInstructions(0.85, "Hdg:") self.error_inst = addInstructions(0, '') self.kh = [] self.campos = Point3(155.6, 41.2, 4.93) base.camera.setPos(self.campos) # Accept the application control keys: currently just esc to exit navgen self.accept("escape", self.exitGame) self.accept("window-event", self.resizeGame) # Create some lighting ambient_level = .6 ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(ambient_level, ambient_level, ambient_level, 1.0)) render.setLight(render.attachNewNode(ambientLight)) direct_level = 0.8 directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(0.0, 0.0, -1.0)) directionalLight.setColor(Vec4(direct_level, direct_level, direct_level, 1)) directionalLight.setSpecularColor(Vec4(direct_level, direct_level, direct_level, 1)) render.setLight(render.attachNewNode(directionalLight)) # create a point light that will follow our view point (the camera for now) # attenuation is set so that this point light has a torch like effect self.plight = PointLight('plight') self.plight.setColor(VBase4(0.8, 0.8, 0.8, 1.0)) self.plight.setAttenuation(Point3(0.0, 0.0, 0.0002)) self.plnp = base.camera.attachNewNode(self.plight) self.plnp.setPos(0, 0, 0) render.setLight(self.plnp) self.cam_light = 1 self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "cam-left":0, \ "cam-right":0, "mouse3":0, "flymode":1 } # setup FOG self.fog_colour = (0.8,0.8,0.8,1.0) self.linfog = Fog("A linear-mode Fog node") self.linfog.setColor(self.fog_colour) self.linfog.setLinearRange(700, 980) # onset, opaque distances as params # linfog.setLinearFallback(45,160,320) base.camera.attachNewNode(self.linfog) render.setFog(self.linfog) self.fog = 1 # camera control self.campos = Point3(0, 0, 0) self.camHeading = 0.0 self.camPitch = 0.0 base.camLens.setFov(65.0) base.camLens.setFar(1200) self.cam_speed = 0 # index into self.camp_speeds self.cam_speeds = [40.0, 80.0, 160.0, 320.0, 640.0] # Collision Detection for "WALKMODE" # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. The ray 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.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0.0, 0.0, 0.0) self.camGroundRay.setDirection(0,0,-1) # straight down self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) # attach the col node to the camCollider dummy node 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.camGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring # self.cTrav.showCollisions(render) # Add the spinCameraTask procedure to the task manager. # taskMgr.add(self.spinCameraTask, "SpinCameraTask") globals.hasClickedSpawn = False; globals.hasClickedGrid = False; taskMgr.add(self.camTask, "camTask") self.toggleControls(1) # need to step the task manager once to make our fake console work taskMgr.step() # CONSOLE --------------------------------------------------------------------- def consoleScroll(self): for i in range(0, self.console_num_lines-1): self.console_lines[i].setText(self.console_lines[i+1].getText()) def consoleOut(self, text): print text # output to stdout/log too if self.console_cur_line == self.console_num_lines-1: self.consoleScroll() elif self.console_cur_line < self.console_num_lines-1: self.console_cur_line += 1 self.console_lines[self.console_cur_line].setText(text) taskMgr.step() def consoleOn(self): self.consoleNode.show() def consoleOff(self): self.consoleNode.hide() # User controls ----------------------------------------------------------- def toggleControls(self, on): cfg = self.configurator.config if on == 1: self.accept("escape", self.exitGame) self.accept("1", self.setSpeed, ["speed", 0]) self.accept("2", self.setSpeed, ["speed", 1]) self.accept("3", self.setSpeed, ["speed", 2]) self.accept("4", self.setSpeed, ["speed", 3]) self.accept("5", self.setSpeed, ["speed", 4]) self.accept("alt-f", self.fogToggle) self.accept(cfg['control_lighting'], self.camLightToggle) self.accept(cfg['control_help'], self.displayKeyHelp) self.accept(cfg['control_flymode'], self.toggleFlymode) self.accept(cfg['control_reload-zone'], self.reloadZone) self.accept(cfg['control_cam-left'], self.setKey, ["cam-left",1]) self.accept(cfg['control_cam-right'], self.setKey, ["cam-right",1]) self.accept(cfg['control_forward'], self.setKey, ["forward",1]) self.accept("mouse3", self.setKey, ["mouse3",1]) self.accept(cfg['control_backward'], self.setKey, ["backward",1]) self.accept("k-up", self.hideKeyHelp) self.accept(cfg['control_cam-left']+"-up", self.setKey, ["cam-left",0]) self.accept(cfg['control_cam-right']+"-up", self.setKey, ["cam-right",0]) self.accept(cfg['control_forward']+"-up", self.setKey, ["forward",0]) self.accept("mouse3-up", self.setKey, ["mouse3",0]) self.accept(cfg['control_backward']+"-up", self.setKey, ["backward",0]) self.accept(cfg['toggle_edit-mode'], self.toggleEditMode) self.accept(cfg['toggle_insert-mode'], self.toggleInsertMode) self.accept(cfg['toggle_explore-mode'], self.toggleExploreMode) self.accept(cfg['toggle_grid-mode'], self.toggleGridMode) # Accept both single-presses and long presses for rotating models self.accept(cfg['rotate-right'] + "-repeat", self.rotateModelRight) self.accept(cfg['rotate-left'] + "-repeat", self.rotateModelLeft) self.accept(cfg['rotate-right'], self.rotateModelRight) self.accept(cfg['rotate-left'], self.rotateModelLeft) self.accept(cfg['clear-selection'], self.clearSelection) else: messenger.clear() def rotateModelRight(self): if globals.editMode == True: if globals.selectedSpawn: cfg = self.configurator.config globals.selectedSpawn.model.setH(globals.selectedSpawn.model.getH() + int(cfg['rotation-amount'])) # Really not sure about that... if globals.selectedSpawn.model.getH() > 360: globals.selectedSpawn.model.setH(0) print globals.selectedSpawn.model.getH() globals.selectedSpawn.setheadingfromworld(globals.selectedSpawn.model.getH()) globals.spawndialog.m_spawnEntryHeadingTextCtrl.SetValue(str(globals.selectedSpawn.spawnentry_heading)) if globals.config['autosave_edit-mode'] == 'True': globals.database.UpdateSpawn(globals.selectedSpawn) print globals.selectedSpawn.spawnentry_heading def rotateModelLeft(self): if globals.editMode == True: if globals.selectedSpawn: cfg = self.configurator.config globals.selectedSpawn.model.setH(globals.selectedSpawn.model.getH() - int(cfg['rotation-amount'])) # Really not sure about that either... if globals.selectedSpawn.model.getH() < -360: globals.selectedSpawn.model.setH(0) print globals.selectedSpawn.model.getH() globals.selectedSpawn.setheadingfromworld(globals.selectedSpawn.model.getH()) globals.spawndialog.m_spawnEntryHeadingTextCtrl.SetValue(str(globals.selectedSpawn.spawnentry_heading)) if globals.config['autosave_edit-mode'] == 'True': globals.database.UpdateSpawn(globals.selectedSpawn) print globals.selectedSpawn.spawnentry_heading def clearSelection(self, eraseNpcId = True): globals.selectedspawn = None globals.selectedgrid = None globals.picker.lastSelectedObject = None if self.inst6: self.inst6.destroy() self.inst6 = addInstructions(0.7, "Current selection: None") npcid = globals.spawndialog.m_spawnEntryNpcIdTextCtrl.Value globals.spawndialog.Reset() # f*****g hacky shit man if eraseNpcId == False: globals.spawndialog.m_spawnEntryNpcIdTextCtrl.SetValue(npcid) gridmanager = GridpointManager() gridmanager.ResetGridList() print "Cleared all selections !" def toggleDefaultMode(self): globals.editMode = False globals.insertMode = False globals.exploreMode = True globals.gridMode = False print "STARTUP Explore mode ACTIVATED" print "STARTUP Grid mode DEACTIVATED" self.inst4 = addInstructions(0.8, "Explore mode ON") self.inst5 = addInstructions(0.75, "Grid mode OFF") self.inst6 = addInstructions(0.7, "Current selection: None") def toggleEditMode(self): globals.editMode = True globals.insertMode = False globals.exploreMode = False print "Edit mode ACTIVATED" if self.inst4: self.inst4.destroy() self.inst4 = addInstructions(0.8, "Edit mode ON") def toggleInsertMode(self): globals.editMode = False globals.insertMode = True globals.exploreMode = False print "Insert mode ACTIVATED" if self.inst4: self.inst4.destroy() self.inst4 = addInstructions(0.8, "Insert mode ON") def toggleExploreMode(self): globals.editMode = False globals.insertMode = False globals.exploreMode = True print "Explore mode ACTIVATED" if self.inst4: self.inst4.destroy() self.inst4 = addInstructions(0.8, "Explore mode ON") def toggleGridMode(self): if globals.gridMode == False: globals.gridMode = True print "Grid mode ACTIVATED" if self.inst5: self.inst5.destroy() self.inst5 = addInstructions(0.75, "Grid mode ON") else: globals.gridMode = False print "Grid mode DEACTIVATED" if self.inst5: self.inst5.destroy() self.inst5 = addInstructions(0.75, "Grid mode OFF") def setSpeed(self, key, value): self.cam_speed = value self.setFlymodeText() def fogToggle(self): if self.fog == 1: render.clearFog() base.camLens.setFar(100000) self.fog = 0 else: render.setFog(self.linfog) base.camLens.setFar(1200) self.fog = 1 def camLightToggle(self): if self.cam_light == 0: render.setLight(self.plnp) self.cam_light = 1 else: render.clearLight(self.plnp) self.cam_light = 0 def displayKeyHelp(self): self.kh = [] msg = 'HOTKEYS:' pos = 0.75 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = '------------------' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'W: camera fwd, S: camera bck, A: rotate view left, D: rotate view right' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = '1-5: set camera movement speed' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'F: toggle Flymode/Walkmode' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'L: load a zone' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'ALT-F: toggle FOG and FAR plane on/off' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'T: toggle additional camera "torch" light on/off' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'Z: set currently loaded zone as new startup default' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) msg = 'ESC: exit World Forge' pos -= 0.05 self.kh.append(OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(-0.5, pos), align=TextNode.ALeft, scale = .04)) def hideKeyHelp(self): for n in self.kh: n.removeNode() def setFlymodeText(self): zname = '' if self.zone: zname = self.zone.name if self.flyMode == 0: self.inst0.setText("[WALKMODE][%i] %s" % (self.cam_speed+1, zname)) else: self.inst0.setText("[FLYMODE][%i] %s " % (self.cam_speed+1, zname)) def toggleFlymode(self): zname = '' if self.zone: zname = self.zone.name if self.flyMode == 0: self.flyMode = 1 else: self.flyMode = 0 self.setFlymodeText() # Define a procedure to move the camera. def spinCameraTask(self, task): angleDegrees = task.time * 6.0 angleRadians = angleDegrees * (pi / 180.0) base.camera.setPos(20 * sin(angleRadians), -20.0 * cos(angleRadians), 3) base.camera.setHpr(angleDegrees, 0, 0) return task.cont def camTask(self, task): if globals.hasClickedSpawn: base.camera.setPos(globals.selectedSpawnPoint3D) self.campos = globals.selectedSpawnPoint3D globals.hasClickedSpawn = False elif globals.hasClickedGrid: base.camera.setPos(globals.selectedGridPoint3D) self.campos = globals.selectedGridPoint3D globals.hasClickedGrid = False else: # query the mouse mouse_dx = 0 mouse_dy = 0 # if we have a mouse and the right button is depressed if base.mouseWatcherNode.hasMouse(): if self.keyMap["mouse3"] != 0: self.mouse_accum.update() else: self.mouse_accum.reset() mouse_dx = self.mouse_accum.dx mouse_dy = self.mouse_accum.dy self.rXSpeed = fabs(self.mouse_accum.dx) * (self.cam_speed+1) * max(5 * 1000/self.xres,3) self.rYSpeed = fabs(self.mouse_accum.dy) * (self.cam_speed+1) * max(3 * 1000/self.yres,1) if (self.keyMap["cam-left"]!=0 or mouse_dx < 0): if self.rSpeed < 160: self.rSpeed += 80 * globalClock.getDt() if mouse_dx != 0: self.camHeading += self.rXSpeed * globalClock.getDt() else: self.camHeading += self.rSpeed * globalClock.getDt() if self.camHeading > 360.0: self.camHeading = self.camHeading - 360.0 elif (self.keyMap["cam-right"]!=0 or mouse_dx > 0): if self.rSpeed < 160: self.rSpeed += 80 * globalClock.getDt() if mouse_dx != 0: self.camHeading -= self.rXSpeed * globalClock.getDt() else: self.camHeading -= self.rSpeed * globalClock.getDt() if self.camHeading < 0.0: self.camHeading = self.camHeading + 360.0 else: self.rSpeed = 80 if mouse_dy > 0: self.camPitch += self.rYSpeed * globalClock.getDt() elif mouse_dy < 0: self.camPitch -= self.rYSpeed * globalClock.getDt() # set camera heading and pitch base.camera.setHpr(self.camHeading, self.camPitch, 0) # viewer position (camera) movement control v = render.getRelativeVector(base.camera, Vec3.forward()) if not self.flyMode: v.setZ(0.0) move_speed = self.cam_speeds[self.cam_speed] if self.keyMap["forward"] == 1: self.campos += v * move_speed * globalClock.getDt() if self.keyMap["backward"] == 1: self.campos -= v * move_speed * globalClock.getDt() # actually move the camera lastPos = base.camera.getPos() base.camera.setPos(self.campos) # self.plnp.setPos(self.campos) # move the point light with the viewer position # WALKMODE: simple collision detection # we simply check a ray from slightly below the "eye point" straight down # for geometry collisions and if there are any we detect the point of collision # and adjust the camera's Z accordingly if self.flyMode == 0: # move the camera to where it would be if it made the move # the colliderNode moves with it # base.camera.setPos(self.campos) # check for collissons self.cTrav.traverse(render) entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) # print 'collision' entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries) > 0): # and (entries[0].getIntoNode().getName() == "terrain"): # print len(entries) self.campos.setZ(entries[0].getSurfacePoint(render).getZ()+self.eyeHeight) else: self.campos = lastPos base.camera.setPos(self.campos) #if (base.camera.getZ() < self.player.getZ() + 2.0): # base.camera.setZ(self.player.getZ() + 2.0) # update loc and hpr display pos = base.camera.getPos() hpr = base.camera.getHpr() self.inst2.setText('Loc: %.2f, %.2f, %.2f' % (pos.getX(), pos.getY(), pos.getZ())) self.inst3.setText('Hdg: %.2f, %.2f, %.2f' % (hpr.getX(), hpr.getY(), hpr.getZ())) return task.cont def exitGame(self): globals.database.conn.close() print "DB connection closed !" sys.exit(0) def resizeGame(self,win): props = base.win.getProperties() self.xres = props.getXSize() self.yres = props.getYSize() self.xres_half = self.xres / 2 self.yres_half = self.yres / 2 self.saveDefaultRes() #Records the state of the arrow keys # this is used for camera control def setKey(self, key, value): self.keyMap[key] = value # ------------------------------------------------------------------------- # this is the mythical MAIN LOOP :) def update(self): if self.zone_reload_name != None: self.doReload(self.zone_reload_name) self.zone_reload_name = None if self.zone != None: self.zone.update() taskMgr.step() # ZONE loading ------------------------------------------------------------ # general zone loader driver # removes existing zone (if any) and load the new one def loadZone(self, name, path): if path[len(path)-1] != '/': path += '/' if self.zone: self.zone.rootNode.removeNode() self.zone = Zone(self, name, path) error = self.zone.load() if error == 0: self.consoleOff() self.setFlymodeText() base.setBackgroundColor(self.fog_colour) def saveDefaultRes(self): cfg = self.configurator.config cfg['xres'] = str(self.xres) cfg['yres'] = str(self.yres) # initial world load after bootup def load(self): cfg = self.configurator.config zone_name = cfg['default_zone'] globals.currentZone = zone_name basepath = cfg['basepath'] self.loadZone(zone_name, basepath) # zone reload user interface # this gets called from our update loop when it detects that zone_reload_name has been set # we do this in this convoluted fashion in order to keep the main loop taskMgr updates ticking # because otherwise our status console output at various stages during the zone load would not # be displayed. Yes, this is hacky. def doReload(self, name): cfg = self.configurator.config basepath = cfg['basepath'] self.loadZone(name, basepath) # form dialog callback # this gets called from the form when the user has entered a something # (hopefully a correct zone short name) def reloadZoneDialogCB(self, name): self.frmDialog.end() self.zone_reload_name = name self.toggleControls(1) # this is called when the user presses "l" # it disables normal controls and fires up our query form dialog def reloadZone(self): base.setBackgroundColor((0,0,0)) self.toggleControls(0) self.consoleOn() self.frmDialog = FileDialog( "Please enter the shortname of the zone you wish to load:", "Examples: qrg, blackburrow, freportn, crushbone etc.", self.reloadZoneDialogCB) self.frmDialog.activate() # relies on the main update loop to run ##################################### # Custom methods ##################################### # Handles populating the zone with spawn data from the EQEmu DB # also makes each spawner model pickable def PopulateSpawns(self, cursor, numrows): spawn_coords = list() globals.spawn_list = list() cfg = self.configurator.config for x in range(0, numrows): row = cursor.fetchone() point = Point3(long(row["Spawn2Y"]), long(row["Spawn2X"]), long(row["Spawn2Z"])) if cfg['ignore_duplicate_spawns'] == 'True': if point not in spawn_coords: self.PlaceSpawnPointOn3dMap(row) spawn_coords.append(point) else: self.PlaceSpawnPointOn3dMap(row) def PlaceSpawnPointOn3dMap(self, row): spawn = Spawn() self.InitSpawnData(spawn, row) spawn.model = loader.loadModel(spawn.modelname) spawn.initmodel() spawn.model.reparentTo(render) spawn.initheadingfromdb(row["Spawn2Heading"]) spawn.placeintoworld(row["Spawn2Y"], row["Spawn2X"], row["Spawn2Z"]) min, macks = spawn.model.getTightBounds() radius = max([macks.getY() - min.getY(), macks.getX() - min.getX()]) / 2 cs = CollisionSphere(row["Spawn2X"], row["Spawn2Y"], row["Spawn2Z"], radius) csNode = spawn.model.attachNewNode(CollisionNode("modelCollide")) csNode.node().addSolid(cs) # TODO: ADD MORE TAGS?? spawn.model.setTag("name", row["NpcName"]) spawn.model.setTag("spawngroup_name", row["spawngroup_name"]) spawn.model.setTag("spawn2id", str(row["Spawn2Id"])) spawn.model.setTag("type", "spawn") globals.picker.makePickable(spawn.model) globals.spawn_list.append(spawn) # Initializes a spawn object with database values def InitSpawnData(self, spawn, row): spawn.spawngroup_id = row["Spawngroup_id"] spawn.spawngroup_name = row["spawngroup_name"] spawn.spawngroup_minx = row["Spawngroup_minX"] spawn.spawngroup_maxx= row["Spawngroup_maxX"] spawn.spawngroup_miny = row["Spawngroup_minY"] spawn.spawngroup_maxy = row["Spawngroup_maxY"] spawn.spawngroup_dist = row["Spawngroup_dist"] spawn.spawngroup_mindelay = row["Spawngroup_mindelay"] spawn.spawngroup_delay = row["Spawngroup_delay"] spawn.spawngroup_despawn = row["Spawngroup_despawntimer"] spawn.spawngroup_despawntimer = row["Spawngroup_despawntimer"] spawn.spawngroup_spawnlimit = row["Spawngroup_spawnlimit"] spawn.spawnentry_id = row["Spawn2Id"] spawn.spawnentry_npcid = row["NpcId"] spawn.spawnentry_npcname = row["NpcName"] spawn.spawnentry_chance = row["Spawnentry_chance"] spawn.spawnentry_x = row["Spawn2X"] spawn.spawnentry_y = row["Spawn2Y"] spawn.spawnentry_z = row["Spawn2Z"] spawn.spawnentry_heading = row["Spawn2Heading"] spawn.spawnentry_respawn = row["Spawn2Respawn"] spawn.spawnentry_variance = row["Spawn2Variance"] spawn.spawnentry_pathgrid = row["Spawn2Grid"] spawn.spawnentry_condition = row["Spawn2Condition"] spawn.spawnentry_condvalue = row["Spawn2CondValue"] spawn.spawnentry_version = row["Spawn2Version"] spawn.spawnentry_enabled = row["Spawn2Enabled"] spawn.spawnentry_animation = row["Spawn2Animation"] spawn.spawnentry_zone = row["Spawn2Zone"] spawn.spawnentry_originalx = row["Spawn2X"] spawn.spawnentry_originaly = row["Spawn2Y"] spawn.spawnentry_originalz = row["Spawn2Z"] spawn.spawnentry_originalheading = row["Spawn2Heading"] # Initializes the camera position upon startup def InitCameraPosition(self): world.campos = Point3(-155.6, 41.2, 4.9 + world.eyeHeight) world.camHeading = 270.0 base.camera.setPos(world.campos) def GetCamera(self): return base.camera
class Usuario(object): ''' Usuario ''' def __init__(self, dadosUsuario, principal=False): self.key = dadosUsuario['key'] self.nick = dadosUsuario['nick'] self.vida_real = float(dadosUsuario['vida_real']) self.vida_total = float(dadosUsuario['vida_total']) self.mana_real = float(dadosUsuario['mana_real']) self.mana_total = float(dadosUsuario['mana_total']) self.forca = float(dadosUsuario['forca']) self.velocidade = float(dadosUsuario['velocidade']) self.velocidade_atack = float(dadosUsuario['velocidade_atack']) self.estaMovendo = False self.estaRodando = False self.__task_name = "Task Usuario - " + self.key self.keyMap = { TECLA_esquerda: EVENT_up, TECLA_direita: EVENT_up, TECLA_frente: EVENT_up, TECLA_traz: EVENT_up } pandaFileModelo = get_path_modelo("ralph") pandaFileAnimacaoRun = get_path_animacao("ralph-run") pandaFileAnimacaoWalk = get_path_animacao("ralph-walk") self.modelo = Actor(pandaFileModelo, { "run": pandaFileAnimacaoRun, "walk": pandaFileAnimacaoWalk }) self.modelo.reparentTo(render) self.modelo.setScale(SCALE_MODELOS) self.set_pos((float(dadosUsuario['x']), float(dadosUsuario['y']), float(dadosUsuario['z']))) self.set_h(float(dadosUsuario['h'])) if not principal: self.text = Text(parent=self.modelo, pos=(0, 0, 5.5), scale=.5, align='center', cor=COR_VERDE, text=self.nick) self.text.billboardEffect() self.__setup_collision() taskMgr.add(self.__task_movimentacao, self.__task_name, sort=1) def get_x(self): return self.modelo.getX() def get_y(self): return self.modelo.getY() def get_z(self): return self.modelo.getZ() def get_h(self): return self.modelo.getH() def get_pos(self): return self.modelo.getPos() def set_x(self, x): self.modelo.setX(x) def set_y(self, y): self.modelo.setY(y) def set_z(self, z): self.modelo.setZ(z) def set_h(self, h): self.modelo.setH(h) def set_pos(self, pos): self.modelo.setPos(pos) def delete(self): taskMgr.remove(self.__task_name) self.modelo.delete() def __setup_collision(self): #Colisao self.cTrav = CollisionTraverser('usuarioTraverser') self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 5) self.ralphGroundRay.setDirection(0, 0, -1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.modelo.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) #self.ralphGroundColNp.show() #self.cTrav.showCollisions(render) #Colisao def __task_movimentacao(self, task): dt = globalClock.getDt() startpos = self.modelo.getPos() #movimentos usuario modelo if self.keyMap[TECLA_esquerda] == EVENT_down and self.keyMap[ TECLA_direita] == EVENT_up: self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt)) if not self.estaRodando: self.estaRodando = True elif self.keyMap[TECLA_direita] == EVENT_down and self.keyMap[ TECLA_esquerda] == EVENT_up: self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt) * -1) if not self.estaRodando: self.estaRodando = True elif self.estaRodando: self.estaRodando = False if self.keyMap[TECLA_frente] == EVENT_down and self.keyMap[ TECLA_traz] == EVENT_up: self.modelo.setY(self.modelo, ((self.velocidade * 2) * dt) * -1) if self.estaMovendo is False: self.modelo.loop("run") self.estaMovendo = True elif self.keyMap[TECLA_traz] == EVENT_down and self.keyMap[ TECLA_frente] == EVENT_up: self.modelo.setY(self.modelo, (self.velocidade * dt)) if self.estaMovendo is False: self.modelo.loop("walk") self.estaMovendo = True elif self.estaMovendo: self.modelo.stop() self.modelo.pose("walk", 5) self.estaMovendo = False #movimentos usuario modelo if self.estaMovendo: self.cTrav.traverse(render) if self.ralphGroundHandler.getNumEntries() == 1: entry = self.ralphGroundHandler.getEntry(0) if entry.getIntoNode().getName() == "terrain": self.modelo.setZ(entry.getSurfacePoint(render).getZ()) else: self.modelo.setPos(startpos) return task.cont
def __init__(self): # Initialize the ShowBase class from which we inherit, which will # create a window and set up everything we need for rendering into it. ShowBase.__init__(self) base.setBackgroundColor(0, 0, 0) self.accept("escape", sys.exit) # Escape quits self.disableMouse() camera.setPosHpr(0, 0, 0, 0, 0, 0) lens = PerspectiveLens() lens.setFov(90, 60) lens.setNear(0.01) lens.setFar(100000) self.cam.node().setLens(lens) self.ballSize = 0.025 self.cueLength = 0.2 # self.ballRoot = render.attachNewNode("ballRoot") # #self.ball = loader.loadModel("models/ball") # self.ball = loader.loadModel("models/ball_0_center.egg") # #self.ball = loader.loadModel("models/ball.dae") # self.ball.setScale(ballSize, ballSize, ballSize) # self.ball.reparentTo(self.ballRoot) # #print(self.ball.getBounds()) # #exit(1) # #self.ballSphere = self.ball.find("**/ball") # #print(self.ball.getScale()[0]) # cs = CollisionSphere(0, 0, 0, 1) # self.ballSphere = self.ball.attachNewNode(CollisionNode('ball')) # self.ballSphere.node().addSolid(cs) # self.ballSphere.node().setFromCollideMask(BitMask32.bit(0)) # self.ballSphere.node().setIntoCollideMask(BitMask32.bit(1)) self.sceneIndex = 2 self.planeInfo = PlaneScene(self.sceneIndex) self.planeScene = self.planeInfo.generateEggModel() self.planeScene.setTwoSided(True) self.planeScene.reparentTo(render) self.planeScene.hide() planeTriangles, horizontalPlaneTriangles, self.gravityDirection = self.planeInfo.getPlaneTriangles( ) self.ballRoots = [] self.balls = [] self.ballSpheres = [] self.ballGroundRays = [] for ballIndex in xrange(3): ballRoot = render.attachNewNode("ballRoot_" + str(ballIndex)) ball = loader.loadModel("models/ball_" + str(ballIndex) + "_center.egg") ball.setScale(self.ballSize, self.ballSize, self.ballSize) cs = CollisionSphere(0, 0, 0, 1) ballSphere = ball.attachNewNode( CollisionNode('ball_' + str(ballIndex))) ballSphere.node().addSolid(cs) ballSphere.node().setFromCollideMask( BitMask32.bit(0) | BitMask32.bit(1) | BitMask32.bit(3) | BitMask32.bit(4)) ballSphere.node().setIntoCollideMask(BitMask32.bit(1)) ball.reparentTo(ballRoot) self.ballRoots.append(ballRoot) self.balls.append(ball) self.ballSpheres.append(ballSphere) ballGroundRay = CollisionRay() # Create the ray ballGroundRay.setOrigin(0, 0, 0) # Set its origin ballGroundRay.setDirection( self.gravityDirection[0], self.gravityDirection[1], self.gravityDirection[2]) # And its direction # Collision solids go in CollisionNode # Create and name the node ballGroundCol = CollisionNode('ball_ray_' + str(ballIndex)) ballGroundCol.addSolid(ballGroundRay) # Add the ray ballGroundCol.setFromCollideMask( BitMask32.bit(2)) # Set its bitmasks ballGroundCol.setIntoCollideMask(BitMask32.allOff()) # Attach the node to the ballRoot so that the ray is relative to the ball # (it will always be 10 feet over the ball and point down) ballGroundColNp = ballRoot.attachNewNode(ballGroundCol) self.ballGroundRays.append(ballGroundColNp) ballRoot.hide() continue # Finally, we create a CollisionTraverser. CollisionTraversers are what # do the job of walking the scene graph and calculating collisions. # For a traverser to actually do collisions, you need to call # traverser.traverse() on a part of the scene. Fortunately, ShowBase # has a task that does this for the entire scene once a frame. By # assigning it to self.cTrav, we designate that this is the one that # it should call traverse() on each frame. self.cTrav = CollisionTraverser() # Collision traversers tell collision handlers about collisions, and then # the handler decides what to do with the information. We are using a # CollisionHandlerQueue, which simply creates a list of all of the # collisions in a given pass. There are more sophisticated handlers like # one that sends events and another that tries to keep collided objects # apart, but the results are often better with a simple queue self.cHandler = CollisionHandlerQueue() # Now we add the collision nodes that can create a collision to the # traverser. The traverser will compare these to all others nodes in the # scene. There is a limit of 32 CollisionNodes per traverser # We add the collider, and the handler to use as a pair #self.cTrav.addCollider(self.ballSphere, self.cHandler) for ballSphere in self.ballSpheres: self.cTrav.addCollider(ballSphere, self.cHandler) continue for ballGroundRay in self.ballGroundRays: self.cTrav.addCollider(ballGroundRay, self.cHandler) continue #self.cTrav.addCollider(self.ballGroundColNp, self.cHandler) # Collision traversers have a built in tool to help visualize collisions. # Uncomment the next line to see it. #self.cTrav.showCollisions(render) # This section deals with lighting for the ball. Only the ball was lit # because the maze has static lighting pregenerated by the modeler ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.55, .55, .55, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(LVector3(0, 0, -1)) directionalLight.setColor((0.375, 0.375, 0.375, 1)) directionalLight.setSpecularColor((1, 1, 1, 1)) for ballRoot in self.ballRoots: ballRoot.setLight(render.attachNewNode(ambientLight)) ballRoot.setLight(render.attachNewNode(directionalLight)) continue # This section deals with adding a specular highlight to the ball to make # it look shiny. Normally, this is specified in the .egg file. m = Material() m.setSpecular((1, 1, 1, 1)) m.setShininess(96) for ball in self.balls: ball.setMaterial(m, 1) continue self.original = False if self.original: camera.setPosHpr(0, 0, 25, 0, -90, 0) self.maze = loader.loadModel("models/maze") self.maze.reparentTo(render) self.walls = self.maze.find("**/wall_collide") self.walls.node().setIntoCollideMask(BitMask32.bit(0)) self.walls.show() pass #planeTriangles, planeNormals = self.planeInfo.getPlaneGeometries() self.triNPs = [] for triangleIndex, triangle in enumerate(planeTriangles): #print(triangleIndex) #for triangle in triangles: #print(triangle) tri = CollisionPolygon( Point3(triangle[0][0], triangle[0][1], triangle[0][2]), Point3(triangle[1][0], triangle[1][1], triangle[1][2]), Point3(triangle[2][0], triangle[2][1], triangle[2][2])) triNP = render.attachNewNode( CollisionNode('tri_' + str(triangleIndex))) triNP.node().setIntoCollideMask(BitMask32.bit(0)) triNP.node().addSolid(tri) self.triNPs.append(triNP) #triNP.show() continue #print(horizontalPlaneTriangles) for triangleIndex, triangle in enumerate(horizontalPlaneTriangles): #print(triangleIndex) #for triangle in triangles: #print(triangle) tri = CollisionPolygon( Point3(triangle[0][0], triangle[0][1], triangle[0][2]), Point3(triangle[1][0], triangle[1][1], triangle[1][2]), Point3(triangle[2][0], triangle[2][1], triangle[2][2])) triNP = render.attachNewNode( CollisionNode('ground_' + str(triangleIndex))) triNP.node().setIntoCollideMask(BitMask32.bit(2)) triNP.node().addSolid(tri) self.triNPs.append(triNP) #triNP.show() continue # tri = CollisionPolygon(Point3(-1, 4, -1), Point3(2, 4, -1), Point3(2, 4, 2)) # triNP = render.attachNewNode(CollisionNode('tri')) # triNP.node().setIntoCollideMask(BitMask32.bit(0)) # triNP.node().addSolid(tri) # triNP.show() #self.planeScene.node().setIntoCollideMask(BitMask32.bit(0)) # roomRootNP = self.planeScene # roomRootNP.flattenLight() # mesh = BulletTriangleMesh() # polygons = roomRootNP.findAllMatches("**/+GeomNode") # # p0 = Point3(-10, 4, -10) # # p1 = Point3(-10, 4, 10) # # p2 = Point3(10, 4, 10) # # p3 = Point3(10, 4, -10) # # mesh.addTriangle(p0, p1, p2) # # mesh.addTriangle(p1, p2, p3) # print(polygons) # for polygon in polygons: # geom_node = polygon.node() # #geom_node.reparentTo(self.render) # #print(geom_node.getNumGeoms()) # ts = geom_node.getTransform() # #print(ts) # for geom in geom_node.getGeoms(): # mesh.addGeom(geom, ts) # continue # continue # #self.scene = roomRootNP # shape = BulletTriangleMeshShape(mesh, dynamic=False) # #shape = BulletPlaneShape(Vec3(0, 0, 1), 1) # room = BulletRigidBodyNode('scene') # room.addShape(shape) # #room.setLinearDamping(0.0) # #room.setFriction(0.0) # print(shape) # room.setDeactivationEnabled(False) # roomNP = render.attachNewNode(room) # roomNP.setPos(0, 0, 0) # roomNP.node().setIntoCollideMask(BitMask32.bit(0)) # self.world = BulletWorld() # self.world.setGravity(Vec3(0, 0, 0)) # self.world.attachRigidBody(roomNP.node()) #room.setRestitution(1) #self.roomNP = self.scene self.cueRoot = render.attachNewNode("cueRoot") self.cue = loader.loadModel("models/cue_center.egg") self.cue.setScale(self.cueLength * 3, self.cueLength * 3, self.cueLength) self.cue.reparentTo(self.cueRoot) self.cuePos = (10, 0, 0) 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 separate it self.pickerNode.setFromCollideMask(BitMask32.bit(2)) self.pickerNode.setIntoCollideMask(BitMask32.allOff()) 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.cTrav.addCollider(self.pickerNP, self.cHandler) self.accept("mouse1", self.hit) # left-click grabs a piece self.holeLength = 0.06 holePos, holeHpr = self.planeInfo.getHolePos() self.holeRoot = render.attachNewNode("holeRoot") #self.hole = loader.loadModel("models/hole_horizontal_center.egg") self.hole = loader.loadModel("models/hole_color.egg") #self.hole = loader.loadModel("models/billiards_hole_center.egg") self.hole.setScale(self.holeLength, self.holeLength, self.holeLength) self.hole.reparentTo(self.holeRoot) self.hole.setTwoSided(True) self.holeRoot.setPos(holePos[0], holePos[1], holePos[2]) self.holeRoot.setHpr(holeHpr[0], holeHpr[1], holeHpr[2]) #tex = loader.loadTexture('models/Black_Hole.jpg') #self.hole.setTexture(tex, 1) self.holeRoot.hide() ct = CollisionTube(0, 0, 0, 0, 0.001, 0, 0.5) self.holeTube = self.hole.attachNewNode(CollisionNode('hole')) self.holeTube.node().addSolid(ct) self.holeTube.node().setFromCollideMask(BitMask32.allOff()) self.holeTube.node().setIntoCollideMask(BitMask32.bit(4)) #self.holeTube.show() inPortalPos, inPortalHpr, outPortalPos, outPortalHpr, self.portalNormal = self.planeInfo.getPortalPos( ) self.portalLength = 0.06 self.inPortalRoot = render.attachNewNode("inPortalRoot") self.inPortal = loader.loadModel("models/portal_2_center.egg") self.inPortal.setScale(self.portalLength, self.portalLength, self.portalLength) self.inPortal.reparentTo(self.inPortalRoot) self.inPortalRoot.setPos(inPortalPos[0], inPortalPos[1], inPortalPos[2]) self.inPortalRoot.setHpr(inPortalHpr[0], inPortalHpr[1], inPortalHpr[2]) self.inPortalRoot.hide() ct = CollisionTube(0, 0, 0, 0, 0.001, 0, 1) self.inPortalTube = self.inPortal.attachNewNode( CollisionNode('portal_in')) self.inPortalTube.node().addSolid(ct) self.inPortalTube.node().setFromCollideMask(BitMask32.allOff()) self.inPortalTube.node().setIntoCollideMask(BitMask32.bit(3)) #self.inPortalTube.hide() self.outPortalRoot = render.attachNewNode("outPortalRoot") self.outPortal = loader.loadModel("models/portal_2_center.egg") self.outPortal.setScale(self.portalLength, self.portalLength, self.portalLength) self.outPortal.reparentTo(self.outPortalRoot) self.outPortalRoot.setPos(outPortalPos[0], outPortalPos[1], outPortalPos[2]) self.outPortalRoot.setHpr(outPortalHpr[0], outPortalHpr[1], outPortalHpr[2]) self.outPortalRoot.hide() ct = CollisionTube(0, 0, 0, 0, 0.001, 0, 1) self.outPortalTube = self.outPortal.attachNewNode( CollisionNode('portal_out')) self.outPortalTube.node().addSolid(ct) self.outPortalTube.node().setFromCollideMask(BitMask32.allOff()) self.outPortalTube.node().setIntoCollideMask(BitMask32.bit(3)) #self.outPortalTube.hide() #self.inPortalTube.show() #self.outPortalTube.show() #self.holeTube.show() #self.cTrav.addCollider(self.holeTube, self.cHandler) background_image = loader.loadTexture('dump/' + str(self.sceneIndex) + '_image.png') cm = CardMaker('background') cm.setHas3dUvs(True) info = np.load('dump/' + str(self.sceneIndex) + '_info.npy') #self.camera = getCameraFromInfo(self.info) depth = 10.0 sizeU = info[2] / info[0] * depth sizeV = info[6] / info[5] * depth cm.setFrame(Point3(-sizeU, depth, -sizeV), Point3(sizeU, depth, -sizeV), Point3(sizeU, depth, sizeV), Point3(-sizeU, depth, sizeV)) self.card = self.render.attachNewNode(cm.generate()) self.card.setTransparency(True) self.card.setTexture(background_image) self.card.hide() self.ballGroundMap = {} self.ballBouncing = np.full(len(self.balls), 3) self.started = False self.start() self.hitIndex = 0 self.showing = 'none' self.showingProgress = 0 partsScene = PartsScene(self.sceneIndex) self.planeNPs, self.planeCenters = partsScene.generateEggModel() return
class Player(): def __init__(self, camera, accept, render, loader, maxJPHeight): #initial variables and sounds self.developer = True # Developer tools (building tools) will be accessible if this is turned on. self.gameMode = self.mode0 # the current playerUpdate function that is in use # self.playerModeParameters = () # the parameters being fed into the function above. self.groundContact = False # if the player is on the ground or a surface, gravity will not pull the player below the surface self.jetPack_energy = 100 self.maximumHeight = maxJPHeight # maximum height in which the jetpack can fly to, this is dependent on the map loaded. self.jetPack_AUDIO = loader.loadSfx("assets/base/sounds/jetpack2.wav") self.jetPack_AUDIO.setLoop(True) self.vertical_velocity = 0 # Current Z velocity, positive = Upwards. self.z_velocity = 0 # Current Y velocity self.x_velocity = 0 self.movingZ = False self.movingX = False #initiate GUI self.HUD = GUI() self.playerHolder = render.attachNewNode('player') # camera control - Hiding mouse and using it to rotate the camera props = WindowProperties() props.setCursorHidden(True) props.setMouseMode(WindowProperties.M_relative) base.win.requestProperties(props) # PLAYER MODEL SCENE GRAPH self.thirdPersonCamera_ZOOM = -50 # initial distance of third person camera. self.character = loader.loadModel( 'assets/base/models/playerModel/player.bam') self.toggleFPCam = False # Whether first person camera is on, this is initially off. self.character.setPos(0, 0, 0) self.character.reparentTo(self.playerHolder) self.playerBase = self.playerHolder.attachNewNode('camParent') self.thirdPersonNode = self.playerBase.attachNewNode('thirdPersonCam') camera.reparentTo(self.thirdPersonNode) self.mouseSeconds = [] self.playerHolder.setScale(4) self.monitor = loader.loadModel( 'assets/base/models/faces/playerMonitor.bam') self.monitor.reparentTo(self.playerHolder) self.cTrav = CollisionTraverser() # Horizontal collisions self.pusher = CollisionHandlerPusher() self.pusher.horizontal = True self.colliderNode = CollisionNode("player") self.colliderNode.addSolid(CollisionSphere(0, 0, 0, 2)) self.colliderNode.setFromCollideMask(CollideMask.bit(1)) self.colliderNode.setFromCollideMask(CollideMask.bit(0)) self.colliderNode.setIntoCollideMask(BitMask32.allOff()) collider = self.playerHolder.attachNewNode(self.colliderNode) collider.show() self.pusher.addCollider(collider, self.playerHolder) self.cTrav.addCollider(collider, self.pusher) # Vertical collisions - Downwards self.groundRay = CollisionRay() self.groundRay.setDirection(0, 0, -1) self.groundRayCol = CollisionNode('playerRay') self.groundRayCol.addSolid(self.groundRay) self.groundRayCol.setFromCollideMask(CollideMask.bit(1)) self.groundRayCol.setIntoCollideMask(CollideMask.allOff()) self.groundColNp = self.playerHolder.attachNewNode(self.groundRayCol) self.groundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.groundColNp, self.groundHandler) # Third Person Camera Collision self.cameraRay = CollisionSegment() self.cameraRayNode = CollisionNode('camerRay') self.cameraRayNode.addSolid(self.cameraRay) self.cameraRayNodePath = render.attachNewNode(self.cameraRayNode) self.cameraCollisionHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.cameraRayNodePath, self.cameraCollisionHandler) # Vertical collisions - Upwards self.upwardsRay = CollisionRay() self.upwardsRay.setDirection(0, 0, 1) self.upwardsRayCol = CollisionNode('playerupRay') self.upwardsRayCol.addSolid(self.upwardsRay) self.upwardsRayCol.setFromCollideMask(CollideMask.bit(1)) self.upwardsRayCol.setIntoCollideMask(CollideMask.allOff()) self.upwardsColNp = self.playerHolder.attachNewNode(self.upwardsRayCol) self.upwardsHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.upwardsColNp, self.upwardsHandler) #self.cTrav.showCollisions(render) if self.developer == True: self.tool = buildingTool( "newbuildings", self.playerHolder, loader, accept) # Load up building tool if developer modee is on. #self.setupLighting() # light #initial position self.playerHolder.setPos(45178.3, 43109.3, 0) self.keyMap = { "left": False, "right": False, "forward": False, "backwards": False, "change_camera": False, "leftClick": False, "space": False, "p": False, "scrollup": False, "scrolldown": False } accept("escape", sys.exit) accept("w", self.updateKey, ["forward", True]) # accept("w-up", self.updateKey, ["forward", False]) accept("a", self.updateKey, ["left", True]) accept("a-up", self.updateKey, ["left", False]) accept("s", self.updateKey, ["backwards", True]) accept("s-up", self.updateKey, ["backwards", False]) accept("d", self.updateKey, ["right", True]) accept("d-up", self.updateKey, ["right", False]) accept("c", self.updateKey, ["change_camera", True]) accept("wheel_up", self.updateKey, ["scrollup", True]) accept("wheel_down", self.updateKey, ["scrolldown", True]) accept("p", self.updateKey, ["p", True]) accept("p-up", self.updateKey, ["p", False]) accept("space", self.updateKey, ["space", True]) accept("space-up", self.updateKey, ["space", False]) self.playerMode = playerModes( self.playerBase, self.playerHolder, self.character, self.vertical_velocity, self.z_velocity, self.x_velocity, self.keyMap, self.monitor, self.thirdPersonNode, self.jetPack_energy, self.jetPack_AUDIO, self.thirdPersonCamera_ZOOM, self.toggleFPCam, self.HUD, self.cTrav, self.groundHandler, self.upwardsHandler, self.maximumHeight) def playerUpdate(self, task): # our UPDATE TASK self.gameMode() return task.cont def updateKey(self, key, value): self.keyMap[key] = value if key == "change_camera": self.changeCamera() self.scrollFactor = 10 if key == "scrollup": # third person zoom in/out self.thirdPersonCamera_ZOOM += self.scrollFactor if key == "scrolldown": self.thirdPersonCamera_ZOOM -= self.scrollFactor def changeCamera(self): # Toggle first person camera. if self.toggleFPCam == False: self.toggleFPCam = True else: self.toggleFPCam = False def recenterMouse(self): base.win.movePointer(0, int(base.win.getProperties().getXSize() / 2), int(base.win.getProperties().getYSize() / 2)) def setupLighting(self): plight = PointLight('plight') plight.setColor((1, 1, 1, 1)) plnp = self.playerHolder.attachNewNode(plight) plnp.setPos(0, 1, 7) render.setLight(plnp) # PLAYER MODES, HOW THE USER INTERACTS AND CONTROLS WITH THE USER # MODE 0 # Mode 0 is the default update mode, it allows WASD movement, # mouse controlled camera rotations, first person and third # person switching, it also has GUI display and player physics. def mode0(self): #THIRD PERSON CAMERA COLLISION # print("thirdpersonnode") # print(self.playerBase.getHpr()) # print("pb") # print(self.character.getHpr()) deltaTime = globalClock.getDt() self.movingZ = False self.movingX = False self.walkConstant = 25 self.rotateConstant = 750 # Keyboard controls # LEVITATION STUFF (FORMERLY CALLED JETPACK) if self.keyMap["space"] and self.jetPack_energy > 0: jetpack = 0.00001 * (( (self.playerHolder.getZ()) - self.maximumHeight)**2) + 9.81 self.playerHolder.setZ(self.playerBase, jetpack) self.jetPack_energy -= 15 * deltaTime self.walkConstant = 70 self.jetPack_AUDIO.play() else: self.jetPack_AUDIO.stop() if self.jetPack_energy < 100: self.jetPack_energy += 10 * deltaTime if self.jetPack_energy > 100: self.jetPack_energy = 100 self.HUD.jetpackStatus.text = "Levitation Battery: " + str( int(self.jetPack_energy)) + "%" if (self.keyMap["forward"] or self.keyMap["backwards"]) and (self.keyMap["right"] or self.keyMap["left"]): self.walkConstant = int(((self.walkConstant**2) / 2)**0.5) # WASD MOVEMENT if self.keyMap["forward"]: self.monitor.setH(self.playerBase.getH() - 90) self.movingZ = True self.z_velocity += 5 if self.z_velocity > self.walkConstant: self.z_velocity = self.walkConstant if self.keyMap["right"]: self.monitor.setH(self.playerBase.getH() - 180) self.movingX = True self.x_velocity += 5 if self.x_velocity > self.walkConstant: self.x_velocity = self.walkConstant if self.keyMap["p"]: print(self.playerHolder.getPos()) print(self.thirdPersonCamera_ZOOM) self.gameMode = self.mode1 if self.keyMap["left"]: self.monitor.setH(self.playerBase.getH()) self.movingX = True self.x_velocity -= 5 if self.x_velocity < -self.walkConstant: self.x_velocity = -self.walkConstant if self.keyMap["backwards"]: self.monitor.setH(self.playerBase.getH() + 90) self.movingZ = True self.z_velocity -= 20 if self.z_velocity < -self.walkConstant: self.z_velocity = -self.walkConstant if self.movingZ == False: if self.z_velocity <= 7 or ( self.z_velocity >= -5 and self.z_velocity < 0): # Shaking bug fix self.z_velocity = 0 if self.z_velocity > 0: self.z_velocity -= 10 elif self.z_velocity < 0: self.z_velocity += 10 if self.movingX == False: if self.x_velocity <= 5 or ( self.x_velocity >= -5 and self.x_velocity < 0): # Shaking bug fix self.x_velocity = 0 if self.x_velocity > 0: self.x_velocity -= 10 elif self.x_velocity < 0: self.x_velocity += 10 # MONITOR HEADINGS FOR DOUBLE INPUT if self.keyMap["forward"] and self.keyMap["right"]: self.monitor.setH(self.playerBase.getH() - 135) elif self.keyMap["forward"] and self.keyMap["left"]: self.monitor.setH(self.playerBase.getH() - 45) elif self.keyMap["backwards"] and self.keyMap["left"]: self.monitor.setH(self.playerBase.getH() + 45) elif self.keyMap["backwards"] and self.keyMap["right"]: self.monitor.setH(self.playerBase.getH() + 135) # third person camera control if (self.toggleFPCam == False): # third person camera controls if (base.mouseWatcherNode.hasMouse() == True): mouseposition = base.mouseWatcherNode.getMouse() self.thirdPersonNode.setP(mouseposition.getY() * 30) self.playerBase.setH(mouseposition.getX() * -50) if (mouseposition.getX() < 0.1 and mouseposition.getX() > -0.1): self.playerBase.setH(self.playerBase.getH()) if self.thirdPersonNode.getP() > 90: self.recenterMouse() self.thirdPersonNode.setP(90) # TRACK MOUSE elif self.thirdPersonNode.getP() < -90: self.recenterMouse() self.thirdPersonNode.setP(-90) if self.thirdPersonCamera_ZOOM > -20: # validate zoom self.thirdPersonCamera_ZOOM = -20 elif self.thirdPersonCamera_ZOOM < -390: self.thirdPersonCamera_ZOOM = -390 # CAMERA STUFF # FIRST PERSON CAMERA if self.toggleFPCam: # first person camera controls camera.setPos(self.character.getPos()) # 0,-50,-10 camera.setZ(camera.getZ() + 6) self.playerHolder.hide() if (base.mouseWatcherNode.hasMouse() == True): mouseposition = base.mouseWatcherNode.getMouse() camera.setP(mouseposition.getY() * 20) self.playerBase.setH(mouseposition.getX() * -50) if (mouseposition.getX() < 0.1 and mouseposition.getX() > -0.1): self.playerBase.setH(self.playerBase.getH()) if camera.getP() > 90: self.recenterMouse() camera.setP(90) # TRACK MOUSE elif camera.getP() < -90: self.recenterMouse() camera.setP(-90) else: # takes out of first person perspective if toggleFPS is turned off. self.playerHolder.show() camera.setPos(0, self.thirdPersonCamera_ZOOM, 0) # 0,-50,-4 camera.lookAt(self.character) # movement updates self.playerHolder.setY(self.playerBase, (self.z_velocity * deltaTime)) self.playerHolder.setX(self.playerBase, (self.x_velocity * deltaTime)) # forward/backward rolling axis = self.playerBase.getQuat().getRight() angle = (self.z_velocity * deltaTime * -8) quat = Quat() quat.setFromAxisAngle(angle, axis) newVec = self.character.getQuat() * quat # print(newVec.getHpr()) self.character.setQuat(newVec) # sideways rolling axis = self.playerBase.getQuat().getForward() angle = (self.x_velocity * deltaTime * 8) quat = Quat() quat.setFromAxisAngle(angle, axis) newVec = self.character.getQuat() * quat # print(self.playerBase.getPos()) self.character.setQuat(newVec) self.cameraRay.setPointA(self.playerBase.getPos()) if camera.getPos() != (0, 0, 0): self.cameraRay.setPointB(camera.getPos(base.render)) self.cTrav.traverse(render) # checking for camera collisions entries = list(self.cameraCollisionHandler.entries) for entry in entries: if str(entry.getIntoNodePath())[:19] != "render/worldTerrain": #camera.setPos(entry.getSurfacePoint(self.thirdPersonNode)) self.thirdPersonCamera_ZOOM += 1 # if len(entries) > 0: # if (self.playerHolder.getZ() < entries[-1].getSurfacePoint(render).getZ() + 8): # self.playerHolder.setZ(entries[-1].getSurfacePoint(render).getZ() + 8) # self.vertical_velocity = 0 # checking for collisions - downwards entries = list(self.groundHandler.entries) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) self.performGravity = True if self.performGravity == True: self.vertical_velocity -= (deltaTime * 9.81) if self.vertical_velocity <= -15: self.vertical_velocity = -15 self.playerHolder.setPos(self.playerHolder, Vec3(0, 0, self.vertical_velocity)) # Gravity if len(entries) > 0: if (self.playerHolder.getZ() < entries[-1].getSurfacePoint(render).getZ() + 8): self.playerHolder.setZ( entries[-1].getSurfacePoint(render).getZ() + 8) self.vertical_velocity = 0 # checking for collisions - upwards entries = list(self.upwardsHandler.entries) entries.sort(key=lambda x: x.getSurfacePoint(render).getZ()) if len(entries) > 0: for entry in entries: if (self.playerHolder.getZ() > entry.getSurfacePoint(render).getZ() - 70): self.playerHolder.setZ( entry.getSurfacePoint(render).getZ() - 130) # PLAYER MODES, HOW THE USER INTERACTS AND CONTROLS WITH THE USER # MODE 1 # Mode 1 is a test update loop used to test player loop switching. # it simply freezes the controls. def mode1(self): self.playerHolder.hide() self.playerHolder.setHpr(0, 0, 0) if self.keyMap["backwards"]: self.playerHolder.show() self.gameMode = self.mode0
class CogdoFlyingLegalEagle(DirectObject, FSM): CollSphereName = 'CogdoFlyingLegalEagleSphere' CollisionEventName = 'CogdoFlyingLegalEagleCollision' InterestCollName = 'CogdoFlyingLegalEagleInterestCollision' RequestAddTargetEventName = 'CogdoFlyingLegalEagleRequestTargetEvent' RequestAddTargetAgainEventName = 'CogdoFlyingLegalEagleRequestTargetAgainEvent' RequestRemoveTargetEventName = 'CogdoFlyingLegalEagleRemoveTargetEvent' ForceRemoveTargetEventName = 'CogdoFlyingLegalEagleForceRemoveTargetEvent' EnterLegalEagle = 'CogdoFlyingLegalEagleDamageToon' ChargingToAttackEventName = 'LegalEagleChargingToAttack' LockOnToonEventName = 'LegalEagleLockOnToon' CooldownEventName = 'LegalEagleCooldown' notify = DirectNotifyGlobal.directNotify.newCategory( 'CogdoFlyingLegalEagle') def __init__(self, nest, index, suitDnaName='le'): FSM.__init__(self, 'CogdoFlyingLegalEagle') self.defaultTransitions = { 'Off': ['Roost'], 'Roost': ['TakeOff', 'Off'], 'TakeOff': ['LockOnToon', 'LandOnNest', 'Off'], 'LockOnToon': ['RetreatToNest', 'ChargeUpAttack', 'Off'], 'ChargeUpAttack': ['RetreatToNest', 'Attack', 'Off'], 'Attack': ['RetreatToSky', 'Off'], 'RetreatToSky': ['Cooldown', 'Off'], 'Cooldown': ['LockOnToon', 'LandOnNest', 'Off'], 'RetreatToNest': ['LandOnNest', 'Off'], 'LandOnNest': ['Roost', 'Off'] } self.index = index self.nest = nest self.target = None self.isEagleInterested = False self.collSphere = None self.suit = Suit.Suit() d = SuitDNA.SuitDNA() d.newSuit(suitDnaName) self.suit.setDNA(d) self.suit.reparentTo(render) swapAvatarShadowPlacer(self.suit, 'legalEagle-%sShadowPlacer' % index) self.suit.setPos(self.nest.getPos(render)) self.suit.setHpr(-180, 0, 0) self.suit.stash() self.prop = None self.attachPropeller() head = self.suit.find('**/joint_head') self.interestConeOrigin = self.nest.attachNewNode('fakeHeadNodePath') self.interestConeOrigin.setPos( render, head.getPos(render) + Vec3(0, Globals.LegalEagle.InterestConeOffset, 0)) self.attackTargetPos = None self.startOfRetreatToSkyPos = None pathModel = CogdoUtil.loadFlyingModel('legalEaglePaths') self.chargeUpMotionPath = Mopath.Mopath(name='chargeUpMotionPath-%i' % self.index) self.chargeUpMotionPath.loadNodePath(pathModel.find('**/charge_path')) self.retreatToSkyMotionPath = Mopath.Mopath( name='retreatToSkyMotionPath-%i' % self.index) self.retreatToSkyMotionPath.loadNodePath( pathModel.find('**/retreat_path')) audioMgr = base.cogdoGameAudioMgr self._screamSfx = audioMgr.createSfx('legalEagleScream', self.suit) self.initIntervals() self.suit.nametag3d.stash() self.suit.nametag.destroy() return def attachPropeller(self): if self.prop == None: self.prop = BattleProps.globalPropPool.getProp('propeller') head = self.suit.find('**/joint_head') self.prop.reparentTo(head) return def detachPropeller(self): if self.prop: self.prop.cleanup() self.prop.removeNode() self.prop = None return def _getAnimationIval(self, animName, startFrame=0, endFrame=None, duration=1): if endFrame == None: self.suit.getNumFrames(animName) - 1 frames = endFrame - startFrame frameRate = self.suit.getFrameRate(animName) newRate = frames / duration playRate = newRate / frameRate ival = Sequence(ActorInterval(self.suit, animName, playRate=playRate)) return ival def initIntervals(self): dur = Globals.LegalEagle.LiftOffTime nestPos = self.nest.getPos(render) airPos = nestPos + Vec3(0.0, 0.0, Globals.LegalEagle.LiftOffHeight) self.takeOffSeq = Sequence(Parallel( Sequence( Wait(dur * 0.6), LerpPosInterval(self.suit, dur * 0.4, startPos=nestPos, pos=airPos, blendType='easeInOut'))), Wait(1.5), Func(self.request, 'next'), name='%s.takeOffSeq-%i' % (self.__class__.__name__, self.index)) self.landOnNestPosLerp = LerpPosInterval(self.suit, 1.0, startPos=airPos, pos=nestPos, blendType='easeInOut') self.landingSeq = Sequence(Func(self.updateLandOnNestPosLerp), Parallel(self.landOnNestPosLerp), Func(self.request, 'next'), name='%s.landingSeq-%i' % (self.__class__.__name__, self.index)) dur = Globals.LegalEagle.ChargeUpTime self.chargeUpPosLerp = LerpFunc( self.moveAlongChargeUpMopathFunc, fromData=0.0, toData=self.chargeUpMotionPath.getMaxT(), duration=dur, blendType='easeInOut') self.chargeUpAttackSeq = Sequence( Func(self.updateChargeUpPosLerp), self.chargeUpPosLerp, Func(self.request, 'next'), name='%s.chargeUpAttackSeq-%i' % (self.__class__.__name__, self.index)) dur = Globals.LegalEagle.RetreatToNestTime self.retreatToNestPosLerp = LerpPosInterval(self.suit, dur, startPos=Vec3(0, 0, 0), pos=airPos, blendType='easeInOut') self.retreatToNestSeq = Sequence(Func(self.updateRetreatToNestPosLerp), self.retreatToNestPosLerp, Func(self.request, 'next'), name='%s.retreatToNestSeq-%i' % (self.__class__.__name__, self.index)) dur = Globals.LegalEagle.RetreatToSkyTime self.retreatToSkyPosLerp = LerpFunc( self.moveAlongRetreatMopathFunc, fromData=0.0, toData=self.retreatToSkyMotionPath.getMaxT(), duration=dur, blendType='easeOut') self.retreatToSkySeq = Sequence(Func(self.updateRetreatToSkyPosLerp), self.retreatToSkyPosLerp, Func(self.request, 'next'), name='%s.retreatToSkySeq-%i' % (self.__class__.__name__, self.index)) dur = Globals.LegalEagle.PreAttackTime self.preAttackLerpXY = LerpFunc(self.updateAttackXY, fromData=0.0, toData=1.0, duration=dur) self.preAttackLerpZ = LerpFunc(self.updateAttackZ, fromData=0.0, toData=1.0, duration=dur, blendType='easeOut') dur = Globals.LegalEagle.PostAttackTime self.postAttackPosLerp = LerpPosInterval(self.suit, dur, startPos=Vec3(0, 0, 0), pos=Vec3(0, 0, 0)) self.attackSeq = Sequence( Parallel(self.preAttackLerpXY, self.preAttackLerpZ), Func(self.updatePostAttackPosLerp), self.postAttackPosLerp, Func(self.request, 'next'), name='%s.attackSeq-%i' % (self.__class__.__name__, self.index)) dur = Globals.LegalEagle.CooldownTime self.cooldownSeq = Sequence(Wait(dur), Func(self.request, 'next'), name='%s.cooldownSeq-%i' % (self.__class__.__name__, self.index)) self.propTrack = Sequence( ActorInterval(self.prop, 'propeller', startFrame=0, endFrame=14)) self.hoverOverNestSeq = Sequence( ActorInterval(self.suit, 'landing', startFrame=10, endFrame=20, playRate=0.5), ActorInterval(self.suit, 'landing', startFrame=20, endFrame=10, playRate=0.5)) def initCollision(self): self.collSphere = CollisionSphere(0, 0, 0, 0) self.collSphere.setTangible(0) self.collNode = CollisionNode('%s-%s' % (self.CollSphereName, self.index)) self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.suit.attachNewNode(self.collNode) self.collNodePath.hide() self.accept('enter%s-%s' % (self.CollSphereName, self.index), self.handleEnterSphere) self.setCollSphereToNest() def getInterestConeLength(self): return Globals.LegalEagle.InterestConeLength + Globals.LegalEagle.InterestConeOffset def isToonInView(self, toon): distanceThreshold = self.getInterestConeLength() angleThreshold = Globals.LegalEagle.InterestConeAngle toonPos = toon.getPos(render) nestPos = self.nest.getPos(render) distance = toon.getDistance(self.interestConeOrigin) if distance > distanceThreshold: return False if toonPos[1] > nestPos[1]: return False a = toon.getPos(render) - self.interestConeOrigin.getPos(render) a.normalize() b = Vec3(0, -1, 0) dotProduct = a.dot(b) angle = math.degrees(math.acos(dotProduct)) if angle <= angleThreshold / 2.0: return True return False def update(self, dt, localPlayer): if Globals.Dev.NoLegalEagleAttacks: return inView = self.isToonInView(localPlayer.toon) if inView and not self.isEagleInterested: self.handleEnterInterest() else: if inView and self.isEagleInterested: self.handleAgainInterest() else: if not inView and self.isEagleInterested: self.handleExitInterest() def updateLockOnTask(self): dt = globalClock.getDt() targetPos = self.target.getPos(render) suitPos = self.suit.getPos(render) nestPos = self.nest.getPos(render) attackPos = Vec3(targetPos) attackPos[1] = nestPos[1] + Globals.LegalEagle.LockOnDistanceFromNest attackPos[2] += Globals.LegalEagle.VerticalOffset if attackPos[2] < nestPos[2]: attackPos[2] = nestPos[2] attackChangeVec = (attackPos - suitPos) * Globals.LegalEagle.LockOnSpeed self.suit.setPos(suitPos + attackChangeVec * dt) return Task.cont def updateAttackXY(self, value): if Globals.LegalEagle.EagleAttackShouldXCorrect: x = self.readyToAttackPos.getX() + (self.attackTargetPos.getX( ) - self.readyToAttackPos.getX()) * value self.suit.setX(x) y = self.readyToAttackPos.getY() + ( self.attackTargetPos.getY() - self.readyToAttackPos.getY()) * value self.suit.setY(y) def updateAttackZ(self, value): z = self.readyToAttackPos.getZ() + ( self.attackTargetPos.getZ() - self.readyToAttackPos.getZ()) * value self.suit.setZ(z) def moveAlongChargeUpMopathFunc(self, value): self.chargeUpMotionPath.goTo(self.suit, value) self.suit.setPos(self.suit.getPos() + self.startOfChargeUpPos) def moveAlongRetreatMopathFunc(self, value): self.retreatToSkyMotionPath.goTo(self.suit, value) self.suit.setPos(self.suit.getPos() + self.startOfRetreatToSkyPos) def updateChargeUpPosLerp(self): self.startOfChargeUpPos = self.suit.getPos(render) def updateLandOnNestPosLerp(self): self.landOnNestPosLerp.setStartPos(self.suit.getPos()) def updateRetreatToNestPosLerp(self): self.retreatToNestPosLerp.setStartPos(self.suit.getPos()) def updateRetreatToSkyPosLerp(self): self.startOfRetreatToSkyPos = self.suit.getPos(render) def updatePostAttackPosLerp(self): suitPos = self.suit.getPos(render) finalPos = suitPos + Vec3(0, -Globals.LegalEagle.PostAttackLength, 0) self.postAttackPosLerp.setStartPos(suitPos) self.postAttackPosLerp.setEndPos(finalPos) def handleEnterSphere(self, collEntry): self.notify.debug('handleEnterSphere:%i' % self.index) messenger.send(CogdoFlyingLegalEagle.EnterLegalEagle, [self, collEntry]) def handleEnterInterest(self): self.notify.debug('handleEnterInterestColl:%i' % self.index) self.isEagleInterested = True messenger.send(CogdoFlyingLegalEagle.RequestAddTargetEventName, [self.index]) def handleAgainInterest(self): self.isEagleInterested = True messenger.send(CogdoFlyingLegalEagle.RequestAddTargetAgainEventName, [self.index]) def handleExitInterest(self): self.notify.debug('handleExitInterestSphere:%i' % self.index) self.isEagleInterested = False messenger.send(CogdoFlyingLegalEagle.RequestRemoveTargetEventName, [self.index]) def hasTarget(self): if self.target != None: return True return False return def setTarget(self, toon, elapsedTime=0.0): self.notify.debug('Setting eagle %i to target: %s, elapsed time: %s' % (self.index, toon.getName(), elapsedTime)) self.target = toon if self.state == 'Roost': self.request('next', elapsedTime) if self.state == 'ChargeUpAttack': messenger.send(CogdoFlyingLegalEagle.ChargingToAttackEventName, [self.target.doId]) def clearTarget(self, elapsedTime=0.0): self.notify.debug('Clearing target from eagle %i, elapsed time: %s' % (self.index, elapsedTime)) messenger.send(CogdoFlyingLegalEagle.CooldownEventName, [self.target.doId]) self.target = None if self.state in ('LockOnToon', ): self.request('next', elapsedTime) return def leaveCooldown(self, elapsedTime=0.0): if self.state in ('Cooldown', ): self.request('next', elapsedTime) def shouldBeInFrame(self): if self.state in ('TakeOff', 'LockOnToon', 'ChargeUpAttack'): return True if self.state == 'Attack': distance = self.suit.getDistance(self.target) threshold = Globals.LegalEagle.EagleAndTargetDistCameraTrackThreshold suitPos = self.suit.getPos(render) targetPos = self.target.getPos(render) if distance > threshold and suitPos[1] > targetPos[1]: return True return False def getTarget(self): return self.target def onstage(self): self.suit.unstash() self.request('Roost') def offstage(self): self.suit.stash() self.request('Off') def gameStart(self, gameStartTime): self.gameStartTime = gameStartTime self.initCollision() def gameEnd(self): self.shutdownCollisions() def shutdownCollisions(self): self.ignoreAll() if self.collSphere != None: del self.collSphere self.collSphere = None if self.collNodePath != None: self.collNodePath.removeNode() del self.collNodePath self.collNodePath = None if self.collNode != None: del self.collNode self.collNode = None return def destroy(self): self.request('Off') self.detachPropeller() del self._screamSfx self.suit.cleanup() self.suit.removeNode() self.suit.delete() self.interestConeOrigin.removeNode() del self.interestConeOrigin self.nest = None self.target = None taskMgr.remove('updateLockOnTask-%i' % self.index) taskMgr.remove('exitLockOnToon-%i' % self.index) self.propTrack.clearToInitial() del self.propTrack del self.chargeUpMotionPath del self.retreatToSkyMotionPath self.takeOffSeq.clearToInitial() del self.takeOffSeq del self.landOnNestPosLerp self.landingSeq.clearToInitial() del self.landingSeq del self.chargeUpPosLerp self.chargeUpAttackSeq.clearToInitial() del self.chargeUpAttackSeq del self.retreatToNestPosLerp self.retreatToNestSeq.clearToInitial() del self.retreatToNestSeq del self.retreatToSkyPosLerp self.retreatToSkySeq.clearToInitial() del self.retreatToSkySeq del self.postAttackPosLerp self.attackSeq.clearToInitial() del self.attackSeq self.cooldownSeq.clearToInitial() del self.cooldownSeq self.hoverOverNestSeq.clearToInitial() del self.hoverOverNestSeq del self.preAttackLerpXY del self.preAttackLerpZ return def requestNext(self): self.request('next') def setCollSphereToNest(self): if hasattr(self, 'collSphere') and self.collSphere is not None: radius = Globals.LegalEagle.OnNestDamageSphereRadius self.collSphere.setCenter( Point3(0.0, -Globals.Level.LaffPowerupNestOffset[1], self.suit.getHeight() / 2.0)) self.collSphere.setRadius(radius) return def setCollSphereToTargeting(self): if hasattr(self, 'collSphere') and self.collSphere is not None: radius = Globals.LegalEagle.DamageSphereRadius self.collSphere.setCenter(Point3(0, 0, radius * 2)) self.collSphere.setRadius(radius) return def enterRoost(self): self.notify.info("enter%s: '%s' -> '%s'" % (self.newState, self.oldState, self.newState)) self.hoverOverNestSeq.loop() self.propTrack.loop() self.setCollSphereToNest() def filterRoost(self, request, args): self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args)) if request == self.state: return if request == 'next': return 'TakeOff' return self.defaultFilter(request, args) return def exitRoost(self): self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState)) self.hoverOverNestSeq.pause() self.setCollSphereToTargeting() def enterTakeOff(self, elapsedTime=0.0): self.notify.info( "enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime)) self.takeOffSeq.start(elapsedTime) self.hoverOverNestSeq.loop() def filterTakeOff(self, request, args): self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args)) if request == self.state: return if request == 'next': if self.hasTarget(): return 'LockOnToon' return 'LandOnNest' else: return self.defaultFilter(request, args) return def exitTakeOff(self): self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState)) self.takeOffSeq.clearToInitial() self.hoverOverNestSeq.pause() def enterLockOnToon(self, elapsedTime=0.0): self.notify.info( "enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime)) taskName = 'updateLockOnTask-%i' % self.index taskMgr.add(self.updateLockOnTask, taskName, 45, extraArgs=[]) messenger.send(CogdoFlyingLegalEagle.LockOnToonEventName, [self.target.doId]) range = self.target.getDistance( self.interestConeOrigin) / self.getInterestConeLength() range = clamp(range, 0.0, 1.0) dur = Globals.LegalEagle.LockOnTime if self.oldState == 'TakeOff': dur *= range else: dur += Globals.LegalEagle.ExtraPostCooldownTime taskName = 'exitLockOnToon-%i' % self.index taskMgr.doMethodLater(dur, self.requestNext, taskName, extraArgs=[]) def filterLockOnToon(self, request, args): self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args)) if request == self.state: return if request == 'next': if self.hasTarget(): return 'ChargeUpAttack' return 'RetreatToNest' else: return self.defaultFilter(request, args) return def exitLockOnToon(self): self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState)) taskMgr.remove('updateLockOnTask-%i' % self.index) taskMgr.remove('exitLockOnToon-%i' % self.index) def enterChargeUpAttack(self, elapsedTime=0.0): self.notify.info( "enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime)) self.chargeUpAttackSeq.start(elapsedTime) messenger.send(CogdoFlyingLegalEagle.ChargingToAttackEventName, [self.target.doId]) def filterChargeUpAttack(self, request, args): self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args)) if request == self.state: return if request == 'next': if self.hasTarget(): return 'Attack' return 'RetreatToNest' else: return self.defaultFilter(request, args) return def exitChargeUpAttack(self): self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState)) self.chargeUpAttackSeq.clearToInitial() def enterAttack(self, elapsedTime=0.0): self.notify.info( "enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime)) self.attackTargetPos = self.target.getPos(render) targetState = self.target.animFSM.getCurrentState().getName() self._screamSfx.play() if targetState == 'jumpAirborne': self.attackTargetPos[2] += Globals.LegalEagle.VerticalOffset else: self.attackTargetPos[ 2] += Globals.LegalEagle.PlatformVerticalOffset self.readyToAttackPos = self.suit.getPos(render) self.attackSeq.start(elapsedTime) def filterAttack(self, request, args): self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args)) if request == self.state: return if request == 'next': return 'RetreatToSky' return self.defaultFilter(request, args) return def exitAttack(self): self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState)) self.attackSeq.clearToInitial() taskMgr.remove('updateAttackPosTask-%i' % self.index) def enterRetreatToSky(self, elapsedTime=0.0): self.notify.info( "enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime)) self.retreatToSkySeq.start(elapsedTime) def filterRetreatToSky(self, request, args): self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args)) if request == self.state: return if request == 'next': return 'Cooldown' return self.defaultFilter(request, args) return def exitRetreatToSky(self): self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState)) self.retreatToSkySeq.clearToInitial() def enterCooldown(self): if self.target != None: messenger.send(CogdoFlyingLegalEagle.CooldownEventName, [self.target.doId]) self.suit.stash() self.notify.info("enter%s: '%s' -> '%s'" % (self.newState, self.oldState, self.newState)) return def filterCooldown(self, request, args): self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args)) if request == self.state: return if request == 'next': if self.hasTarget(): return 'LockOnToon' return 'LandOnNest' else: return self.defaultFilter(request, args) return def exitCooldown(self): self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState)) self.suit.unstash() self.cooldownSeq.clearToInitial() if self.newState != 'Off': heightOffNest = Globals.LegalEagle.PostCooldownHeightOffNest nestPos = self.nest.getPos(render) if self.newState in ('LandOnNest', ): self.suit.setPos(nestPos + Vec3(0, 0, heightOffNest)) else: targetPos = self.target.getPos(render) attackPos = Vec3(targetPos) attackPos[1] = nestPos[1] attackPos[2] = nestPos[2] + heightOffNest self.suit.setPos(attackPos) def enterRetreatToNest(self, elapsedTime=0.0): self.notify.info( "enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime)) self.retreatToNestSeq.start(elapsedTime) def filterRetreatToNest(self, request, args): self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args)) if request == self.state: return if request == 'next': return 'LandOnNest' return self.defaultFilter(request, args) return def exitRetreatToNest(self): self.retreatToNestSeq.clearToInitial() def enterLandOnNest(self, elapsedTime=0.0): self.notify.info( "enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime)) self.landingSeq.start(elapsedTime) def filterLandOnNest(self, request, args): self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args)) if request == self.state: return if request == 'next': if self.hasTarget(): return 'TakeOff' return 'Roost' else: return self.defaultFilter(request, args) return def exitLandOnNest(self): self.landingSeq.clearToInitial()
class World(DirectObject): global bk_text bk_text = ' ' def __init__(self): global speed global maxspeed self.keyMap = { "left": 0, "right": 0, "forward": 0, "accelerate": 0, "decelerate": 0, "cam-left": 0, "cam-right": 0 } base.win.setClearColor(Vec4(0, 0, 0, 1)) # Post the instructions self.title = addTitle( "HW2: Roaming Ralph Modified (Walking on the Moon) with friends") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[A]: Rotate Ralph Left") self.inst3 = addInstructions(0.85, "[D]: Rotate Ralph Right") self.inst4 = addInstructions(0.80, "[W]: Move Ralph Forward") self.inst5 = addInstructions(0.75, "[P]: Increase Ralph Velocity (Run)") self.inst6 = addInstructions(0.70, "[O]: Decrease Ralph Velocity (Walk)") self.inst7 = addInstructions(0.60, "[Left Arrow]: Rotate Camera Left") self.inst8 = addInstructions(0.55, "[Right Arrow]: Rotate Camera Right") # Set up the environment self.environ = loader.loadModel("models/square") self.environ.reparentTo(render) self.environ.setPos(0, 0, 0) self.environ.setScale(100, 100, 1) self.moon_tex = loader.loadTexture("models/moon_1k_tex.jpg") self.environ.setTexture(self.moon_tex, 1) # Create the main character, Ralph if (v == [0]): print(model) self.ralph = Actor("models/ralph", { "run": "models/ralph-run", "walk": "models/ralph-walk" }) self.ralph.setScale(.2) elif (v == [1]): print(model) self.ralph = Actor("models/panda-model", {"walk": "models/panda-walk4"}) speed = 100 maxspeed = 10000 self.ralph.setScale(0.0001, 0.00015, 0.0005) self.ralph.setScale(.002) self.ralph.setPlayRate(100.0, "models/panda-walk4") speed = 100 maxspeed = 10000 self.ralph.setScale(.0035) else: print(model) self.ralph = Actor("models/GroundRoamer.egg") self.ralph.setScale(.15) self.ralph.setHpr(180, 0, 0) self.Groundroamer_texture = loader.loadTexture( "models/Groundroamer.tif") self.ralph.setTexture(self.Groundroamer_texture) self.ralph.reparentTo(render) self.ralph.setPos(0, 0, 0) #creates Earth self.earth = Actor("models/planet_sphere.egg.pz") self.earth.reparentTo(render) self.earth.setScale(6.0) self.earth.setPos(40, 25, 6) self.earth_texture = loader.loadTexture("models/earth_1k_tex.jpg") self.earth.setTexture(self.earth_texture) #creates Mercury self.mercury = Actor("models/planet_sphere.egg.pz") self.mercury.reparentTo(render) self.mercury.setScale(2.0) self.mercury.setPos(-40, -25, 2) self.mercury_texture = loader.loadTexture("models/mercury_1k_tex.jpg") self.mercury.setTexture(self.mercury_texture) #creates Venus self.venus = Actor("models/planet_sphere.egg.pz") self.venus.reparentTo(render) self.venus.setScale(4.0) self.venus.setPos(40, -30, 4) self.venus_texture = loader.loadTexture("models/venus_1k_tex.jpg") self.venus.setTexture(self.venus_texture) # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("a", self.setKey, ["left", 1]) self.accept("d", self.setKey, ["right", 1]) self.accept("w", self.setKey, ["forward", 1]) self.accept("s", self.setKey, ["backward", 1]) self.accept("arrow_left", self.setKey, ["cam-left", 1]) self.accept("arrow_right", self.setKey, ["cam-right", 1]) self.accept("a-up", self.setKey, ["left", 0]) self.accept("d-up", self.setKey, ["right", 0]) self.accept("w-up", self.setKey, ["forward", 0]) self.accept("arrow_left-up", self.setKey, ["cam-left", 0]) self.accept("arrow_right-up", self.setKey, ["cam-right", 0]) self.accept("p", self.setKey, ["accelerate", 1]) self.accept("o", self.setKey, ["decelerate", 1]) self.accept("p-up", self.setKey, ["accelerate", 0]) self.accept("o-up", self.setKey, ["decelerate", 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) 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) # 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() # pring the inital position #print startpos global speed global maxspeed # 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): if (v == [2]): self.ralph.setY(self.ralph, speed * globalClock.getDt()) else: self.ralph.setY(self.ralph, -speed * globalClock.getDt()) if (self.keyMap["accelerate"] != 0): speed += 100 if (speed > maxspeed): speed = maxspeed elif (self.keyMap["decelerate"] != 0): speed -= 1 if (speed < 10.0): speed = 10.0 # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0) or (self.keyMap["right"] != 0): if self.isMoving is False: self.ralph.loop("walk") self.ralph.loop("run") self.isMoving = True else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False speed = 10.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() - 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 # 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