class World(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.debug = False
        self.statusLabel = self.makeStatusLabel(0)
        self.collisionLabel = self.makeStatusLabel(1)
        if os.path.isfile("assets/1stmap.bam"):
            self.world = self.loader.loadModel("assets/1stmap.bam")
            self.world.reparentTo(self.render)
        else:
            print "generating terrain and saving bam for future use"
            terrain = GeoMipTerrain("worldTerrain")
            terrain.setHeightfield("./assets/1stmap_HF.png")
            terrain.setColorMap("./assets/1stmap_TM.png")
            terrain.setBruteforce(True)
            root = terrain.getRoot()
            root.reparentTo(self.render)
            root.setSz(60)
            terrain.generate()
            root.writeBamFile("./assets/1stmap.bam")

        self.worldsize = 1024

        # Player
        self.maxspeed = 100.0
        self.startPos = Vec3(200, 200, 35)
        self.startHpr = Vec3(225, 0, 0)
        self.player = self.loader.loadModel("assets/alliedflanker.egg")
        self.player.setScale(0.2, 0.2, 0.2)
        self.player.reparentTo(self.render)
        self.resetPlayer()

        # Player destruction
        self.explosionModel = loader.loadModel("assets/explosion")
        self.explosionModel.reparentTo(self.render)
        self.explosionModel.setScale(0.0)
        self.explosionModel.setLightOff()
        # Only one explosion at a time
        self.exploding = False

        self.taskMgr.add(self.updateTask, "update")
        self.keyboardSetup()

        self.maxdistance = 600
        self.camLens.setFar(self.maxdistance)
        self.camLens.setFov(60)

        self.createEnvironment()
        self.setupCollisions()
        self.textCounter = 0

    def makeStatusLabel(self, i):
        return OnscreenText(
            style=2, fg=(0.5, 1, 0.5, 1), pos=(-1.3, 0.92 - (0.08 * i)), align=TextNode.ALeft, scale=0.08, mayChange=1
        )

    def createEnvironment(self):
        # Fog
        expfog = Fog("scene-wide-fog")
        expfog.setColor(0.5, 0.5, 0.5)
        expfog.setExpDensity(0.002)
        self.render.setFog(expfog)

        # Sky
        skysphere = self.loader.loadModel("assets/blue-sky-sphere")
        skysphere.setEffect(CompassEffect.make(self.render))
        skysphere.setScale(0.08)
        skysphere.reparentTo(self.camera)

        # Lights
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(0.6, 0.6, 0.6, 1))
        self.render.setLight(self.render.attachNewNode(ambientLight))

        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setColor(VBase4(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)

        # Water
        self.water = self.loader.loadModel("assets/square.egg")
        self.water.setSx(self.worldsize * 2)
        self.water.setSy(self.worldsize * 2)
        self.water.setPos(self.worldsize / 2, self.worldsize / 2, 25)
        self.water.setTransparency(TransparencyAttrib.MAlpha)
        newTS = TextureStage("1")
        self.water.setTexture(newTS, self.loader.loadTexture("assets/water.png"))
        self.water.setTexScale(newTS, 4)
        self.water.reparentTo(self.render)
        LerpTexOffsetInterval(self.water, 200, (1, 0), (0, 0), textureStage=newTS).loop()

    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 setKey(self, key, value):
        self.keyMap[key] = value

    def updateTask(self, task):
        self.updatePlayer()
        self.updateCamera()

        self.collTrav.traverse(self.render)
        for i in range(self.playerGroundHandler.getNumEntries()):
            entry = self.playerGroundHandler.getEntry(i)
            if self.debug == True:
                self.collisionLabel.setText("DEAD:" + str(globalClock.getFrameTime()))
            if self.exploding == False:
                self.player.setZ(entry.getSurfacePoint(self.render).getZ() + 10)
                self.explosionSequence()
        return Task.cont

    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 updatePlayer(self):
        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:
            self.player.setZ(self.player.getZ() + climbfactor)
            self.player.setR(self.player.getR() + climbfactor)
            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)
            if (self.player.getR()) <= -180:
                self.player.setR(180)
        elif self.player.getR() > 0:
            self.player.setR(self.player.getR() - (climbfactor + 0.1))
            if self.player.getR() < 0:
                self.player.setR(0)
        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
        if self.exploding == False:
            self.player.setX(self.player, -speedfactor)
            self.applyBoundaries()

        if self.exploding == False:
            self.player.setX(self.player, -speedfactor)
            self.applyBoundaries()
            self.player.setZ(self.player, -gravityfactor)

    def applyBoundaries(self):
        # respect max camera distance else you
        # cannot see the floor post loop the loop!
        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)

        # 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

        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 += 1

    def updateCamera(self):
        percent = self.speed / self.maxspeed
        self.camera.setPos(self.player, 19.6225 + (10 * percent), 3.8807, 10.2779)
        self.camera.setHpr(self.player, 94.8996, -12.6549, 1.55508)

    def setupCollisions(self):
        self.collTrav = CollisionTraverser()

        self.playerGroundSphere = CollisionSphere(0, 1.5, -1.5, 1.5)
        self.playerGroundCol = CollisionNode("playersphere")
        self.playerGroundCol.addSolid(self.playerGroundSphere)

        # bitmasks
        self.playerGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.playerGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.world.setCollideMask(BitMask32.bit(0))

        self.playerGroundColNp = self.player.attachNewNode(self.playerGroundCol)
        self.playerGroundHandler = CollisionHandlerQueue()
        self.collTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler)

        self.water.setCollideMask(BitMask32.bit(0))

        # Debug
        if self.debug == True:
            self.playerGroundColNp.show()
            self.collTrav.showCollisions(self.render)

    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):
        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()
Beispiel #2
0
class Input1(DirectObject):
    def __init__(self,model):
        # 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)
       

    
    #Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value
    

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        # Get the time elapsed since last frame. We need this
        # for framerate-independent movement.
        elapsed = globalClock.getDt()       #Has a Change in time from 0.04 to 0.09 constantly changes
        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        base.camera.lookAt(self.model.getX(),self.model.getY(),0)
        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.model.getPos()

        # If a move-key is pressed, move ralph in the specified direction.
                
        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.model.getPos() - base.camera.getPos()
        camvec.setZ(5)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 30.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-30))
            camdist = 30.0
        if (camdist < 15.0):
            base.camera.setPos(base.camera.getPos() - camvec*(15-camdist))
            camdist = 15.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.
        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.
        self.floater.setPos(self.model.getPos())
        base.camera.lookAt(self.floater)        
        # 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)

        
        
        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)
            
        
        return Task.cont
Beispiel #3
0
class Swifter:
    def __init__(self, model, run, walk, idle, jump, crouch, crouchWalk, startPos, scale):
         #(self, model, run, walk, startPos, scale):
        """Initialise the character.
        
        Arguments:
        model -- The path to the character's model file (string)
           run : The path to the model's run animation (string)
           walk : The path to the model's walk animation (string)
           startPos : Where in the world the character will begin (pos)
           scale : The amount by which the size of the model will be scaled 
                   (float)
                   
        """
        
        #Define movement map and speeds
        self.speedSprint = 20
        self.speedWalk = 7
        self.speedCrouch = 5
        self.speed = self.speedWalk
        #Capture control status
        self.isMoving = False
        self.isJumping = False
        self.isIdle = False
        self.isCrouching = False
        
        self.movementMap = {"forward":Vec3(0,-self.speed,0), "back":Vec3(0,self.speed,0), \
                            "left":Vec3(self.speed,0,0), "right":Vec3(-self.speed,0,0), \
                            "crouch":0, "sprint":0, "jump":1, "punch":0, "kick":0, "stop":Vec3(0), "changeView":0}
        
        #Set up key state variables
        self.strafe_left = self.movementMap["stop"]
        self.strafe_right = self.movementMap["stop"]
        self.forward = self.movementMap["stop"]
        self.back = self.movementMap["stop"]
        self.jump = False
        self.sprint = False
        self.crouch = False
        
        #Stop player by default
        self.walk = self.movementMap["stop"]
        self.strafe = self.movementMap["stop"]
           
        #Define the actor and his animations
        self.actor = Actor(model,
                           {"run":run,
                            "walk":walk,
                            "idle":idle,
                            "jump":jump,
                            "crouch":crouch,
                            "crouchWalk":crouchWalk})
        
        
        #self.actor.enableBlend()
       
        self.actor.setBlend(frameBlend = True)#Enable interpolation
        self.actor.reparentTo(render)
        self.actor.setScale(scale)
        self.actor.setPos(startPos)
        
        #Set up FSM controller
        self.FSM = ActorFSM(self.actor)
        
        
        
        taskMgr.add(self.move,"moveTask") # Note: deriving classes DO NOT need
                                          # to add their own move tasks to the
                                          # task manager. If they override
                                          # self.move, then their own self.move
                                          # function will get called by the
                                          # task manager (they must then
                                          # explicitly call Character.move in
                                          # that function if they want it).
    
        self.prevtime = 0
        
        

        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above ralph's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.

        self.cTrav = CollisionTraverser()

        self.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(1))
        self.groundCol.setIntoCollideMask(BitMask32.allOff())
        self.groundColNp = self.actor.attachNewNode(self.groundCol)
        self.groundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.groundColNp, self.groundHandler)

        # Uncomment this line to see the collision rays
        self.groundColNp.show()

        #Uncomment this line to show a visual representation of the 
        #collisions occuring
        self.cTrav.showCollisions(render)
    """    
    def jumpUpdate(self,task):
        # this task simulates gravity and makes the player jump 
        # get the highest Z from the down casting ray
        
        highestZ = -100
        for i in range(self.nodeGroundHandler.getNumEntries()):
            entry = self.nodeGroundHandler.getEntry(i)
            z = entry.getSurfacePoint(self.render).getZ()
            if z > highestZ and entry.getIntoNode().getName() == "Cube":
                highestZ = z
        # gravity effects and jumps
        self.node.setZ(self.node.getZ()+self.jump*globalClock.getDt())
        self.jump -= 1*self.globalClock.getDt()
        if highestZ > self.node.getZ()-.3:
            self.jump = 0
            self.node.setZ(highestZ+.3)
            if self.readyToJump:
                self.jump = 1
        return task.cont    
    """
    def move(self, task):
        """Move and animate the character for one frame.
        
        This is a task function that is called every frame by Panda3D.
        The character is moved according to which of it's movement controls
        are set, and the function keeps the character's feet on the ground
        and stops the character from moving if a collision is detected.
        This function also handles playing the characters movement
        animations.

        Arguments:
        task -- A direct.task.Task object passed to this function by Panda3D.
        
        Return:
        Task.cont -- To tell Panda3D to call this task function again next
                     frame.
        """

         
        elapsed = task.time - self.prevtime

        # save the character's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.actor.getPos()
 

        #Calculate stateful movement
        
        self.walk = self.forward + self.back
        self.strafe = self.strafe_left + self.strafe_right

        
        # move the character if any of the move controls are activated.
        self.actor.setPos(self.actor,self.walk*globalClock.getDt()*self.speed)
        self.actor.setPos(self.actor,self.strafe*globalClock.getDt()*self.speed)
        
        #If strafing rotate the model -90 / 90 degrees to go in the direction specified
        #if going backwards rotate model 180 degrees

        # If the character is moving, loop the run animation.
        # If he is standing still, stop the animation.
        
        ##CALLL CONTROLLER CLASS AND CALL FSM's INSTEAD OF DOING IT HERE
        
        #Decide what type of movement anim to use
        
        if(self.sprint is True):
            #If we are sprinting..
            self.walkAnim = 'Run'
            self.speed = self.speedSprint
        elif(self.crouch is True): # Can't sprint while crouching ;)
            #If we are crouching..
            print ("Crouching!")
            self.walkAnim = "CrouchWalk"
            self.idleAnim = "Crouch"
            self.speed = self.speedCrouch
        else:
            #Otherwise were walking..
            self.walkAnim = 'Walk'
            self.idleAnim = 'Idle'
            self.speed = self.speedWalk
            
            
        #Idling
        if(self.isJumping is False and self.isMoving is False and self.isIdle is True and self.FSM.state != self.idleAnim):
            #If were not moving and not jumping and were supposed to be idle, play the idle anim if we aren't already
            self.FSM.request(self.idleAnim,1)
            
            #We are idle, feel free to do something else, setting isIdle = False.
            print ("We are Idle but ready to do something: isIdle = False")
            
        elif(self.isJumping is False and self.isMoving is False and self.isIdle is False):
            #If were not moving or jumping, were not  doing anything, we should probably be idle if we aren't already          
            self.isIdle = True

        
        #locomotion           
        #TODO: Separate out into animations for forward, back and side stepping
        if( (self.walk != self.movementMap["stop"] or self.strafe != self.movementMap["stop"]) and self.isJumping is False):
            #Check if actor is walking forward/back
            if(self.walk != self.movementMap["stop"]):
                if(self.isMoving is False or self.FSM.state != self.walkAnim):
                    self.isMoving = True # were now moving
                    self.isIdle = False # were not idle right now 
                    self.FSM.request(self.walkAnim,1)
                    print ("Started running or walking")
            #Check if actor is strafing
            if(self.strafe != self.movementMap["stop"]):
                if(self.isMoving is False or self.FSM.state != self.walkAnim):
                    #MAKE THE NODE ROTATE SO THE LEGS POINT THE DIRECTION MOVING
                    #myLegRotate = actor.controlJoint(None,"modelRoot",)
                    #http://www.panda3d.org/manual/index.php/Controlling_a_Joint_Procedurally
                    self.isMoving = True # were now moving
                    self.isIdle = False # were not idle right now 
                    self.FSM.request(self.walkAnim,1)
                    print ("Started running or walking")    
        elif(self.isMoving is True and self.isIdle is False):
            #Only switch of isMoving if we were moving and not idle
            self.isMoving = False
            print ("Finished walking")
            
                  
            #if were moving, set isMoving = 1 and call walking FSM
        
            
        '''
        Jumping
        
        Check if the user is jumping, if they currently aren't jumping:
        make them not idle and mark them as jumping and request the Jump FSM.
        
        If the jump anim isn't playing but we were jumping, mark actor as not jumping.
        
        '''     
        if(self.jump is True):
            #if user pressed jump and were not already jumping, jump
            if(self.isJumping is False and self.FSM.state != 'Jump'):
                self.isJumping = True # were jumping 
                self.isIdle = False # were not idle right now
                self.FSM.request('Jump',1)
                print ("Started jumping")
        
        #if we are jumping, check the anim has finished and stop jumping
        self.JumpQuery = self.actor.getAnimControl('jump')
        if(self.isJumping is True and self.JumpQuery.isPlaying() is False):
            self.isJumping = False # finished jumping
            print ("Finished Jumping")
        
                

        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust the character's Z coordinate.  If the character'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.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)

        # Store the task time and continue.
        self.prevtime = task.time
        return Task.cont    
            
    def setMove(self, key, moveType):
        """ Used by keyboard setup 
            This gets the input from keyBoardSetup and will capture inputs
        """
        if (moveType == "strafe_left"):
            self.strafe_left = self.movementMap[key]
        if (moveType == "strafe_right"):
            self.strafe_right = self.movementMap[key]
        if (moveType == "forward"):
            self.forward = self.movementMap[key]
        if (moveType == "back"):
            self.back = self.movementMap[key]
        if (moveType == "sprint"):
            self.sprint = key
        if (moveType == "jump"):
            self.jump = key
        if (moveType == "crouch"):
            self.crouch = key
Beispiel #4
0
class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.debug = True
        self.statusLabel = self.makeStatusLabel(0)
        self.collisionLabel = self.makeStatusLabel(1)

        self.world = self.loader.loadModel("world.bam")
        self.world.reparentTo(self.render)

        self.maxspeed = 100.0
        # Avion à la pointe des chateaux, direction Ouest !
        self.startPos = Vec3(1200, 320, 85)
        #print (self.startPos)
        self.startHpr = Vec3(0, 0, 0)
        #self.player.setPos(1200,320,85)
        #self.player.setH(0)
        self.player = self.loader.loadModel("alliedflanker.egg")
        #self.player.setPos(640,640,85)
        self.player.setScale(0.2, 0.2, 0.2)
        self.player.reparentTo(self.render)
        self.resetPlayer()

        # load the explosion ring
        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

        # performance (to be masked later by fog) and view:
        self.maxdistance = 1200
        self.camLens.setFar(self.maxdistance)
        self.camLens.setFov(60)

        self.taskMgr.add(self.updateTask, "update")
        self.keyboardSetup()

        # relevant for world boundaries
        self.worldsize = 1024

        self.createEnvironment()

        self.setupCollisions()
        self.textCounter = 0

    def resetPlayer(self):
        self.player.show()
        #self.player.setPos(self.world,self.startPos)
        #self.player.setHpr(self.world,self.startHpr)
        self.player.setPos(self.startPos)
        self.player.setHpr(self.startHpr)
        self.speed = 10.0
        #self.speed = self.maxspeed/2

        #print (self.player.getPos())

    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)

    def updateTask(self, task):
        self.updatePlayer()
        self.updateCamera()

        self.collTrav.traverse(self.render)
        for i in range(self.playerGroundHandler.getNumEntries()):
            entry = self.playerGroundHandler.getEntry(i)
            if (self.debug == True):
                self.collisionLabel.setText("DEAD:" +
                                            str(globalClock.getFrameTime()))
            if (self.exploding == False):
                self.player.setZ(
                    entry.getSurfacePoint(self.render).getZ() + 10)
                self.explosionSequence()
            # we will later deal with 'what to do' when the player dies

        return task.cont

    def keyboardSetup(self):
        self.keyMap = {"left":0, "right":0, "climb":0, "fall":0, \
            "accelerate":0, "decelerate":0, "fire":0}

        self.accept("escape", sys.exit)

        ## Gestion Vitesse
        self.accept("a", self.setKey, ["accelerate", 1])
        self.accept("a-up", self.setKey, ["accelerate", 0])

        self.accept("q", self.setKey, ["decelerate", 1])
        self.accept("q-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_left", self.setKey, ["left", 1])
        self.accept("arrow_left-up", self.setKey, ["left", 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 setKey(self, key, value):
        self.keyMap[key] = value

    def updateCamera(self):
        # see issue content for how we calculated these:
        self.camera.setPos(self.player, 25.6225, 3.8807, 10.2779)
        #self.camera.setPos(0, 0, 90)
        self.camera.setHpr(self.player, 94.8996, -16.6549, 1.55508)

    def updatePlayer(self):
        # 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
        climbfactor = scalefactor * 0.5 * 2
        bankfactor = scalefactor * 2.0
        speedfactor = scalefactor * 2.9

        # 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

        # 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)
            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)

        elif (self.player.getP() > 0):  # autoreturn from right
            self.player.setP(self.player.getP() - (bankfactor + 0.1))
            if (self.player.getP() < 0): self.player.setP(0)

        elif (self.player.getP() < 0):  # autoreturn from left
            self.player.setP(self.player.getP() + (bankfactor + 0.1))
            if (self.player.getP() > 0):
                self.player.setP(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)
            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)
            if (self.player.getR() <= -180):
                self.player.setR(180)

        elif (self.player.getR() > 0):  # autoreturn from up
            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):  # autoreturn from down
            self.player.setR(self.player.getR() + (climbfactor + 0.1))
            if (self.player.getR() > 0):
                self.player.setR(0)

        # move forwards - our X/Y is inverted, see the issue
        if self.exploding == False:
            self.player.setX(self.player, -speedfactor)
            self.applyBoundaries()

    def createEnvironment(self):
        # Fog to hide a performance tweak:
        colour = (0.0, 0.0, 0.0)
        expfog = Fog("scene-wide-fog")
        expfog.setColor(*colour)
        expfog.setExpDensity(0.001)  # original : 0.004
        render.setFog(expfog)
        base.setBackgroundColor(*colour)

        # Our sky
        skydome = loader.loadModel('sky.egg')
        skydome.setEffect(CompassEffect.make(self.render))
        skydome.setScale(self.maxdistance / 2)  # bit less than "far"
        skydome.setZ(-65)  # sink it
        # NOT render - you'll fly through the sky!:
        skydome.reparentTo(self.camera)

        # Our lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.6, .6, .6, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0, -10, -10))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def setupCollisions(self):
        self.collTrav = CollisionTraverser()

        self.playerGroundSphere = CollisionSphere(0, 1.5, -1.5, 1.5)
        self.playerGroundCol = CollisionNode('playerSphere')
        self.playerGroundCol.addSolid(self.playerGroundSphere)

        # bitmasks
        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 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 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()
Beispiel #5
0
class World(DirectObject):
    #class World, extends DirectObject, builds the world to play the game

###################### INITIALIZATIONS #########################################
    def __init__(self):

        mySplashScreen = SplashScreen()
        mySplashScreen.loading()
        mySplashScreen.introduction()
        self.promptMode()

        self.turnWallNotification()

        ##### Creating Scene #####
        self.createBackground()
        self.loadWallModel()
        self.loadBallModel()
        self.setCamera()
        self.createLighting()

        ##### Create Controls #####
        self.createKeyControls()
        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "drop":0}

        ##### Task Manager #####
        timer = 0.2
        taskMgr.doMethodLater(timer, self.traverseTask, "tsk_traverse")
            #scans for collisions every 0.2 seconds
        taskMgr.add(self.move,"moveTask")
            #constant smooth movement

        ##### Collisions #####
        self.createBallColliderModel()
        self.disableForwardMovement = False
        self.disableBackwardMovement = False
        self.disableLeftMovement = False
        self.disableRightMovement = False

        ##### Game state variables #####
        self.isMoving = False
        self.isDropping = False 
        self.camAngle = math.pi/2
        self.direction = "W" #constant; does not change with relativity
        self.drop = False

        self.levelHeight = 2.1
        self.level = 0
        self.maxLevel = 6
        self.currentHeight = 13.302
        self.cameraHeight = 0.2
        self.mode = None
        self.timer = ""

        ##### Views #####
        self.xray_mode = False
        self.collision_mode = False
        self.wireframe = False

        ##### On-Screen Text #####
        self.title = addTitle("aMAZEing")
        self.instructions = OnscreenText(text="[ i ]: Toggle Instructions", 
                style=1, fg=(0, 0, 0, 1), pos=(1.3, 0.95), 
                align=TextNode.ARight, scale=0.05)
        self.instr = []
        self.messages = []
        self.levelText = OnscreenText(text= "Level = " + str(self.level), 
                style=1, fg=(0, 0, 0, 1), pos=(-1.3, -0.95), 
                align=TextNode.ALeft, scale=0.07)
        self.directionText = OnscreenText(text="Direction = " + self.direction,
                style=1, fg=(0, 0, 0, 1), pos=(-1.3, -0.85),
                align=TextNode.ALeft, scale=0.07)

        self.timerText = OnscreenText(text= self.timer, 
                style=1, fg=(1, 1, 1, 1), pos=(1.3, 0.85), 
                align=TextNode.ARight, scale=0.07)
    
    def setKey(self, key, value):
        #records the state of the arrow keys
        self.keyMap[key] = value

    ###################### Onscreen Text #######################################

    def postInstructions(self):
        #posts the instructions onto the screen

        inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.instr.append(inst1)
        inst2 = addInstructions(0.90,  "[Left Arrow]: Turn Left")
        self.instr.append(inst2)
                               
        inst3 = addInstructions(0.85, "[Right Arrow]: Turn Right")
        self.instr.append(inst3)
                                
        inst4 = addInstructions(0.80, "[Up Arrow]: Move Ball Forward")
        self.instr.append(inst4)
                                
        inst5 = addInstructions(0.75,  "[Down Arrow]: Move Ball Backwards")
        self.instr.append(inst5)
                               
        inst6 = addInstructions(0.70,
                            "[Space]: Drop Levels (if level drop is availale)")
        self.instr.append(inst6)
                               
        inst7 = addInstructions(0.60,  "[x]: Toggle XRay Mode")
        self.instr.append(inst7)
                               
        inst8 = addInstructions(0.55, "[c]: Toggle Collision Mode")
        self.instr.append(inst8)
                                
        inst9 = addInstructions(0.50, "[z]: Toggle Wireframe")
        self.instr.append(inst9)

        inst10 = OnscreenText(text='''Hello!
        Welcome to aMAZEing!
        You are this sphere,
        and your goal is to find the exit of the maze! Each level
        of the maze has a hole you can drop through, to move on to the
        next level. This maze has six levels and each maze is a 12x12.
        If you chose timer mode, you have 5 minutes to finish the maze,
        or else you lose.
        Good luck! You're aMAZEing :)''', style = 1, 
                fg=(0, 0, 0, 1), pos=(0, -.1), align=TextNode.ACenter, scale=0.07)
        self.instr.append(inst10)

    def deleteInstructions(self):
        #deletes onscreen instructions
        for instr in self.instr:
            instr.destroy()

    def addNotification(self, txt):
        #adds a notification to the screen
        y = 0.9
        tex = OnscreenText(text=txt, style=1, fg= (0, 0, 0, 1), pos=(0, y))
        self.messages.append(tex)

    def deleteNotifications(self):
        #deletes all on-screen notifications
        for msg in self.messages:
            msg.destroy()

    def updateLevelText(self):
        #updates the level text
        self.levelText.destroy()

        levelTextPos = (-1.3, -0.95)
        levelScale = 0.07

        self.levelText = OnscreenText(text= "Level = " + str(self.level), 
                style=1, fg=(0, 0, 0, 1), pos=levelTextPos, 
                align=TextNode.ALeft, scale=levelScale)

    def updateDirectionText(self):
        #updates the direction text on the screen
        self.directionText.destroy()

        directionTextPos = (-1.3, -0.85)
        directionScale = 0.07

        self.directionText = OnscreenText(text="Direction = " + self.direction,
                style=1, fg=(0, 0, 0, 1), pos=directionTextPos,
                align=TextNode.ALeft, scale=directionScale)

    def updateTimerText(self):
        #updates timer on screen
        self.timerText.destroy()

        timerTextPos = (1.3, 0.85)
        timerScale = 0.07

        if self.mode == "timer":
            self.timerText = OnscreenText(text= self.timer, 
                style=1, fg=(1, 1, 1, 1), pos=timerTextPos, 
                align=TextNode.ARight, scale=timerScale)

    def turnWallNotification(self):
        #give a notification sequence at the beginning
        notificationSeq = Sequence()
        notificationSeq.append(Func(addNotification,"""
        If you just see a blank color,
        it means you are facing a wall :)"""))
        notificationSeq.append(Wait(8))
        notificationSeq.append(Func(deleteNotifications))
        notificationSeq.start()

    def promptMode(self):
        #prompts for the mode
        modeScreen = SplashScreen()
        modeScreen.mode()

    def setMode(self, mode):
        #sets the mode of the game
        self.mode = mode
        
        if self.mode == "timer":
            self.setTimer()

    ###################### Initialization Helper Functions #####################

    def createBackground(self):
        #black feautureless space
        base.win.setClearColor(Vec4(0,0,0,1))

    def loadWallModel(self):
        #loads the wall model (the maze) 
        wallScale = 0.3
        wallModelName = self.randomWallModel()
            #randomly select a maze

        self.wallModel = loader.loadModel(wallModelName)
        self.wallModel.setScale(wallScale)
        self.wallModel.setPos(0, 0, 0)
        self.wallModel.setCollideMask(BitMask32.allOff())
        self.wallModel.reparentTo(render)

        ### Setting Texture ###
        texScale = 0.08
        self.wallModel.setTexGen(TextureStage.getDefault(),
                                   TexGenAttrib.MWorldNormal)
        self.wallModel.setTexProjector(TextureStage.getDefault(),
                                         render, self.wallModel)
        self.wallModel.setTexScale(TextureStage.getDefault(), texScale)
        tex = loader.load3DTexture('/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/wallTex/wallTex_#.png')
        self.wallModel.setTexture(tex)

        #creating visual geometry collision
        self.wallModel.setCollideMask(BitMask32.bit(0))

    def randomWallModel(self):
        #generates a random wall in the library of mazes that were 
        #randomly generated by the Blender script "mazeGenerator"
        #and exported to this computer
        numMazes = 10

        name = str(random.randint(0, numMazes))
            #randomly selects a number saved in the computer

        path = "/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/mazeModels/maze"

        path += name 

        return path
        
    def loadBallModel(self):
        #loads the character, a ball model

        #ballModelStartPos = (-8, -8, 0.701) #THIS IS THE END
        ballModelStartPos = (8, 8, 13.301) #level 0 
        ballScale = 0.01
        self.ballModel = loader.loadModel("/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/ball")
        self.ballModel.reparentTo(render)
        self.ballModel.setScale(ballScale)
        self.ballModel.setPos(ballModelStartPos)


        ### Setting ball texture ###
        texScale = 0.08
        self.ballModel.setTexGen(TextureStage.getDefault(),
                                   TexGenAttrib.MWorldPosition)
        self.ballModel.setTexProjector(TextureStage.getDefault(), 
                                         render, self.ballModel)
        self.ballModel.setTexScale(TextureStage.getDefault(), texScale)
        tex = loader.load3DTexture('/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/ballTex/ballTex_#.png')
        self.ballModel.setTexture(tex)

    def setCamera(self):
        #sets up the initial camera location
        #camera will follow the sphere 
        followLength = 2
        camHeight = 0.2

        base.disableMouse()
        base.camera.setPos(self.ballModel.getX(),
                                self.ballModel.getY() - followLength,
                                self.ballModel.getZ() + camHeight)
        base.camLens.setNear(0.4)

        #creates a floater object - will look at the floater object 
        #above the sphere, so you can get a better view
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

    def createKeyControls(self):
        #creates the controllers for the keys
        #event handler
        #describes what each key does when pressed and unpressed

        self.accept("escape", sys.exit)

        self.accept("arrow_left", self.turnLeft)
        self.accept("arrow_right", self.turnRight)
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_down", self.setKey, ["backward",1])
        self.accept("space", self.nowDropping)

        #unpressed event handlers
        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("arrow_down-up", self.setKey, ["backward",0])
        self.accept("space_up", self.setKey, ["drop", 0])

        #views
        self.accept('x', self.toggle_xray_mode)
        self.accept('c', self.toggle_collision_mode)
        self.accept('z', self.toggle_wireframe)

        #information
        self.accept('i', self.postInstructions)
        self.accept('i-up', self.deleteInstructions)

        #restart
        self.accept('r', self.restart)

        #modes
        self.accept("t", self.setMode, ["timer"])
        self.accept("m", self.setMode, ["marathon"])

    def createBallColliderModel(self):
        #creates the collider sphere around the ball
        cSphereRad = 9.9
        self.cTrav = CollisionTraverser() #moves over all possible collisions

        self.ballModelSphere = CollisionSphere(0, 0, 0, cSphereRad)
            #collision mesh around ball is a simple sphere
        self.ballModelCol = CollisionNode('ballModelSphere')
        self.ballModelCol.addSolid(self.ballModelSphere)
        self.ballModelCol.setFromCollideMask(BitMask32.bit(0))
        self.ballModelCol.setIntoCollideMask(BitMask32.allOff())
        self.ballModelColNp = self.ballModel.attachNewNode(self.ballModelCol)
        self.ballModelGroundHandler = CollisionHandlerQueue()
            #collision handler queue stores all collision points
        self.cTrav.addCollider(self.ballModelColNp, self.ballModelGroundHandler)

    def createLighting(self):
        #creates lighting for the scene
        aLightVal = 0.3
        dLightVal1 = -5
        dLightVal2 = 5

        #set up the ambient light
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(aLightVal, aLightVal, aLightVal, 1))
        ambientLight1 = AmbientLight("ambientLight1")
        ambientLight1.setColor(Vec4(aLightVal, aLightVal, aLightVal, 1))
        ambientLight2 = AmbientLight("ambientLight2")
        ambientLight2.setColor(Vec4(aLightVal, aLightVal, aLightVal, 1))

        #sets a directional light
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(dLightVal1, dLightVal1, dLightVal1))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(0, 0, 0, 1))

        #sets a directional light
        directionalLight1 = DirectionalLight("directionalLight2")
        directionalLight1.setDirection(Vec3(dLightVal2, dLightVal1, dLightVal1))
        directionalLight1.setColor(Vec4(1, 1, 1, 1))
        directionalLight1.setSpecularColor(Vec4(1, 1, 1, 1))


        #attaches lights to scene
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(ambientLight1))
        render.setLight(render.attachNewNode(ambientLight1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(directionalLight1))

###################### COLLISION DETECTION #####################################

    def traverseTask(self, task=None):
        # handles collisions with collision handers and a 
        # collision queue
        # essentially checks region of potential collision for collisions
        # and stops the ball if a collision is triggered
        # called by task manager
        self.ballModelGroundHandler.sortEntries()
        for i in range(self.ballModelGroundHandler.getNumEntries()):
            entry = self.ballModelGroundHandler.getEntry(i)

            if self.drop == True:
                #we cant drop in this situation
                self.ballModel.setZ(self.currentHeight)

                dropFailWait = 4
                dropFailSeq = Sequence()
                dropFailSeq.append(Func(addNotification,"Whoops! You can't drop here!"))
                dropFailSeq.append(Wait(dropFailWait))
                dropFailSeq.append(Func(deleteNotifications))
                dropFailSeq.start()

                self.drop = False

            elif self.direction == "N":
                self.northDisableMovements()

            elif self.direction == "S":
                self.southDisableMovements()

            elif self.direction == "E":
                self.eastDisableMovements()

            elif self.direction == "W":
                self.westDisableMovements()

            if task: return task.cont #exit task

        # If there are no collisions
        
        if task: return task.cont

    def northDisableMovements(self):
        #disables movements when direction is north
        if self.keyMap["forward"] != 0: #if the ball was moving foward
            self.disableForwardMovement = True #disable forward movement
        if self.keyMap["backward"] != 0:
            self.disableBackwardMovement = True

    def southDisableMovements(self):
        #disables movements when direction is south
        if self.keyMap["forward"] != 0: 
            self.disableBackwardMovement = True 
        if self.keyMap["backward"] != 0:
            self.disableForwardMovement = True

    def eastDisableMovements(self):
        #disables movements when direction is east
        if self.keyMap["forward"] != 0: 
            self.disableRightMovement = True 
        if self.keyMap["backward"] != 0:
            self.disableLeftMovement = True

    def westDisableMovements(self):
        #disables movements when direction is west
        if self.keyMap["forward"] != 0: 
            self.disableLeftMovement = True 
        if self.keyMap["backward"] != 0:
            self.disableRightMovement = True

    def checkCollisions(self):
        #checks for collisions
        self.cTrav.traverse(render)

    def enableAllWalls(self):
        #enables all walls by disabling all the disable wall functions
        self.disableLeftMovement = False
        self.disableRightMovement = False 
        self.disableForwardMovement = False
        self.disableBackwardMovement = False

    def inCollision(self):
        #return true if we are in a collision right now, false otherwise
        if (self.disableForwardMovement == True
            or self.disableBackwardMovement == True 
            or self.disableRightMovement == True 
            or self.disableLeftMovement):
            return True
        return False

    def checkForWin(self):
        #checks for a win, toggles win splash sceen if we win
        yLoc = self.ballModel.getY()
        exitBound = -9.1

        if yLoc < exitBound: 
            winScreen = SplashScreen()
            winScreen.win()

        if self.mode == "timer":
            self.checkForTimerLoss()

    def checkForTimerLoss(self):
        #checks to see the time, will lose if past 5 minutes
        
        if self.timer == "0:05:00":
            loseScreen = SplashScreen()
            loseScreen.lose()

###################### MOVEMENTS ###############################################

    def move(self, task):
        # Accepts arrow keys to move the player front and back
        # Also deals with grid checking and collision detection

        step = 0.03

        #movement animation
        self.movementAnimation(step)
        #rotation animation
        self.rotationAnimation()

        base.camera.setX(self.ballModel.getX() + math.sin(self.camAngle))
        base.camera.setY(self.ballModel.getY() + math.cos(self.camAngle))

        self.resetCamDist()
        self.checkCollisions()
        self.lookAtFloater()

        self.checkForWin()

        return task.cont

    def resetCamDist(self):
        #resets the camera distance to a specific distance
        #keeps distance relatively constant
        camFarDist = 0.75
        camCloseDist = 0.7

        camvec = self.ballModel.getPos() - base.camera.getPos()
            #vector between ball and camera
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()

        if (camdist > camFarDist):
            base.camera.setPos(base.camera.getPos() + 
                                    camvec*(camdist-camFarDist))
            camdist = camFarDist

        if (camdist < camCloseDist):
            base.camera.setPos(base.camera.getPos() -
                                    camvec*(camCloseDist-camdist))
            camdist = camCloseDist

        base.camera.lookAt(self.ballModel)

    def lookAtFloater(self):
        #looks at the floater above the sphere
        floaterHeight = 0.23
        self.floater.setPos(self.ballModel.getPos())
        self.floater.setZ(self.ballModel.getZ() + floaterHeight)
        base.camera.lookAt(self.floater)

    ####################### Movement Animation #################################

    def ballIsMoving(self):
        #notes if the ball is moving or not with self.isMoving variable
        if (self.keyMap["forward"]!=0) or (self.keyMap["backward"]!=0):
            if self.isMoving == False:
                self.isMoving = True

        elif self.keyMap["forward"] == 0 and self.keyMap["backward"] == 0:
            self.isMoving = False

    def movementAnimation(self, step):
        #describes the movement animation
        if self.drop == True:
            self.dropMovementAnimation(step)
        elif self.direction == "N":
            self.northMovementAnimation(step)

        elif self.direction == "S":
            self.southMovementAnimation(step)

        elif self.direction == "E":
            self.eastMovementAnimation(step)

        elif self.direction == "W":
            self.westMovementAnimation(step)

    def northMovementAnimation(self, step):
        #describes animation when direction is north
        if (self.keyMap["forward"]!=0):
            #if you are pressing forward
            if self.disableForwardMovement == False:
                #if you are just moving through space...
                self.ballModel.setY(self.ballModel.getY() + step)
            if self.disableBackwardMovement == True:
                #if you had moved backwards into a wall
                #and you want to move forward again
                self.ballModel.setY(self.ballModel.getY() + step)
                self.disableBackwardMovement = False
                

        if (self.keyMap["backward"]!=0):
            #if you are pressing backwards
            if self.disableBackwardMovement == False:
                #if you are just moving backwards through space...
                self.ballModel.setY(self.ballModel.getY() - step)
            if self.disableForwardMovement == True:
                #if you had moved forward into a wall
                #and want to back away from the wall
                self.ballModel.setY(self.ballModel.getY() - step)
                self.disableForwardMovement = False        

    def southMovementAnimation(self, step):
        #describes animation when direction is north
        #same relative set of animations to northMovementAnimation
        #but opposite
        if (self.keyMap["forward"]!=0):
            if self.disableBackwardMovement == False:
                self.ballModel.setY(self.ballModel.getY() - step)
            if self.disableForwardMovement == True:
                self.ballModel.setY(self.ballModel.getY() - step)
                self.disableForwardMovement = False

        if (self.keyMap["backward"]!=0):
            if self.disableForwardMovement == False:
                self.ballModel.setY(self.ballModel.getY() + step)
            if self.disableBackwardMovement == True:
                self.ballModel.setY(self.ballModel.getY() + step)
                self.disableBackwardMovement = False        

    def eastMovementAnimation(self, step):
        #describes animation when direction is east
        #same relative as north and south movement animations
        #but relative to the x axis
        #and disabling/enabling right and left movement at collisions
        if (self.keyMap["forward"]!=0):
            if self.disableRightMovement == False:
                self.ballModel.setX(self.ballModel.getX() + step)
            if self.disableLeftMovement == True:
                self.ballModel.setX(self.ballModel.getX() + step)
                self.disableLeftMovement = False

        if (self.keyMap["backward"]!=0):
            if self.disableLeftMovement == False:
                self.ballModel.setX(self.ballModel.getX() - step)
            if self.disableRightMovement == True:
                self.ballModel.setX(self.ballModel.getX() - step)
                self.disableRightMovement = False

    def westMovementAnimation(self, step):
        #describes animation when direction is west
        #relatively same animations as the east movement animations
        #exact opposite
        if (self.keyMap["forward"]!=0):
            if self.disableLeftMovement == False:
                self.ballModel.setX(self.ballModel.getX() - step)
            if self.disableRightMovement == True:
                self.ballModel.setX(self.ballModel.getX() - step)
                self.disableRightMovement = False

        if (self.keyMap["backward"]!=0):
            if self.disableRightMovement == False:
                self.ballModel.setX(self.ballModel.getX() + step)
            if self.disableLeftMovement == True:
                self.ballModel.setX(self.ballModel.getX() + step)
                self.disableLeftMovement = False

    def turnRight(self):
        #turns right in the animation

        #uses an interval to slowly rotate camera around
        initial = self.camAngle
        final = self.camAngle + math.pi/2

        #turn animation
        turnTime = 0.2
        turnRightSeq = Sequence()
        turnRightSeq.append(LerpFunc(self.changeCamAngle, turnTime, initial,
                                                         final, 'easeInOut'))
        turnRightSeq.start()

        self.setKey("right", 1) #notes that the right key is pressed

        #changes the direction right, based on current direction
        if self.direction == "N":
            self.direction = "E"
        elif self.direction == "E":
            self.direction = "S"
        elif self.direction == "S":
            self.direction = "W"
        else:
            self.direction = "N"

        #when you turn, all the collision disablements should be True
        #just checking
        #self.enableAllWalls()

        #update the label
        self.updateDirectionText()

    def turnLeft(self):
        #turns left

        initial = self.camAngle
        final = self.camAngle - math.pi/2

        #turn animation
        turnTime = 0.2
        turnRightSeq = Sequence()
        turnRightSeq.append(LerpFunc(self.changeCamAngle, turnTime, initial,
                                                         final, 'easeInOut'))
        turnRightSeq.start()


        self.setKey("left", 1) #notes that left key is pressed

        #changes the direction left, based on current direction
        if self.direction == "N":
            self.direction = "W"
        elif self.direction == "W":
            self.direction = "S"
        elif self.direction == "S":
            self.direction = "E"
        else:
            self.direction = "N"

        #when you turn, all the collision disablements should be True
        #just checking
        #self.enableAllWalls()

        #update the label
        self.updateDirectionText()

    def changeCamAngle(self, angle):
        #changes the camAngle to angle
        self.camAngle = angle

    def dropMovementAnimation(self, step):
        #describes movement when drop is hit

        a = 0.1

        if self.keyMap["drop"] != 0:
            if self.ballModel.getZ() > self.currentHeight - self.levelHeight+ a:
                self.ballModel.setZ(self.ballModel.getZ() - step)
            else:
                self.currentHeight -= self.levelHeight
                self.level += 1
                self.updateLevelText()
                self.drop = False
                base.camera.setZ(self.ballModel.getZ() + self.cameraHeight)

    def nowDropping(self):
        #toggles isDropping boolean
        self.drop = True
        self.setKey("drop", 1)
        
    ################## Ball Rotation Animation #################################

    def rotationAnimation(self):
        #describes the rotation movement of sphere
        self.ballIsMoving()
        speed=300
        inCollision = self.inCollision()

        if self.isMoving and not inCollision:
            if self.direction == "N":
                self.northRotationAnimation(speed)
            if self.direction == "S":
                self.southRotationAnimation(speed)
            if self.direction == "E":
                self.eastRotationAnimation(speed)
            if self.direction == "W":
                self.westRotationAnimation(speed)

    def northRotationAnimation(self, speed):
        #describes the rotation animation if direction is north
        if self.keyMap["forward"] != 0:
            self.ballModel.setP(self.ballModel.getP()-speed*globalClock.getDt())
        elif self.keyMap["backward"] != 0:
            self.ballModel.setP(self.ballModel.getP()+speed*globalClock.getDt())

    def southRotationAnimation(self, speed):
        #describes the rotaiton animation if the direction is south
        if self.keyMap["backward"] != 0:
            self.ballModel.setP(self.ballModel.getP()-speed*globalClock.getDt())
        elif self.keyMap["forward"] != 0:
            self.ballModel.setP(self.ballModel.getP()+speed*globalClock.getDt())

    def eastRotationAnimation(self, speed):
        #describes the rotation animation if the direction is east
        if self.keyMap["backward"] != 0:
            self.ballModel.setR(self.ballModel.getR()-speed*globalClock.getDt())
        elif self.keyMap["forward"] != 0:
            self.ballModel.setR(self.ballModel.getR()+speed*globalClock.getDt())

    def westRotationAnimation(self, speed):
        #describes the rotation animation if the direction is west
        if self.keyMap["forward"] != 0:
            self.ballModel.setR(self.ballModel.getR()-speed*globalClock.getDt())
        elif self.keyMap["backward"] != 0:
            self.ballModel.setR(self.ballModel.getR()+speed*globalClock.getDt())

###################### VIEWS ###################################################

    def toggle_xray_mode(self):
        #Toggle X-ray mode on and off.
        #Note: slows down program considerably
        xRayA = 0.5
        self.xray_mode = not self.xray_mode
        if self.xray_mode:
            self.wallModel.setColorScale((1, 1, 1, xRayA))
            self.wallModel.setTransparency(TransparencyAttrib.MDual)
        else:
            self.wallModel.setColorScaleOff()
            self.wallModel.setTransparency(TransparencyAttrib.MNone)

    def toggle_collision_mode(self):
        #Toggle collision mode on and off
        #Shows visual representation of the collisions occuring
        self.collision_mode = not self.collision_mode
        if self.collision_mode == True:
            # Note: Slows the program down considerably
            self.cTrav.showCollisions(render)
        else:
            self.cTrav.hideCollisions()

    def toggle_wireframe(self):
        #toggles wireframe view
        self.wireframe = not self.wireframe
        if self.wireframe:
            self.wallModel.setRenderModeWireframe()
        else:
            self.wallModel.setRenderModeFilled()

##################### RESTART ##################################################
    
    def restart(self):
        #restarts the game
        loading = SplashScreen()
        loading.loading()
        self.reset()

    def reset(self):
        #resets the maze, resets the location of the character

        #removes all notes
        self.wallModel.removeNode()
        self.ballModel.removeNode()

        #resets notes
        self.loadWallModel()
        self.loadBallModel()
        self.createBallColliderModel()
        self.resetCamDist()

        #resets timers
        taskMgr.remove("timerTask")
        self.timer = ""
        self.timerText.destroy()

        self.promptMode()

#################### TIMER #####################################################

    def setTimer(self):
        #code from panda.egg user on Panda3D, 
        #"How to use Timer, a small example maybe?" forum
        #creates a timer
        self.timer = DirectLabel(pos=Vec3(1, 0.85),scale=0.08)

        taskMgr.add(self.timerTask, "timerTask")

    def dCharstr(self, theString):
        #code from panda.egg user on Panda3D, 
        #"How to use Timer, a small example maybe?" forum
        #turns time string into a readable clock string
        if len(theString) != 2:
            theString = '0' + theString
        return theString

    def timerTask(self, task):
        #code from panda.egg user on Panda3D, 
        #"How to use Timer, a small example maybe?" forum
        #task for resetting timer in timer mode
        secondsTime = int(task.time)
        minutesTime = int(secondsTime/60)
        hoursTime = int(minutesTime/60)
        self.timer = (str(hoursTime) + ':' 
                            + self.dCharstr(str(minutesTime%60)) + ':' 
                            + self.dCharstr(str(secondsTime%60)))

        self.updateTimerText()
        
        return Task.cont
Beispiel #6
0
class BallPlateWorld(WorldBase):
    
  def __init__(self, controller, log_2_memory, display_categories):    
    WorldBase.__init__(self, controller, log_2_memory, display_categories)
    self.display_categories = display_categories
    self.last_time = time.time()
    self.step = 0
    self.__init_kepler_scene()
    
      
    
  
  def set_3d_scene(self, x,y,z, alpha, beta, dt):
    new_position = Point3(x,y,z)
    self.maze.setP(-self.alpha)
    self.maze.setR(-self.beta)
    self.ballRoot.setPos(new_position)

    #This block of code rotates the ball. It uses a quaternion
    #to rotate the ball around an arbitrary axis. That axis perpendicular to
    #the balls rotation, and the amount has to do with the size of the ball
    #This is multiplied on the previous rotation to incrimentally turn it.
    prevRot = LRotationf(self.ball.getQuat())
    axis = UP.cross(self.ballV)
    newRot = LRotationf(axis, 45.5 * dt * self.ballV.length())
    self.ball.setQuat(prevRot * newRot)

 
  def __init_kepler_scene(self):
    self.hud_count_down = 0
    self.alpha = 0.
    self.beta = 0.  
    self._set_title("Hugomatic 3D sim")
    self.alpha_rot_speed = 0.
    self.beta_rot_speed = 0.
    
    #This code puts the standard title and instruction text on screen
    self.title = OnscreenText(text="Kepler simulation tool 1",
                              style=1, fg=(1,1,1,1),
                              pos=(0.7,-0.95), scale = .07, font = font)
    
    self.instructions = OnscreenText(text="alpha: 0.000\nbeta: 0.000",
                                     pos = (-1.3, .95), fg=(1,1,1,1), font = font,
                                     align = TextNode.ALeft, scale = .05)
    
    if DISABLE_MOUSE:
        base.disableMouse()                    #Disable mouse-based camera control
    camera.setPosHpr(-10, -10, 25, 0, -90, 0)  #Place the camera

    #Load the maze and place it in the scene
    self.maze = loader.loadModel("models/maze")
    process_model(self.maze)
    self.maze.reparentTo(render)

    #Most times, you want collisions to be tested against invisible geometry
    #rather than every polygon. This is because testing against every polygon
    #in the scene is usually too slow. You can have simplified or approximate
    #geometry for the solids and still get good results.
    #
    #Sometimes you'll want to create and position your own collision solids in
    #code, but it's often easier to have them built automatically. This can be
    #done by adding special tags into an egg file. Check maze.egg and ball.egg
    #and look for lines starting with <Collide>. The part is brackets tells
    #Panda exactly what to do. Polyset means to use the polygons in that group
    #as solids, while Sphere tells panda to make a collision sphere around them
    #Keep means to keep the polygons in the group as visable geometry (good
    #for the ball, not for the triggers), and descend means to make sure that
    #the settings are applied to any subgroups.
    #
    #Once we have the collision tags in the models, we can get to them using
    #NodePath's find command

    #Find the collision node named wall_collide
    self.walls = self.maze.find("**/wall_collide")

    #Collision objects are sorted using BitMasks. BitMasks are ordinary numbers
    #with extra methods for working with them as binary bits. Every collision
    #solid has both a from mask and an into mask. Before Panda tests two
    #objects, it checks to make sure that the from and into collision masks
    #have at least one bit in common. That way things that shouldn't interact
    #won't. Normal model nodes have collision masks as well. By default they
    #are set to bit 20. If you want to collide against actual visible 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
    if VISIBLE_WALLS:
        self.walls.show()

    #Ground_collide is a single polygon on the same plane as the ground in the
    #maze. We will use a ray to collide with it so that we will know exactly
    #what height to put the ball at every frame. Since this is not something
    #that we want the ball itself to collide with, it has a different
    #bitmask.
    self.mazeGround = self.maze.find("**/ground_collide")
    self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1))
    
    #Load the ball and attach it to the scene
    #It is on a root dummy node so that we can rotate the ball itself without
    #rotating the ray that will be attached to it
    self.ballRoot = render.attachNewNode("ballRoot")
    self.ball = loader.loadModel("models/ball")
    self.ball.reparentTo(self.ballRoot)

    #Find the collison sphere for the ball which was created in the egg file
    #Notice that it has a from collision mask of bit 0, and an into collison
    #mask of no bits. This means that the ball can only cause collisions, not
    #be collided into
    self.ballSphere = self.ball.find("**/ball")
    self.ballSphere.node().setFromCollideMask(BitMask32.bit(0))
    self.ballSphere.node().setIntoCollideMask(BitMask32.allOff())

    #No we create a ray to start above the ball and cast down. This is to
    #Determine the height the ball should be at and the angle the floor is
    #tilting. We could have used the sphere around the ball itself, but it
    #would not be as reliable
    self.ballGroundRay = CollisionRay()     #Create the ray
    self.ballGroundRay.setOrigin(0,0,10)    #Set its origin
    self.ballGroundRay.setDirection(0,0,-1) #And its direction
    #Collision solids go in CollisionNode
    self.ballGroundCol = CollisionNode('groundRay') #Create and name the node
    self.ballGroundCol.addSolid(self.ballGroundRay) #Add the ray
    self.ballGroundCol.setFromCollideMask(BitMask32.bit(1)) #Set its bitmasks
    self.ballGroundCol.setIntoCollideMask(BitMask32.allOff())
    #Attach the node to the ballRoot so that the ray is relative to the ball
    #(it will always be 10 feet over the ball and point down)
    self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol)
    #Uncomment this line to see the ray
    self.ballGroundColNp.show()

    #Finally, we create a CollisionTraverser. CollisionTraversers are what
    #do the job of calculating collisions
    self.cTrav = CollisionTraverser()
    #Collision traverservs tell collision handlers about collisions, and then
    #the handler decides what to do with the information. We are using a
    #CollisionHandlerQueue, which simply creates a list of all of the
    #collisions in a given pass. There are more sophisticated handlers like
    #one that sends events and another that tries to keep collided objects
    #apart, but the results are often better with a simple queue
    self.cHandler = CollisionHandlerQueue()
    #Now we add the collision nodes that can create a collision to the
    #traverser. The traverser will compare these to all others nodes in the
    #scene. There is a limit of 32 CollisionNodes per traverser
    #We add the collider, and the handler to use as a pair
    self.cTrav.addCollider(self.ballSphere, self.cHandler)
    self.cTrav.addCollider(self.ballGroundColNp, self.cHandler)

    #Collision traversers have a built in tool to help visualize collisions.
    #Uncomment the next line to see it.
    if VISIBLE_WALLS:
        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
    lAttrib = LightAttrib.makeAllOff()
    ambientLight = AmbientLight( "ambientLight" )
    ambientLight.setColor( Vec4(.55, .55, .55, 1) )
    lAttrib = lAttrib.addLight( ambientLight )
    directionalLight = DirectionalLight( "directionalLight" )
    directionalLight.setDirection( Vec3( 0, 0, -1 ) )
    directionalLight.setColor( Vec4( 0.375, 0.375, 0.375, 1 ) )
    directionalLight.setSpecularColor(Vec4(1,1,1,1))
    lAttrib = lAttrib.addLight( directionalLight )
    self.ballRoot.node().setAttrib( lAttrib )
    
    #This section deals with adding a specular highlight to the ball to make
    #it look shiny
    m = Material()
    m.setSpecular(Vec4(1,1,1,1))
    m.setShininess(96)
    self.ball.setMaterial(m, 1)

    #Finally, we call start for more initialization
    # self.start()
  
      
    #def start(self):
    #The maze model also has a locator in it for where to start the ball
    #To access it we use the find command
    startPos = (0,0,0)#= self.maze.find("**/start").getPos()
    self.ballRoot.setPos(startPos)   #Set the ball in the starting position
    self.ballV = Vec3(0,0,0)         #Initial velocity is 0
    self.accelV = Vec3(0,0,0)        #Initial acceleration is 0
    
    #For a traverser to actually do collisions, you need to call
    #traverser.traverse() on a part of the scene. Fortunatly, base has a
    #task that does this for the entire scene once a frame. This sets up our
    #traverser as the one to be called automatically
    base.cTrav = self.cTrav

  #This function handles the collision between the ray and the ground
  #Information about the interaction is passed in colEntry
  def groundCollideHandler(self, colEntry):
    #Set the ball to the appropriate Z value for it to be exactly on the ground
    newZ = colEntry.getSurfacePoint(render).getZ()
    self.ballRoot.setZ(newZ + .4)

    #Find the acceleration direction. First the surface normal is crossed with
    #the up vector to get a vector perpendicular to the slope
    norm = colEntry.getSurfaceNormal(render)
    accelSide = norm.cross(UP)
    #Then that vector is crossed with the surface normal to get a vector that
    #points down the slope. By getting the acceleration in 3D like this rather
    #than in 2D, we reduce the amount of error per-frame, reducing jitter
    self.accelV = norm.cross(accelSide)

  #This function handles the collision between the ball and a wall
  def wallCollideHandler(self, colEntry):
    #First we calculate some numbers we need to do a reflection
    norm = colEntry.getSurfaceNormal(render) * -1 #The normal of the wall
    curSpeed = self.ballV.length()                #The current speed
    inVec = self.ballV / curSpeed                 #The direction of travel
    velAngle = norm.dot(inVec)                    #Angle of incidance
    hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos()
    hitDir.normalize()                            
    hitAngle = norm.dot(hitDir)   #The angle between the ball and the normal

    #Ignore the collision if the ball is either moving away from the wall
    #already (so that we don't accidentally send it back into the wall)
    #and ignore it if the collision isn't dead-on (to avoid getting caught on
    #corners)
    if velAngle > 0 and hitAngle > .995:
      #Standard reflection equation
      reflectVec = (norm * norm.dot(inVec * -1) * 2) + inVec
        
      #This makes the velocity half of what it was if the hit was dead-on
      #and nearly exactly what it was if this is a glancing blow
      self.ballV = reflectVec * (curSpeed * (((1-velAngle)*.5)+.5))
      #Since we have a collision, the ball is already a little bit buried in
      #the wall. This calculates a vector needed to move it so that it is
      #exactly touching the wall
      disp = (colEntry.getSurfacePoint(render) -
              colEntry.getInteriorPoint(render))
      newPos = self.ballRoot.getPos() + disp
      self.ballRoot.setPos(newPos)

  def update_hud(self):
    self.hud_count_down -= 1
    if self.hud_count_down <= 0:
        self.hud_count_down = 5
        p1, p2 = self.get_ball_position()
        text =  "\nalpha: %.5f\nbeta: %.5f\npos [%.05f,%.05f]\n" % (self.alpha, self.beta, p1,p2)
        self.instructions.setText(text) 
    
  def control_task(self,task):
        delta_time = task.time - self.last_time
        self.last_time = task.time
        self.step += 1
        if self.controller:
            self.controller.loop(self.step, task.time, delta_time)     

        if self.logging:
            data = self.controller.get_display_data()
            self.log.snapshot(get_data_logger(), self.step, task.time, data, ('self'))        
 
  def get_table_inclination(self):
      angle1 = math.radians(self.alpha)
      angle2 = math.radians(self.beta)
      return (angle1, angle2)
  
  def set_table_rotation_speed(self, alpha_rot_speed, beta_rot_speed):
      self.alpha_rot_speed = alpha_rot_speed
      self.beta_rot_speed = beta_rot_speed
  
  def get_ball_position(self):
      p = self.ballRoot.getPos()
      p1 = p[0]
      p2 = p[1]
      #print "ball position [%s, %s]" % (p1, p2)
      return (p1, p2)
Beispiel #7
0
class DemoGame(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.debug = False
        self.status_label = self.makeStatusLabel(0)
        self.collision_label = self.makeCollisionLabel(1)

        # terrain = GeoMipTerrain("worldTerrain")
        # terrain.setHeightfield("models/height_map.png")
        # terrain.setColorMap("models/colour_map_flipped.png")
        # terrain.setBruteforce(True)
        # root = terrain.getRoot()
        # root.reparentTo(render)
        # root.setSz(60)
        # terrain.generate()
        # root.writeBamFile("models/world.bam")

        self.world = self.loader.loadModel("models/world.bam")
        self.world.reparentTo(self.render)
        self.world_size = 1024

        self.player = self.loader.loadModel("models/alliedflanker")    # alliedflanker.egg by default
        self.max_speed = 100.0
        self.start_pos = Vec3(200, 200, 65)
        self.start_hpr = Vec3(225, 0, 0)
        self.player.setScale(0.2, 0.2, 0.2)
        self.player.reparentTo(self.render)
        self.resetPlayer()

        self.taskMgr.add(self.updateTask, "update")
        self.keyboardSetup()

        self.max_distance = 400
        if not self.debug:
            self.camLens.setFar(self.max_distance)
        else:
            base.oobe()

        self.camLens.setFov(60)
        self.createEnvironment()
        self.setupCollisions()
        self.text_counter = 0

        # load the explosion ring
        self.explosion_model = loader.loadModel("models/explosion")    # Panda3D Defaults to '.egg'
        self.explosion_model.reparentTo(self.render)
        self.explosion_model.setScale(0.0)
        self.explosion_model.setLightOff()
        # Only one explosion at a time
        self.exploding = False

    def makeStatusLabel(self, i):
        return OnscreenText(style=2, fg=(0.5, 1, 0.5, 1), pos=(-1.3, 0.92, (-0.08 * i)),
                            align=TextNode.ALeft, scale=0.08, mayChange=1)

    def makeCollisionLabel(self, i):
        return OnscreenText(style=2, fg=(0.5, 1, 0.5, 1), pos=(-1.3, 0.92, (-0.08 * i)),
                            align=TextNode.ALeft, scale=0.08, mayChange=1)

    def resetPlayer(self):
        self.player.show()
        self.player.setPos(self.world, self.start_pos)
        self.player.setHpr(self.world, self.start_hpr)
        self.speed = self.max_speed / 2

    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 setKey(self, key, value):
        self.keyMap[key] = value

    def updateTask(self, task):
        self.updatePlayer()
        self.updateCamera()

        self.coll_trav.traverse(self.render)
        for i in range(self.player_ground_handler.getNumEntries()):
            entry = self.player_ground_handler.getEntry(i)
            if self.debug:
                self.collision_label.setText("dead:"+str(globalClock.getFrameTime()))
            if not self.exploding:
                self.player.setZ(entry.getSurfacePoint(self.render).getZ() + 10)
                self.explosionSequence()
        return Task.cont

    def explosionSequence(self):
        self.exploding = True
        pos = Vec3(self.player.getX(), self.player.getY(), self.player.getZ())
        hpr = Vec3(self.player.getH(), 0, 0)
        self.explosion_model.setPosHpr(pos, hpr)
        self.player.hide()
        taskMgr.add(self.expandExplosion, "expandExplosion")

    def expandExplosion(self, Task):
        if self.explosion_model.getScale() < VBase3(60.0, 60.0, 60.0):
            factor = globalClock.getDt()
            scale = self.explosion_model.getScale()
            scale += VBase3(factor*40, factor*40, factor*40)
            self.explosion_model.setScale(scale)
            return Task.cont
        else:
            self.explosion_model.setScale(0)
            self.exploding = False
            self.resetPlayer()

    def updatePlayer(self):
        # Global Clock
        # by default, panda runs as fast as it can frame by frame
        scale_factor = (globalClock.getDt()*self.speed)
        climb_factor = scale_factor * 0.5
        bank_factor = scale_factor
        speed_factor = scale_factor * 2.9
        gravity_factor = 2 * (self.max_speed - self.speed) / 100

        # Climb and Fall
        if self.keyMap["climb"] != 0 and self.speed > 0.00:
            # The faster you go, the faster you climb
            self.player.setZ(self.player.getZ() + climb_factor)
            self.player.setR(self.player.getR() + climb_factor)
            # quickest return: avaoids 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() - climb_factor)
            self.player.setR(self.player.getR() - climb_factor)
            # 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() - (climb_factor + 0.1))
            if self.player.getR() < 0:
                self.player.setR(0)
        elif self.player.getR() < 0:
            self.player.setR(self.player.getR() + (climb_factor + 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() + bank_factor)
            self.player.setP(self.player.getP() + bank_factor)
            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() - bank_factor)
            self.player.setP(self.player.getP() - bank_factor)
            if self.player.getP() <= -180:
                self.player.setP(180)
        elif self.player.getP() > 0:
            self.player.setP(self.player.getP() - (bank_factor + 0.1))
            if self.player.getP() < 0:
                self.player.setP(0)
        elif self.player.getP() < 0:
            self.player.setP(self.player.getP() + (bank_factor + 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.max_speed:
                self.speed = self.max_speed
        elif self.keyMap["decelerate"] != 0:
            self.speed -= 1
            if self.speed < 0.0:
                self.speed = 0.0

        # move forwards - our X/Y is inverted
        if not self.exploding:
            self.player.setX(self.player, -speed_factor)
            self.applyBoundaries()
            self.player.setZ(self.player, -gravity_factor)

    def applyBoundaries(self):
        # respet max camera distance else you
        # cannot see the floor post loop the loop
        if self.player.getZ() > self.max_distance:
            self.player.setZ(self.max_distance)
        # should never happen once we add collusion, but in case:
        elif self.player.getZ() < 0:
            self.player.setZ(0)

        boundary = False

        # and now the X/Y world boundaries:
        if self.player.getX() < 0:
            self.player.setX(0)
            boundary = True
        elif self.player.getX() > self.world_size:
            self.player.setX(self.world_size)
            boundary = True

        if self.player.getY() < 0:
            self.player.setY(0)
            boundary = True
        elif self.player.getY() > self.world_size:
            self.player.setY(self.world_size)
            boundary = True

        # Avoid doing this every frame
        if boundary and self.text_counter > 30:
            self.status_label.setText("STATUS: MAP END; TURN AROUND")
        elif self.text_counter > 30:
            self.status_label.setText("STATUS: OK")

        if self.text_counter > 30:
            self.text_counter = 0
        else:
            self.text_counter += 1

    def updateCamera(self):
        self.camera.setPos(self.player, 25.6225, 3.8807, 10.2779)
        self.camera.setHpr(self.player, 94.8996, -16.6549, 1.55508)

    def createEnvironment(self):
        # Fog to hide a performance tweak
        exp_fog = Fog("scene-wide-fog")
        exp_fog.setColor(1, 0.8, 0.8)
        exp_fog.setExpDensity(0.002)
        render.setFog(exp_fog)
        # base.setBackgroundColor(*colour)

        # Sky Dome
        '''
        sky_dome = loader.loadModel("models/sky")      # sky_sphere.egg by default
        sky_dome.setEffect(CompassEffect.make(self.render))
        sky_dome.setScale(self.max_distance / 2)
        sky_dome.setZ(-65)  # sink it
        # NOT render - you'll fly through the sky!
        sky_dome.reparentTo(self.camera)
        '''

        # Sky Sphere
        sky_sphere = self.loader.loadModel("models/sky_sphere")
        sky_sphere.setEffect(CompassEffect.make(self.render))
        sky_sphere.setScale(0.08)
        sky_sphere.reparentTo(self.camera)

        # Lighting
        ambient_light = AmbientLight("ambientLight")
        ambient_colour = Vec4(0.6, 0.6, 0.6, 1)
        ambient_light.setColor(ambient_colour)
        self.render.setLight(self.render.attachNewNode(ambient_light))

        directional_light = DirectionalLight("directionalLight")
        # direction = Vec3(0, -10, -10)
        # directional_light.setDirection(direction)
        directional_colour = Vec4(0.8, 0.8, 0.5, 1)
        directional_light.setColor(directional_colour)

        # directional_specular = Vec4(1, 1, 1, 1)
        # directional_light.setSpecularColor(directional_specular)

        dir_light_np = self.render.attachNewNode(directional_light)
        dir_light_np.setPos(0, 0, 260)
        dir_light_np.lookAt(self.player)
        self.render.setLight(dir_light_np)

        # Water
        self.water = self.loader.loadModel("models/square")
        self.water.setSx(self.world_size*2)
        self.water.setSy(self.world_size*2)
        self.water.setPos(self.world_size/2, self.world_size/2, 25)   # z is sea level
        self.water.setTransparency(TransparencyAttrib.MAlpha)
        newTS = TextureStage("1")
        self.water.setTexture(newTS, self.loader.loadTexture("models/water.png"))
        self.water.setTexScale(newTS, 4)
        self.water.reparentTo(self.render)
        LerpTexOffsetInterval(self.water, 200, (1,0), (0,0), textureStage=newTS).loop()

    def setupCollisions(self):
        self.coll_trav = CollisionTraverser()

        self.player_ground_sphere = CollisionSphere(0, 1.5, -1.5, 1.5)
        self.player_ground_col = CollisionNode('playerSphere')
        self.player_ground_col.addSolid(self.player_ground_sphere)

        # bitmasks
        self.player_ground_col.setFromCollideMask(BitMask32.bit(0))
        self.player_ground_col.setIntoCollideMask(BitMask32.allOff())
        self.world.setCollideMask(BitMask32.bit(0))
        self.water.setCollideMask(BitMask32.bit(0))

        # and done
        self.player_ground_col_np = self.player.attachNewNode(self.player_ground_col)
        self.player_ground_handler = CollisionHandlerQueue()
        self.coll_trav.addCollider(self.player_ground_col_np, self.player_ground_handler)

        # DEBUG
        if self.debug:
            self.player_ground_col_np.show()
            self.coll_trav.showCollisions(self.render)
Beispiel #8
0
class MousePicker( p3d.Object ):
    """
    Class to represent a ray fired from the input camera lens using the mouse.
    """

    def __init__( self, name, camera=None, rootNp=None, fromCollideMask=None, pickTag=None, gizmos=None ):
        p3d.Object.__init__( self, name, camera, rootNp )
        self.fromCollideMask = fromCollideMask
        self.pickTag         = pickTag
        self.selection       = set([])
        self.node            = None
        self.np              = None
        self.collEntry       = None
        self.gizmos          = gizmos
        assert self.gizmos is not None
        # Create a marquee
        self.marquee = marquee.Marquee( '%sMarquee' % self.name )
        # Create collision ray
        self.pickerRay   = CollisionRay()
        # Create collision node
        pickerNode = CollisionNode( self.name )
        pickerNode.addSolid( self.pickerRay )
        pickerNode.setFromCollideMask( self.fromCollideMask )
        self.pickerNp = camera.attachNewNode( pickerNode )
        #pickerNp.setCollideMask(AXIS_COLLISION_MASK)
        self.collHandler = CollisionHandlerQueue()
        self.collTrav = CollisionTraverser()
        self.collTrav.showCollisions( render )
        self.collTrav.addCollider( self.pickerNp, self.collHandler )
        # Bind mouse button events
        eventNames = ['mouse1', 'control-mouse1', 'mouse1-up']
        for eventName in eventNames:
            self.accept( eventName, self.FireEvent, [eventName] )
        #==
        self.selectionCol = None

    def FireEvent( self, event ):
        # Send a message containing the node name and the event name, including
        # the collision entry as arguments
        print "FireEvent", event, self.node
        if self.node is not None:
            print self.np, self.np.getName()
            messenger.send( '%s-%s' % ( self.node.getName(), event ), [self.collEntry] )
        elif event in ('mouse1', 'control-mouse1'):
            self.StartSelection()
        elif event == 'mouse1-up':
            if self.marquee.started:
                self.StopSelection()

    def UpdateTask( self, task ):
        #self.collTrav.traverse( self.rootNp ) # Traverse the hierarchy and find collisions
        self.collTrav.traverse(render) # Traverse the hierarchy and find collisions
        if self.collHandler.getNumEntries():  # If we have hit something,
            self.collHandler.sortEntries()    # sort the hits so that the closest is first
            collEntry = self.collHandler.getEntry( 0 )
        else:
            collEntry = None
        self.set_node( collEntry)
        # updating the pickerRay
        if base.mouseWatcherNode.hasMouse():
            mp = base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens( self.camera.node(), mp.getX(), mp.getY() )
        return task.cont
    
    def set_node(self, collEntry):
        #==
        if collEntry : new_node = collEntry.getIntoNode()
        else         : new_node = None
        #==
        if new_node == self.node :
            # ultra triky bit, even if the node is th same
            # the collision is not and it is used for the picking later on
            if collEntry : self.collEntry = collEntry 
            return
        #==
        if self.node is not None:
            messenger.send( '%s-mouse-leave' % self.node.getName())
            self.np.setColorScale( Vec4(1) )
            self.node = None
        #==
        if new_node is not None:
            self.collEntry = collEntry
            self.node      = new_node
            #==
            self.np = self.collEntry.getIntoNodePath().getParent()
            self.np.setColorScale( Vec4(1, 0, 0, 1) )
            print self.np , self.np.getName()
            messenger.send( '%s-mouse-enter' %self.node.getName(), [collEntry] )
            messenger.send( '%s-mouse-over'  %self.node.getName(), [collEntry] )

    def StartSelection( self, clearSelection=True ):
        print "StartSelection"
        # Reset selected node colours
        if self.selectionCol:
            self.selectionCol.replace_nodes([])
        #for i in self.selection:
            #i.setColorScale( Vec4(1) )
        self.marquee.Start()
        #==
        if clearSelection:
            self.selection = set([])

    def StopSelection( self ):
        print "StopSelection"
        # Stop the marquee
        self.marquee.Stop()
        nodes = set([])
        for node in self.rootNp.findAllMatches( '**' ):
            if self.marquee.IsPoint3Inside( self.camera, self.rootNp, node.getPos() ):
                #if self.pickTag is None or node.getTag( self.pickTag ):
                if node.getPythonTag('mesh_view'):
                    nodes.add( node )
        # Add any node which was under the mouse to the selection
        if self.collHandler.getNumEntries():
            collEntry = self.collHandler.getEntry( 0 )
            node = collEntry.getIntoNodePath().getParent()
            if node.getPythonTag('mesh_view'):
                nodes.add( node )
            #nodes.add( node )
        self.selection = nodes
        #==
        if self.selectionCol:
            self.selectionCol.replace_nodes(nodes)
        #for i in self.selection:
            #i.setColorScale( Vec4(1, 0, 0, 1) )
        #==
        self.gizmos.AttachNodePaths( self.selection )
        if self.gizmos.active is not None:
            # Refresh the active gizmo so it appears in the right place
            self.gizmos.active.Refresh()
Beispiel #9
0
class ArcadeFlightGame(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.debug = False
        self.maxdistance = 400
        self.statusLabel = self.makeStatusLabel(0)
        self.collisionLabel = self.makeStatusLabel(1)

        self.player = AlliedFlanker(self.loader, self.render, self.taskMgr)
        self.world = GameWorld(1024, self.loader, self.render, self.camera)

        self.taskMgr.add(self.updateTask, "update")
        self.keyboardSetup()

        # performance and map to player so can't fly beyond visible terrain
        self.player.setMaxHeight(self.maxdistance)

        if self.debug == False:
            self.camLens.setFar(self.maxdistance)
        else:
            base.oobe()

        self.camLens.setFov(60)
        self.setupCollisions()
        self.textCounter = 0

    def makeStatusLabel(self, i):
        """ Create a status label at the top-left of the screen,
        Parameter 'i' is the row number """
        return OnscreenText(style=2, fg=(.5,1,.5,1), pos=(-1.3,0.92-(.08 * i)), \
                               align=TextNode.ALeft, scale = .08, mayChange = 1)

    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 setKey(self, key, value):
        """ Used by keyboard setup """
        self.keyMap[key] = value

    def setupCollisions(self):
        self.collTrav = CollisionTraverser()

        # rapid collisions detected using below plus FLUID pos
        self.collTrav.setRespectPrevTransform(True)

        self.playerGroundSphere = CollisionSphere(0, 1.5, -1.5, 1.5)
        self.playerGroundCol = CollisionNode('playerSphere')
        self.playerGroundCol.addSolid(self.playerGroundSphere)

        # bitmasks
        self.playerGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.playerGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.world.setGroundMask(BitMask32.bit(0))
        self.world.setWaterMask(BitMask32.bit(0))

        # and done
        self.playerGroundColNp = self.player.attach(self.playerGroundCol)
        self.playerGroundHandler = CollisionHandlerQueue()
        self.collTrav.addCollider(self.playerGroundColNp,
                                  self.playerGroundHandler)

        # DEBUG as per video:
        if (self.debug == True):
            self.playerGroundColNp.show()
            self.collTrav.showCollisions(self.render)

    def updateTask(self, task):
        """ Gets added to the task manager, updates the player, deals with inputs,
        collisions, game logic etc. """
        self.player.calculate()
        self.actionInput()
        validMove = self.player.move(self.world.getSize())

        # lets not be doing this every frame...
        if validMove == False 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
        self.updateCamera()

        self.collTrav.traverse(self.render)
        for i in range(self.playerGroundHandler.getNumEntries()):
            entry = self.playerGroundHandler.getEntry(i)
            if (self.debug == True):
                self.collisionLabel.setText("DEAD:" +
                                            str(globalClock.getFrameTime()))
            self.player.die()
        return Task.cont

    def actionInput(self):
        """ Used by updateTask to process keyboard input """
        if (self.keyMap["climb"] != 0):
            self.player.climb()
        elif (self.keyMap["fall"] != 0):
            self.player.dive()
        else:
            self.player.unwindVertical()

        if (self.keyMap["left"] != 0):
            self.player.bankLeft()
        elif (self.keyMap["right"] != 0):
            self.player.bankRight()
        else:
            self.player.unwindHorizontal()

        if (self.keyMap["accelerate"] != 0):
            self.player.accelerate()
        elif (self.keyMap["decelerate"] != 0):
            self.player.brake()

    def updateCamera(self):
        self.player.lookAtMe(self.camera)