예제 #1
0
class Mouse(object):
    def __init__(self, base):
        self.base = base
        if settings.mouse_over:
            taskMgr.add(self.mouse_task, 'mouse-task')
        self.picker = CollisionTraverser()
        self.pq = CollisionHandlerQueue()
        self.pickerNode = CollisionNode('mouseRay')
        self.pickerNP = self.base.cam.attachNewNode(self.pickerNode)
        self.pickerNode.setFromCollideMask(
            CollisionNode.getDefaultCollideMask()
            | GeomNode.getDefaultCollideMask())
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        self.picker.addCollider(self.pickerNP, self.pq)
        #self.picker.showCollisions(render)
        self.over = None

    def find_over(self):
        over = None
        if self.base.mouseWatcherNode.hasMouse():
            mpos = self.base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens(self.base.camNode, mpos.getX(),
                                       mpos.getY())
            self.picker.traverse(render)
            if self.pq.getNumEntries() > 0:
                self.pq.sortEntries()
                np = self.pq.getEntry(0).getIntoNodePath().findNetPythonTag(
                    'owner')
                owner = np.getPythonTag('owner')
                over = owner
                np = self.pq.getEntry(0).getIntoNodePath().findNetPythonTag(
                    'patch')
                if np is not None:
                    self.patch = np.getPythonTag('patch')
                else:
                    self.patch = None
        return over

    def get_over(self):
        if settings.mouse_over:
            over = self.over
        else:
            over = self.find_over()
        return over

    def mouse_task(self, task):
        if self.mouseWatcherNode.hasMouse():
            self.over = self.find_over()
        return Task.cont
예제 #2
0
class Boule_feu(Arme):
    def __init__(self, parent):
        Arme.__init__(self, parent)
        # init du rayon de la mort
        self.ray = CollisionRay(0, 0, 0, 0, 1, 0)
        rayNode = CollisionNode("boule_feu")
        rayNode.addSolid(self.ray)
        mask = BitMask32()
        mask.setBit(2)
        rayNode.setFromCollideMask(mask)
        maskI = BitMask32()
        maskI.setBit(0)
        rayNode.setIntoCollideMask(maskI)
        self.rayNodePath = render.attachNewNode(rayNode)
        self.rayQueue = CollisionHandlerQueue()
        self.parent.base.cTrav.addCollider(self.rayNodePath, self.rayQueue)
        self.ray.setOrigin(12, 9, 7)
        self.ray.setDirection(self.parent.heros.actor.getPos() -
                              self.parent.sorcier.obj.getPos())
        self.rayNodePath.show()

    def update(self, keys, dt):
        self.ray.setDirection(self.parent.heros.actor.getPos() -
                              self.parent.sorcier.obj.getPos())
        if self.rayQueue.getNumEntries() > 0:
            self.rayQueue.sortEntries()
            rayHit = self.rayQueue.getEntry(0)
            hitPos = rayHit.getSurfacePoint(render)
            hitNodePath = rayHit.getIntoNodePath()
            print(hitNodePath)
예제 #3
0
class DPlayer(DistributedObject):
    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.name = "Player"
        self.piece = None

        self.pickerQueue = CollisionHandlerQueue()
        self.pickerRay = CollisionRay()
        pickerNode = CollisionNode('mouseRay')
        pickerNode.setFromCollideMask(BitMask32(0x80))
        pickerNode.addSolid(self.pickerRay)
        self.pickerNP = base.camera.attachNewNode(pickerNode)
        base.cTrav.addCollider(self.pickerNP, self.pickerQueue)

        self.accept("mouse1", self.checkClick)

    def delete(self):
        """Cleanup just before the object gets deleted"""
        self.ignoreAll()
        base.cTrav.removeCollider(self.pickerNP)
        self.pickerNP.removeNode()

        if self.piece is not None:
            self.piece.sendDeleteMsg()

        DistributedObject.delete(self)

    def d_getName(self):
        self.sendUpdate("requestName")

    def setName(self, newName):
        self.name = newName
        base.messenger.send(self.cr.uniqueName("setPlayerName"), [self.name])

    def setPiece(self, piece):
        self.piece = piece

    def checkClick(self):
        """Check if the player has clicked on a field and send a request to move
        to it to the server."""
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens(base.camNode, mpos.x, mpos.y)

            base.cTrav.traverse(render)
            if self.pickerQueue.getNumEntries() > 0:
                self.pickerQueue.sortEntries()
                pickedObj = self.pickerQueue.getEntry(0).getIntoNodePath()
                fieldName = pickedObj.getParent().getName()
                base.messenger.send("requestMoveToField", [fieldName])

    def d_updateInventory(self):
        self.sendUpdate("updateInventory")

    def doUpdateInventory(self, level, inventoryDir):
        base.messenger.send("updateInventory", [level, inventoryDir])

    def doUpdatePotions(self, numPotions):
        base.messenger.send("updateHealthPotions", [numPotions])
예제 #4
0
class Tree(object):
    def __init__(self, app, pos, level, index):
        self.hp = 200 * level
        self.app = app

        self.np = app.render.attachNewNode("tree%d" % index)
        self.np.setPos(pos)

        self.level = level
        self.pursuers = []

        self.model = app.loader.loadModel('models/tree1')
        tex = app.loader.loadTexture("textures/"+'tree1'+".jpg") #Load the texture
        tex.setWrapU(Texture.WMClamp)                    # default is repeat, which will give
        tex.setWrapV(Texture.WMClamp)                    # artifacts at the edges
        self.model.setTexture(tex, 1)                           #Set the texture
        self.model.reparentTo(self.np)

        self.model.setHpr(uniform(-180,180),0,0)
        self.model.setScale(2)

        self.cn = self.np.attachNewNode(CollisionNode('tree_c_%d' % index))
        self.cs = CollisionSphere(0,0.0,0.0,6)
        self.cn.node().addSolid(self.cs)

        self.cn.node().setFromCollideMask(BitMask32(0x01))
        self.cn.node().setIntoCollideMask(BitMask32(0x00))

        self.cqueue = CollisionHandlerQueue()
        app.cTrav.addCollider(self.cn, self.cqueue)

    def update(self, timer):
        for i in range(self.cqueue.getNumEntries()):
            collided_name = self.cqueue.getEntry(i).getIntoNodePath().getName()
            #enemy collision
            if collided_name[0] == 'e':
                self.app.enemy_manager.handle_collision(collided_name, self, timer)
                # drop loot when killed by panda
                if self.hp < 0:
                    self.app.item_manager.add_item(self.np.getPos(), "upgrade", self.level)

            #hit by bullet    
            if collided_name[0] == 'b':    
                if self.hp < 0:
                    bullet = self.app.bullet_manager.get_bullet(collided_name)
                    bullet.apply_effect(self)
                    self.app.bullet_manager.remove_bullet(collided_name)

        # tree is dead
        if self.hp < 0:
            for p in self.pursuers:
                p.ai_b.pursue(self.app.player.np)

            self.app.scene.remove(self)
            self.np.detachNode()
예제 #5
0
class Mouse(DirectObject):
    def __init__(self, levelNP):
        self.setCursor()
        # store the nodepath to the level collisions
        # will be used to check for intersections with the mouse ray
        self.levelNP = levelNP
        # Setup a traverser for the picking collisions
        self.picker = CollisionTraverser()
        # Setup mouse ray
        self.pq = CollisionHandlerQueue()
        # Create a collision Node
        pickerNode = CollisionNode('MouseRay')
        # set the nodes collision bitmask
        pickerNode.setFromCollideMask(BitMask32.bit(1))#GeomNode.getDefaultCollideMask())
        # create a collision ray
        self.pickerRay = CollisionRay()
        # add the ray as a solid to the picker node
        pickerNode.addSolid(self.pickerRay)
        # create a nodepath with the camera to the picker node
        self.pickerNP = base.camera.attachNewNode(pickerNode)
        # add the nodepath to the base traverser
        self.picker.addCollider(self.pickerNP, self.pq)

    def setCursor(self):
        base.win.clearRejectedProperties()
        props = WindowProperties()
        if sys.platform.startswith('linux'):
            props.setCursorFilename("./assets/cursor.x11")
        else:
            props.setCursorFilename("./assets/cursor.ico")
        base.win.requestProperties(props)

    def getMousePos(self):
        # check if we have a mouse on the window
        if base.mouseWatcherNode.hasMouse():
            # get the mouse position on the screen
            mpos = base.mouseWatcherNode.getMouse()
            # set the ray's position
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            # Now call the traverse function to let the traverser check for collisions
            # with the added colliders and the levelNP
            self.picker.traverse(self.levelNP)
            # check if we have a collision
            if self.pq.getNumEntries() > 0:
                # sort the entries to get the closest first
                self.pq.sortEntries()
                # This is the point at where the mouse ray and the level plane intersect
                hitPos = self.pq.getEntry(0).getSurfacePoint(render)
                return hitPos
        return Point3(0, 0, 0)

        task.cont
예제 #6
0
 def get_dist_to_cell(self, pos):
     """Given a position, return the distance to the nearest cell
     below that position. If no cell is found, returns None."""
     self.ray.setOrigin(pos)
     queue = CollisionHandlerQueue()
     self.traverser.addCollider(self.ray_nodepath, queue)
     self.traverser.traverse(self.cell_picker_world)
     self.traverser.removeCollider(self.ray_nodepath)
     queue.sortEntries()
     if not queue.getNumEntries():
         return None
     entry = queue.getEntry(0)
     return (entry.getSurfacePoint(self.cell_picker_world) - pos).length()
 def get_dist_to_cell(self, pos):
     """Given a position, return the distance to the nearest cell
     below that position. If no cell is found, returns None."""
     self.ray.setOrigin(pos)
     queue = CollisionHandlerQueue()
     self.traverser.addCollider(self.ray_nodepath, queue)
     self.traverser.traverse(self.cell_picker_world)
     self.traverser.removeCollider(self.ray_nodepath)
     queue.sortEntries()
     if not queue.getNumEntries():
         return None
     entry = queue.getEntry(0)
     return (entry.getSurfacePoint(self.cell_picker_world) - pos).length()
 def get_cell(self, pos):
     """Given a position, return the nearest cell below that position.
     If no cell is found, returns None."""
     self.ray.setOrigin(pos)
     queue = CollisionHandlerQueue()
     self.traverser.addCollider(self.ray_nodepath, queue)
     self.traverser.traverse(self.cell_picker_world)
     self.traverser.removeCollider(self.ray_nodepath)
     queue.sortEntries()
     if not queue.getNumEntries():
         return None
     entry = queue.getEntry(0)
     cnode = entry.getIntoNode()
     try:
         return self.cells_by_collider[cnode]
     except KeyError:
         raise Warning('collision ray collided with something '
                       'other than a cell: %s' % cnode)
예제 #9
0
 def get_cell(self, pos):
     """Given a position, return the nearest cell below that position.
     If no cell is found, returns None."""
     self.ray.setOrigin(pos)
     queue = CollisionHandlerQueue()
     self.traverser.addCollider(self.ray_nodepath, queue)
     self.traverser.traverse(self.cell_picker_world)
     self.traverser.removeCollider(self.ray_nodepath)
     queue.sortEntries()
     if not queue.getNumEntries():
         return None
     entry = queue.getEntry(0)
     cnode = entry.getIntoNode()
     try:
         return self.cells_by_collider[cnode]
     except KeyError:
         raise Warning('collision ray collided with something '
                       'other than a cell: %s' % cnode)
예제 #10
0
class Colisiones:
    def __init__(self, energy, jeep):

        self.bebidas = 0
        self.energy = energy
        self.crash = []
        self.jeep = jeep
        """  ---------------------- Prepara las Colisiones ---------------------- """

        self.cs = CollisionSphere(0, 0, 0, 20)
        cont = 0
        while (cont < 80):
            self.crash.append(self.energy[cont].attachNewNode(
                CollisionNode(str(cont))))
            self.crash[cont].node().addSolid(self.cs)
            #self.crash[cont].show() Uncomment this line to see the colisions
            cont = cont + 1

        self.css = CollisionSphere(0, 0, 0, 12)
        self.cnodePath = self.jeep.attachNewNode(CollisionNode('cnode'))
        self.cnodePath.node().addSolid(self.css)

        #self.cnodePath.show() Uncomment this line to see the colisions

        self.traverser = CollisionTraverser()
        self.queue = CollisionHandlerQueue()
        """ --------------------------------------------------------------------- """

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

    def choque(self, task):

        self.traverser.addCollider(self.cnodePath, self.queue)
        self.traverser.traverse(render)
        for i in range(self.queue.getNumEntries()):
            entry = self.queue.getEntry(i)
            self.energy[int(entry.getIntoNode().getName())].setPos(0, 0, 5000)
            self.bebidas = self.bebidas + 1
            global texta
            texta.destroy()
            texta = addText(
                0.9, -1.2,
                "Hasta Ahora LLevamos " + str(self.bebidas) + " Bebidas", 0.07)
        return Task.cont
예제 #11
0
class Colisiones:

    def __init__(self, energy, jeep):

        self.bebidas = 0
        self.energy = energy
        self.crash = []
        self.jeep = jeep

        """  ---------------------- Prepara las Colisiones ---------------------- """
        
        self.cs = CollisionSphere(0, 0, 0, 20)
        cont = 0
        while( cont < 80 ):
            self.crash.append( self.energy[cont].attachNewNode(CollisionNode(str(cont))) )
            self.crash[cont].node().addSolid(self.cs)
            #self.crash[cont].show() Uncomment this line to see the colisions
            cont = cont + 1

        self.css = CollisionSphere(0, 0, 0, 12)
        self.cnodePath = self.jeep.attachNewNode(CollisionNode('cnode'))
        self.cnodePath.node().addSolid(self.css)

        #self.cnodePath.show() Uncomment this line to see the colisions

        self.traverser = CollisionTraverser()
        self.queue = CollisionHandlerQueue()
        
        """ --------------------------------------------------------------------- """

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

    def choque(self, task):
        
        self.traverser.addCollider(self.cnodePath, self.queue)
        self.traverser.traverse(render)
        for i in range(self.queue.getNumEntries()):
            entry = self.queue.getEntry(i)
            self.energy[int( entry.getIntoNode().getName() )].setPos(0,0,5000)
            self.bebidas = self.bebidas + 1
            global texta
            texta.destroy()
            texta = addText( 0.9, -1.2,  "Hasta Ahora LLevamos " + str(self.bebidas) + " Bebidas", 0.07 )
        return Task.cont
예제 #12
0
 def __endFireWater(self):
     if self.aimStart == None:
         return
     if not self.state == 'Controlled':
         return
     if not self.avId == localAvatar.doId:
         return
     taskMgr.remove(self.waterPowerTaskName)
     messenger.send('wakeup')
     self.aimStart = None
     origin = self.nozzle.getPos(render)
     target = self.boss.getPos(render)
     angle = deg2Rad(self.waterPitcherNode.getH() + 90)
     x = math.cos(angle)
     y = math.sin(angle)
     fireVector = Point3(x, y, 0)
     if self.power < 0.001:
         self.power = 0.001
     self.lastPowerFired = self.power
     fireVector *= self.fireLength * self.power
     target = origin + fireVector
     segment = CollisionSegment(origin[0], origin[1], origin[2], target[0],
                                target[1], target[2])
     fromObject = render.attachNewNode(CollisionNode('pitcherColNode'))
     fromObject.node().addSolid(segment)
     fromObject.node().setFromCollideMask(ToontownGlobals.PieBitmask
                                          | ToontownGlobals.CameraBitmask
                                          | ToontownGlobals.FloorBitmask)
     fromObject.node().setIntoCollideMask(BitMask32.allOff())
     queue = CollisionHandlerQueue()
     base.cTrav.addCollider(fromObject, queue)
     base.cTrav.traverse(render)
     queue.sortEntries()
     self.hitObject = None
     if queue.getNumEntries():
         entry = queue.getEntry(0)
         target = entry.getSurfacePoint(render)
         self.hitObject = entry.getIntoNodePath()
     base.cTrav.removeCollider(fromObject)
     fromObject.removeNode()
     self.d_firingWater(origin, target)
     self.fireWater(origin, target)
     self.resetPowerBar()
     return
예제 #13
0
class Walker():
    def __init__(self):

        colliderNode = CollisionNode(self.colliderName + "WallCollider")
        colliderNode.addSolid(CollisionSphere(0, 0, 0, 0.3))
        self.collider = self.root.attachNewNode(colliderNode)
        self.collider.setPythonTag(TAG_OWNER, self)
        colliderNode.setFromCollideMask(MASK_WALLS)
        colliderNode.setIntoCollideMask(0)

        self.collider.setZ(self.height * 0.5)

        base.pusher.addCollider(self.collider, self.root)
        base.traverser.addCollider(self.collider, base.pusher)

        self.ray = CollisionRay(0, 0, self.height / 2, 0, 0, -1)

        rayNode = CollisionNode(self.colliderName + "Ray")
        rayNode.addSolid(self.ray)

        rayNode.setFromCollideMask(MASK_FLOORS)
        rayNode.setIntoCollideMask(0)

        self.rayNodePath = self.root.attachNewNode(rayNode)
        self.rayQueue = CollisionHandlerQueue()

        base.traverser.addCollider(self.rayNodePath, self.rayQueue)

    def update(self, dt):
        if self.rayQueue.getNumEntries() > 0:
            self.rayQueue.sortEntries()
            rayHit = self.rayQueue.getEntry(0)
            hitPos = rayHit.getSurfacePoint(render)
            self.root.setZ(hitPos.z)

    def cleanup(self):
        if self.collider is not None and not self.collider.isEmpty():
            self.collider.clearPythonTag(TAG_OWNER)
            base.traverser.removeCollider(self.collider)
            base.pusher.removeCollider(self.collider)

        base.traverser.removeCollider(self.rayNodePath)
예제 #14
0
파일: mouse.py 프로젝트: keeeal/tracks
class MouseHandler:
    def __init__(self, camera, level):
        self.camera = camera
        self.level = level
        self.handler = CollisionHandlerQueue()
        self.traverser = CollisionTraverser('traverser')
        pickerNode = CollisionNode('mouseRay')
        pickerNP = self.camera.attachNewNode(pickerNode)
        pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.pickerRay = CollisionRay()
        pickerNode.addSolid(self.pickerRay)
        self.traverser.addCollider(pickerNP, self.handler)

    def pick_node(self, mpos):
        self.pickerRay.setFromLens(self.camera.getChild(0).node(), mpos.getX(), mpos.getY())
        self.traverser.traverse(self.level)

        if self.handler.getNumEntries() > 0:
            self.handler.sortEntries()
            node = self.handler.getEntry(0).getIntoNodePath()
            if not node.isEmpty():
                return node
예제 #15
0
class World(DirectObject):
    def __init__(self):

        self.startvar = 0
        self.startdialog = YesNoDialog(dialogName="START GAME",
                                       text="START GAME",
                                       command=self.endbox)
        self.timepass = model()
        self.timepass1 = model1()
        self.keyMap = {"left": 0, "right": 0, "forward": 0, "backward": 0}
        base.win.setClearColor(Vec4(0, 0, 0, 1))

        # number of collectibles
        self.numObjects = 0

        #music
        self.backmusic = base.loader.loadSfx("sounds/tales.mp3")
        self.backmusic.setLoop(True)
        self.backmusic.setVolume(0.2)
        self.backmusic.play()

        self.skatemusic = base.loader.loadSfx("sounds/skate.mp3")
        self.skatemusic.setVolume(.65)
        self.skatemusic.setLoop(True)

        self.bombmusic = base.loader.loadSfx("sounds/bomb.mp3")
        self.bombmusic.setVolume(.85)

        self.springmusic = base.loader.loadSfx("sounds/spring.mp3")
        self.springmusic.setVolume(.65)
        self.springmusic.setLoop(True)

        self.colmusic = base.loader.loadSfx("sounds/collect.mp3")
        self.colmusic.setVolume(.65)

        # print the number of objects
        printNumObj(self.numObjects)

        # Post the instructions
        # self.title = addTitle("Roaming Ralph (Edited by Adam Gressen)")
        # self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        # self.inst2 = addInstructions(0.90, "[A]: Rotate Ralph Left")
        # self.inst3 = addInstructions(0.85, "[D]: Rotate Ralph Right")
        # self.inst4 = addInstructions(0.80, "[W]: Run Ralph Forward")
        # self.inst5 = addInstructions(0.75, "[S]: Run Ralph Backward")
        # self.inst6 = addInstructions(0.70, "[Space]: Run, Ralph, Run")

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)
        self.environ.setPos(0, 0, 0)

        # Timer to increment in the move task
        self.time = 0

        # Get bounds of environment
        min, max = self.environ.getTightBounds()
        self.mapSize = max - min

        # Create the main character, Ralph
        self.ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor(
            "models/ralph", {
                "run": "models/ralph-run",
                "jump": "models/ralph-jump",
                "walk": "models/ralph-walk"
            })
        self.ralph.reparentTo(render)
        self.ralph.setScale(.30)
        self.ralph.setPos(self.ralphStartPos)
        #skate
        self.skate = loader.loadModel("models/Skateboard")
        self.skate.reparentTo(render)
        self.skate.setScale(.02)
        self.skate.setPos(-random.randint(38, 50), -random.randint(15, 37),
                          -0.015)
        # ralph's health
        self.health = 100

        #spring
        self.spring = loader.loadModel("models/spring")
        self.spring.reparentTo(render)
        self.spring.setScale(.8)
        self.spring.setPos(-random.randint(72, 78), -random.randint(10, 15),
                           6.715)
        # ralph's stamina
        self.stamina = 100

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation
        self.accept("escape", sys.exit)

        # these don't work well in combination with the space bar
        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("arrow_up", self.setKey, ["forward", 1])
        self.accept("arrow_down", self.setKey, ["backward", 1])
        self.accept("arrow_left-up", self.setKey, ["left", 0])
        self.accept("arrow_right-up", self.setKey, ["right", 0])
        self.accept("arrow_up-up", self.setKey, ["forward", 0])
        self.accept("arrow_down-up", self.setKey, ["backward", 0])

        self.accept("a", self.setKey, ["left", 1])
        self.accept("d", self.setKey, ["right", 1])
        self.accept("w", self.setKey, ["forward", 1])
        self.accept("s", self.setKey, ["backward", 1])
        self.accept("a-up", self.setKey, ["left", 0])
        self.accept("d-up", self.setKey, ["right", 0])
        self.accept("w-up", self.setKey, ["forward", 0])
        self.accept("s-up", self.setKey, ["backward", 0])

        # Game state variables
        self.isMoving = False
        self.isRunning = False
        self.onboard = 0
        self.boardtime = 0
        self.onspring = 0
        self.isjumping = False
        # Set up the camera
        base.disableMouse()
        #base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,2)
        base.camera.setPos(0, 0, 0)
        base.camera.reparentTo(self.ralph)
        base.camera.setPos(0, 40, 2)
        base.camera.lookAt(self.ralph)

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

        base.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 300)
        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()
        base.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        # camera ground collision handler
        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 300)
        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()
        base.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Place the health items
        self.placeHealthItems()

        # Place the collectibles
        self.placeCollectibles()

        # Place the bomb
        self.placebombItems()

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #base.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))
        #print self.startvar

        taskMgr.add(self.move, "moveTask")
        #taskMgr.doMethodLater(0.5, self.healthDec, "healthTask")

    # Display ralph's health
    def displayHealth(self):
        healthBar['scale'] = (self.health * 0.01 * BAR_WIDTH, 0.2, 0.2)

    # Display ralph's stamina
    def displayStamina(self):
        sprintBar['scale'] = (self.stamina * 0.01 * BAR_WIDTH, 0.2, 0.2)

    # Allow ralph to collect the health items
    def collectHealthItems(self, entry):
        # refill ralph's health
        self.colmusic.play()
        if (self.health < 100):
            self.health = self.health + 15.5
        # reposition the collectible
        self.placeItem(entry.getIntoNodePath().getParent())

    def collectCollectibles(self, entry):
        # remove the collectible
        #entry.getIntoNodePath().getParent().removeNode()
        self.colmusic.play()
        self.placeItem(entry.getIntoNodePath().getParent())
        # update the number of objects
        self.numObjects += 1
        #self.tot=10-self.numObjects
        printNumObj(self.numObjects)

    def blastbomb(self):
        # remove the collectible
        #self.placeItem(entry.getIntoNodePath().getParent())
        # blast
        self.fire = loader.loadModel("models/fire")
        self.fire.reparentTo(render)
        self.fire.setScale(.01)
        self.fire.setHpr(0, -90, 0)
        self.bombmusic.play()
        self.backmusic.stop()
        self.fire.setPos(self.ralph.getPos())
        self.die()

    # Places an item randomly on the map
    def placeItem(self, item):
        # Add ground collision detector to the health item
        self.collectGroundRay = CollisionRay()
        self.collectGroundRay.setOrigin(0, 0, 300)
        self.collectGroundRay.setDirection(0, 0, -1)
        self.collectGroundCol = CollisionNode('colRay')
        self.collectGroundCol.addSolid(self.collectGroundRay)
        self.collectGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.collectGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.collectGroundColNp = item.attachNewNode(self.collectGroundCol)
        self.collectGroundHandler = CollisionHandlerQueue()
        base.cTrav.addCollider(self.collectGroundColNp,
                               self.collectGroundHandler)

        placed = False
        while placed == False:
            # re-randomize position
            item.setPos(-random.randint(-40, 140), -random.randint(-40, 40), 0)

            base.cTrav.traverse(render)

            # Get Z position from terrain collision
            entries = []
            for j in range(self.collectGroundHandler.getNumEntries()):
                entry = self.collectGroundHandler.getEntry(j)
                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"):
                item.setZ(entries[0].getSurfacePoint(render).getZ() + 1)
                placed = True

        # remove placement collider
        self.collectGroundColNp.removeNode()

    def placeHealthItems(self):
        self.placeholder = render.attachNewNode("HealthItem-Placeholder")
        self.placeholder.setPos(0, 0, 0)

        # Add the health items to the placeholder node
        for i in range(5):
            # Load in the health item model
            self.healthy = loader.loadModel("models/sphere")
            self.healthy.setPos(0, 0, 0)
            self.healthy.setScale(.4)
            self.healthy.reparentTo(self.placeholder)

            self.placeItem(self.healthy)

            # Add spherical collision detection
            healthSphere = CollisionSphere(0, 0, 0, 1.4)
            sphereNode = CollisionNode('healthSphere')
            sphereNode.addSolid(healthSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.healthy.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)

#bomb

    def placebombItems(self):
        self.placebomb = render.attachNewNode("bomb-Placeholder")
        self.placebomb.setPos(0, 0, 0)

        # Add the bomb items to the placeholder node
        for i in range(30):
            # Load in the health item model
            self.bomby = loader.loadModel("models/bomb")
            self.bomby.setPos(0, 0, 0)
            self.bomby.setScale(.4)
            self.bomby.reparentTo(self.placebomb)

            self.placeItem(self.bomby)

            # Add spherical collision detection
            bombSphere = CollisionSphere(0, 0, 0, 1.4)
            sphereNode = CollisionNode('bombSphere')
            sphereNode.addSolid(bombSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.bomby.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)

#blue

    def placeCollectibles(self):
        self.placeCol = render.attachNewNode("Collectible-Placeholder")
        self.placeCol.setPos(0, 0, 0)

        # Add the health items to the placeCol node
        for i in range(50):
            # Load in the health item model
            self.collect = loader.loadModel("models/jack")
            self.collect.setPos(0, 0, 0)
            self.collect.setScale(.4)
            self.collect.reparentTo(self.placeCol)

            self.placeItem(self.collect)

            # Add spherical collision detection
            colSphere = CollisionSphere(0, 0, 0, 1.4)
            sphereNode = CollisionNode('colSphere')
            sphereNode.addSolid(colSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.collect.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)

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

    # Makes ralph's health decrease over time

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):
        #print self.ralph.getPos()
        self.time += globalClock.getDt()
        timeText['text'] = str(self.time)

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.
        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.
        # and rotate the camera to remain behind ralph
        if (self.keyMap["left"] != 0) and (self.onboard == 0):
            self.ralph.setH(self.ralph.getH() + 100 * globalClock.getDt())
        if (self.keyMap["right"] != 0) and (self.onboard == 0):
            self.ralph.setH(self.ralph.getH() - 100 * globalClock.getDt())
        if (self.keyMap["forward"] != 0) and (self.onboard == 0):
            self.ralph.setY(self.ralph, -45 * globalClock.getDt())
        if (self.keyMap["backward"] != 0) and (self.onboard == 0):
            self.ralph.setY(self.ralph, 45 * globalClock.getDt())
        if (self.keyMap["forward"] != 0) and (self.onboard
                                              == 0) and (self.onspring > 0):
            self.ralph.setY(self.ralph, -65 * globalClock.getDt())
        if (self.keyMap["backward"] != 0) and (self.onboard
                                               == 0) and (self.onspring > 0):
            self.ralph.setY(self.ralph, +65 * globalClock.getDt())

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.
        if (self.isMoving):
            if (self.health <= 0):
                self.ralph.setPos(10000, 10000, 1000)
                self.ralph.stop()
                self.blastbomb()
            else:
                self.health -= .07

        if ((self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0) or
            (self.keyMap["right"] != 0) or
            (self.keyMap["backward"] != 0)) and (self.onboard == 0):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving and (self.onspring == 0):
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False
#skate
        if (math.fabs(self.skate.getX() - self.ralph.getX()) <
                2) and (math.fabs(self.skate.getY() - self.ralph.getY()) <
                        5) and (self.onspring == 0) and (self.onboard == 0):
            self.onboard = 1
            self.ralph.stop()
            self.ralph.pose("walk", 5)
            self.isMoving = False
            self.isjumping = False
            self.skatemusic.play()

        if (self.onboard == 1):
            if (self.keyMap["left"] != 0):
                self.ralph.setH(self.ralph.getH() + 60 * globalClock.getDt())
                self.skate.setH(self.ralph.getH())
            if (self.keyMap["right"] != 0):
                self.ralph.setH(self.ralph.getH() - 60 * globalClock.getDt())
                self.skate.setH(self.ralph.getH())
            if (self.keyMap["forward"] != 0):
                self.ralph.setY(self.ralph, -100 * globalClock.getDt())
                self.skate.setY(self.ralph.getY())
                self.skate.setZ(self.ralph.getZ())
                self.skate.setX(self.ralph.getX())
            if (self.keyMap["backward"] != 0):
                self.ralph.setY(self.ralph, 100 * globalClock.getDt())
                self.skate.setY(self.ralph.getY())
                self.skate.setZ(self.ralph.getZ())
                self.skate.setX(self.ralph.getX())
            self.boardtime = self.boardtime + 1
            #self.ralph.stop()
            #self.ralph.pose("walk",5)
            #print self.onboard
            if (self.boardtime == 1000):
                self.onboard = 0
                self.boardtime = 0
                self.skate.setPos(-random.randint(72, 78),
                                  -random.randint(10, 15), 6.715)
                self.skatemusic.stop()
#spring

#spring
        if (math.fabs(self.spring.getX() - self.ralph.getX()) <
                2) and (math.fabs(self.spring.getY() - self.ralph.getY()) <
                        2) and (self.onboard == 0) and (self.onspring == 0):
            self.onspring = 500
            self.springmusic.play()
            self.spring.setPos(-random.randint(38, 50),
                               -random.randint(15, 37), -0.015)

        if (self.onspring > 0):
            self.onspring = self.onspring - 1
            #print self.onspring
            if (self.isjumping is False):
                self.ralph.loop("jump")
                self.isjumping = True
        else:
            #print self.ralph.getX()
            if self.isjumping:
                if ((self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0)
                        or (self.keyMap["right"] != 0)):
                    self.ralph.loop("run")
                    self.isMoving = True
                else:
                    self.ralph.stop()
                    self.ralph.pose("walk", 5)
                self.isjumping = False
                self.onspring = 0
                self.springmusic.stop()

        # so the following line is unnecessary
        base.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())
            #base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+5)
        elif (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                     == "healthSphere"):
            self.collectHealthItems(entries[0])
        elif (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                     == "colSphere"):
            self.collectCollectibles(entries[0])
        elif (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                     == "bombSphere"):
            self.blastbomb()
        else:
            self.ralph.setPos(startpos)

        # Keep the camera above the terrain
        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"):
            modZ = entries[0].getSurfacePoint(render).getZ()
            base.camera.setZ(10.0 + modZ + (modZ - self.ralph.getZ()))

        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        self.displayHealth()

        return task.cont

    #  End
    def die(self):
        # end all running tasks
        self.ralph.setPos(10000, 10000, 10000)
        taskMgr.remove("moveTask")
        taskMgr.remove("healthTask")
        self.ralph.stop()
        self.skatemusic.stop()
        self.springmusic.stop()
        self.backmusic.stop()

        colObj = self.numObjects
        myscore = str(colObj)

        self.highscore = OkDialog(dialogName="highscoreDialog",
                                  text="Your Score: " + myscore,
                                  command=self.endResult)

    # Handle the dialog result

    def endResult(self, arg):
        sys.exit()

    def endbox(self, arg):
        if (arg):
            self.startvar = 1
            self.startdialog.cleanup()
            # restart the game
            #self.restart()
        else:
            sys.exit()
예제 #16
0
class World(DirectObject):
    def __init__(self):
        #This code puts the standard title and instruction text on screen
        self.title = OnscreenText(text="Panda3D: Tutorial - Mouse Picking",
                                  style=1, fg=(1, 1, 1, 1),
                                  pos=(0.8, -0.95), scale=.07)
        self.escapeEvent = OnscreenText(
            text="ESC: Quit",
            style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.95),
            align=TextNode.ALeft, scale=.05)
        self.mouse1Event = OnscreenText(
            text="Left-click and drag: Pick up and drag piece",
            style=1, fg=(1, 1, 1, 1), pos=(-1.3, 0.90),
            align=TextNode.ALeft, scale=.05)

        self.accept('escape', sys.exit)  #Escape quits
        base.disableMouse()  #Disble mouse camera control
        camera.setPosHpr(0, -13.75, 6, 0, -25, 0)  #Set the camera
        self.setupLights()  #Setup default lighting

        #Since we are using collision detection to do picking, we set it up like
        #any other collision detection system with a traverser and a handler
        self.picker = CollisionTraverser()  #Make a traverser
        self.pq = CollisionHandlerQueue()  #Make a handler
        #Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        #Attach that node to the camera since the ray will need to be positioned
        #relative to it
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        #Everything to be picked will use bit 1. This way if we were doing other
        #collision we could seperate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  #Make our ray
        self.pickerNode.addSolid(self.pickerRay)  #Add it to the collision node
        #Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)
        #self.picker.showCollisions(render)

        #Now we create the chess board and its pieces

        #We will attach all of the squares to their own root. This way we can do the
        #collision pass just on the sqaures and save the time of checking the rest
        #of the scene
        self.squareRoot = render.attachNewNode("squareRoot")

        #For each square
        self.squares = [None for i in range(64)]
        self.pieces = dict((i, None) for i in range(64))  #MOD
        for i in range(64):
            #Load, parent, color, and position the model (a single square polygon)
            self.squares[i] = loader.loadModel("models/square")
            self.squares[i].reparentTo(self.squareRoot)
            self.squares[i].setPos(SquarePos(i))
            self.squares[i].setColor(SquareColor(i))
            #Set the model itself to be collideable with the ray. If this model was
            #any more complex than a single polygon, you should set up a collision
            #sphere around it instead. But for single polygons this works fine.
            self.squares[i].find("**/polygon").node().setIntoCollideMask(
                BitMask32.bit(1))
            #Set a tag on the square's node so we can look up what square this is
            #later during the collision pass
            self.squares[i].find("**/polygon").node().setTag('square', str(i))

            #We will use this variable as a pointer to whatever piece is currently
            #in this square

        #The order of pieces on a chessboard from white's perspective. This list
        #contains the constructor functions for the piece classes defined below
        pieceOrder = (Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook)

        for i in range(8, 16):
            #Load the white pawns
            self.pieces[i] = Pawn(i, WHITE)
        for i in range(48, 56):
            #load the black pawns
            self.pieces[i] = Pawn(i, PIECEBLACK)
        for i in range(8):
            #Load the special pieces for the front row and color them white
            self.pieces[i] = pieceOrder[i](i, WHITE)
            #Load the special pieces for the back row and color them black
            self.pieces[i + 56] = pieceOrder[i](i + 56, PIECEBLACK)

        #This will represent the index of the currently highlited square
        self.hiSq = False
        #This wil represent the index of the square where currently dragged piece
        #was grabbed from
        self.dragging = False

        #Start the task that handles the picking
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
        self.accept("mouse1", self.grabPiece)  #left-click grabs a piece
        self.accept("mouse1-up", self.releasePiece)  #releasing places it

    #This function swaps the positions of two pieces
    def swapPieces(self, fr, to):
        temp = self.pieces[fr]
        self.pieces[fr] = self.pieces[to]
        self.pieces[to] = temp
        if self.pieces[fr]:
            self.pieces[fr].square = fr
            self.pieces[fr].obj.setPos(SquarePos(fr))
        if self.pieces[to]:
            self.pieces[to].square = to
            self.pieces[to].obj.setPos(SquarePos(to))

    def mouseTask(self, task):
        #This task deals with the highlighting and dragging based on the mouse

        #First, clear the current highlight
        if self.hiSq is not False:
            self.squares[self.hiSq].setColor(SquareColor(self.hiSq))
            self.hiSq = False

        #Check to see if we can access the mouse. We need it to do anything else
        if base.mouseWatcherNode.hasMouse():
            #get the mouse position
            mpos = base.mouseWatcherNode.getMouse()

            #Set the position of the ray based on the mouse position
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())

            #If we are dragging something, set the position of the object
            #to be at the appropriate point over the plane of the board
            if self.dragging is not False:
                #Gets the point described by pickerRay.getOrigin(), which is relative to
                #camera, relative instead to render
                nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin())
                #Same thing with the direction of the ray
                nearVec = render.getRelativeVector(camera, self.pickerRay.getDirection())
                self.pieces[self.dragging].obj.setPos(
                    PointAtZ(.5, nearPoint, nearVec))

            #Do the actual collision pass (Do it only on the squares for
            #efficiency purposes)
            self.picker.traverse(self.squareRoot)
            if self.pq.getNumEntries() > 0:
                #if we have hit something, sort the hits so that the closest
                #is first, and highlight that node
                self.pq.sortEntries()
                i = int(self.pq.getEntry(0).getIntoNode().getTag('square'))
                #Set the highlight on the picked square
                self.squares[i].setColor(HIGHLIGHT)
                self.hiSq = i

        return Task.cont

    def grabPiece(self):
        #If a square is highlighted and it has a piece, set it to dragging mode
        if (self.hiSq is not False and
                self.pieces[self.hiSq]):
            self.dragging = self.hiSq
            self.hiSq = False

    def releasePiece(self):
        #Letting go of a piece. If we are not on a square, return it to its original
        #position. Otherwise, swap it with the piece in the new square
        if self.dragging is not False:  #Make sure we really are dragging something
            #We have let go of the piece, but we are not on a square
            if self.hiSq is False:
                self.pieces[self.dragging].obj.setPos(
                    SquarePos(self.dragging))
            else:
                #Otherwise, swap the pieces
                self.swapPieces(self.dragging, self.hiSq)

        #We are no longer dragging anything
        self.dragging = False

    def setupLights(self):  #This function sets up some default lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.8, .8, .8, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0, 45, -45))
        directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(ambientLight))
예제 #17
0
class HexGrid(object):

    def __init__(self, w, h, show):

        self.width = w
        self.height = h

        self.loader = show.loader

        self.root = show.render.attachNewNode("hexgrid_root")

        self.base_tile = 'hex'

        self.diameter = 20
        self.inscribed = self.diameter * sqrt(3) / 2

        self.nodes = None

        self.show = show

        # Since we are using collision detection to do picking, we set it up like
        # any other collision detection system with a traverser and a handler
        self.picker = CollisionTraverser()  # Make a traverser
        self.picker_queue = CollisionHandlerQueue()  # Make a handler
        # Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        # Attach that node to the camera since the ray will need to be positioned
        # relative to it
        self.pickerNP = show.camera.attachNewNode(self.pickerNode)
        # Everything to be picked will use bit 1. This way if we were doing other
        # collision we could seperate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  # Make our ray
        # Add it to the collision node
        self.pickerNode.addSolid(self.pickerRay)
        # Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.picker_queue)

        self.assemble()

        self.onclick_fn = None

        # self.mouseTask = self.taskMgr.add(self.mouseTask, 'mouseTask')
        # self.accept("mouse1", self.grabPiece)  # left-click grabs a piece
        show.accept("mouse1-up", self.mouse_up)  # releasing places it

    def mouse_up(self):
        # This task deals with the highlighting and dragging based on the mouse

        # Check to see if we can access the mouse. We need it to do anything
        # else
        if self.onclick_fn and self.show.mouseWatcherNode.hasMouse():
            # get the mouse position
            mpos = self.show.mouseWatcherNode.getMouse()

            # Set the position of the ray based on the mouse position
            self.pickerRay.setFromLens(self.show.camNode, mpos.getX(), mpos.getY())

            # Do the actual collision pass
            self.picker.traverse(self.root)
            if self.picker_queue.getNumEntries() > 0:
                # if we have hit something, sort the hits so that the closest
                # is first, and highlight that node
                self.picker_queue.sortEntries()
                i = int(self.picker_queue.getEntry(0).getIntoNode().getTag('hexmesh_i'))

                self.onclick_fn(self.nodes[i])

        return Task.cont

    def onclick(self, fn):

        self.onclick_fn = fn

    def index_of(self, x, y):

        return x + y * self.width

    def xyi_iter(self, fn):

        for x in range(self.height):
            for y in range(self.width):

                fn(x, y, self.index_of(x, y))

    def node_iter(self, fn):

        for node in self.nodes:
            fn(node)

    def assemble(self):

        random.seed(3141592)

        def make_node(x, y, i):

            row_offset = self.inscribed / 2. if y % 2 == 0 else 0

            pos = Point3(x * self.inscribed + row_offset, y * self.diameter * 0.75, 0)

            self.nodes[i] = HexNode(self.base_tile, pos, self.root, i)

        self.nodes = [None for _ in range(self.width * self.height)]

        self.xyi_iter(make_node)
예제 #18
0
class Physics:
    def __init__(self):
        self.rayCTrav = CollisionTraverser("collision traverser for ray tests")
        #self.pusher = PhysicsCollisionHandler()
        self.pusher = CollisionHandlerPusher()
        self.pusher.addInPattern('%fn-in-%in')
        self.pusher.addOutPattern('%fn-out-%in')
        self.pusher.addInPattern('%fn-in')
        self.pusher.addOutPattern('%fn-out')

    def startPhysics(self):
        #self.actorNode = ActorNode("playerPhysicsControler")
        #base.physicsMgr.attachPhysicalNode(self.actorNode)
        #self.actorNode.getPhysicsObject().setMass(self.player_mass)
        #self.mainNode = render.attachNewNode(self.actorNode)
        self.mainNode = render.attachNewNode("CharacterColliders")
        self.reparentTo(self.mainNode)

        charCollisions = self.mainNode.attachNewNode(CollisionNode(self.char_collision_name))
        #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0, self.player_height/4.0))
        #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0*3.05, self.player_height/4.0))
        charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/2.0, self.player_height/4.0))
        charCollisions.node().setIntoCollideMask(BitMask32(0x80))  # 1000 0000
        if self.show_collisions:
            charCollisions.show()
        self.pusher.addCollider(charCollisions, self.mainNode)
        base.cTrav.addCollider(charCollisions, self.pusher)

        charFFootCollisions = self.attachNewNode(CollisionNode("floor_ray"))
        charFFootCollisions.node().addSolid(CollisionRay(0, 0, 0.5, 0, 0, -1))
        #charFFootCollisions.node().addSolid(CollisionSegment((0, 0, 0.2), (0, 0, -1)))
        charFFootCollisions.node().setIntoCollideMask(BitMask32.allOff())
        charFFootCollisions.node().setFromCollideMask(BitMask32(0x7f))  # 0111 1111
        if self.show_collisions:
            charFFootCollisions.show()

        self.floor_handler = CollisionHandlerFloor()
        self.floor_handler.addCollider(charFFootCollisions, self.mainNode)
        #self.floor_handler.setOffset(0)
        self.floor_handler.setMaxVelocity(5)
        base.cTrav.addCollider(charFFootCollisions, self.floor_handler)

        self.accept("{}-in".format(self.char_collision_name), self.checkCharCollisions)

        self.raytest_segment = CollisionSegment(0, 1)
        self.raytest_np = render.attachNewNode(CollisionNode("testRay"))
        self.raytest_np.node().addSolid(self.raytest_segment)
        self.raytest_np.node().setIntoCollideMask(BitMask32.allOff())
        self.raytest_np.node().setFromCollideMask(BitMask32(0x7f))  # 0111 1111
        if self.show_collisions:
            self.raytest_np.show()

        self.raytest_queue = CollisionHandlerQueue()
        self.rayCTrav.addCollider(self.raytest_np, self.raytest_queue)

    def stopPhysics(self):
        self.raytest_segment.removeNode()
        self.pusher.clearColliders()
        self.floor_handler.clearColliders()
        self.rayCTrav.clearColliders()

    def updatePlayerPos(self, speed, heading, dt):
        if heading is not None:
            self.mainNode.setH(camera, heading)
            self.mainNode.setP(0)
            self.mainNode.setR(0)
        self.mainNode.setFluidPos(self.mainNode, speed)
        self.doStep()

    def checkCharCollisions(self, args):
        self.doStep()

    def doStep(self):
        # do the step height check
        tmpNP = self.mainNode.attachNewNode("temporary")
        tmpNP.setPos(self.mainNode, 0, 0, -self.stepheight)
        pointA = self.mainNode.getPos(render)
        pointA.setZ(pointA.getZ() + self.player_height/1.8)
        pointB = tmpNP.getPos(render)
        if pointA == pointB: return
        char_step_collision = self.getFirstCollisionInLine(pointA, pointB)
        tmpNP.removeNode()
        if char_step_collision is not None:
            self.mainNode.setFluidZ(char_step_collision.getZ())
            return True
        return False

    def getFirstCollisionInLine(self, pointA, pointB):
        """A simple raycast check which will return the first collision point as
        seen from point A towards pointB"""
        self.raytest_segment.setPointA(pointA)
        self.raytest_segment.setPointB(pointB)
        self.rayCTrav.traverse(render)
        self.raytest_queue.sortEntries()
        pos = None
        if self.raytest_queue.getNumEntries() > 0:
            pos = self.raytest_queue.getEntry(0).getSurfacePoint(render)
        return pos
예제 #19
0
class TrainingBananas(JoystickHandler):
    def __init__(self):
        """
        Initialize the experiment
        """
        pydaq_loaded = PYDAQ_LOADED
        self.base = ShowBase()
        config = {}
        execfile('train_config.py', config)
        if not unittest:
            JoystickHandler.__init__(self)
        self.base.disableMouse()
        sys.stdout.write('Subject is ' + str(config['subject']) + '\n')
        self.subject = config['subject']
        self.levels_available = [[2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6], [3, 3.1], [4, 4.1, 4.2]]

        # set up reward system
        # if unit-testing, pretend like we couldn't
        # load the module
        if unittest:
            pydaq_loaded = False
        if config['reward'] and pydaq_loaded:
            self.reward = pydaq.GiveReward()
        else:
            self.reward = None
            sys.stdout.write('Warning: reward system not on \n')

        # setup windows
        if not unittest:
            # if doing unittests, there is no window
            wp = WindowProperties()
            # wp.setSize(1280, 800)
            wp.setSize(1024, 768)
            wp.setOrigin(0, 0)
            wp.setCursorHidden(True)
            self.base.win.requestProperties(wp)
            # base.setFrameRateMeter(True)
            # initialize training file name
            self.data_file_name = ''
            self.data_file = None
            self.open_data_file(config)

        # Get initial direction, only matters for manual, random will override later
        # for bananas, changing the angle from avatar to banana, so left is negative
        # right is positive.
        if config['trainingDirection'] == 'Right':
            self.multiplier = 1
        elif config['trainingDirection'] == 'Left':
            self.multiplier = -1
        # print config['trainingDirection']
        self.last_multiplier = self.multiplier

        # get more variables from configuration
        self.side_bias = config['random_bias']
        # bring some configuration parameters into memory, so we don't need to
        # reload the config file multiple times, also allows us to change these
        # variables dynamically
        self.num_beeps = config['numBeeps']
        # not changing now, but may eventually...
        self.x_alpha = config['xHairAlpha']
        self.reward_time = config['pulseInterval']  # usually 200ms
        # amount need to hold crosshair on banana to get reward (2.3)
        # must be more than zero. At 1.5 distance, must be greater than
        # 0.5 to require stopping
        self.hold_aim = config['hold_aim']
        self.initial_speed = config['initial_turn_speed']
        self.initial_forward_speed = config['initial_forward_speed']
        self.forward_limit = config['forward_limit']
        self.training = config['training']
        if not unittest:
            sys.stdout.write('training level: ' + str(self.training) + '\n')
            if self.training < 2.2:
                sys.stdout.write('starting direction: ' + str(config['trainingDirection']) + '\n')
        # random selection used for training 2.3 and above
        self.all_random_selections = config['random_lists']
        self.current_choice = config['random_selection'] - 1
        self.random_choices = self.all_random_selections[self.current_choice]

        # Setup Graphics
        # bitmasks for collisions
        ray_mask = BitMask32(0x1)
        sphere_mask = BitMask32(0x2)
        self.mask_list = [ray_mask, sphere_mask, ray_mask | sphere_mask]
        if config['background']:
            field = self.base.loader.loadModel("models/play_space/field.bam")
            field.setPos(Point3(0, 0, 0))
            field.reparentTo(self.base.render)
            field_node_path = field.find('**/+CollisionNode')
            field_node_path.node().setIntoCollideMask(0)
            sky = self.base.loader.loadModel("models/sky/sky.bam")
            sky.setPos(Point3(0, 0, 0))
            sky.reparentTo(self.base.render)

        # set up banana
        self.banana = None
        self.banana_mask = None
        self.banana_node_path = None
        self.banana_coll_node = None
        self.load_fruit(config.get('fruit', 'banana'))

        # set up collision system and collision ray to camera
        self.base.cTrav = CollisionTraverser()
        self.collHandler = CollisionHandlerQueue()
        ray_node = self.base.camera.attachNewNode(CollisionNode('CrossHairRay'))
        # ray that comes straight out from the camera
        ray_solid = CollisionRay(0, 0, 0, 0, 1, 0)
        self.ray_node_path = self.make_coll_node_path(ray_node, ray_solid)
        self.ray_node_path.node().setIntoCollideMask(0)
        self.ray_node_path.node().setFromCollideMask(ray_mask)

        # add collision sphere to camera
        sphere_node = self.base.camera.attachNewNode(CollisionNode('CollisionSphere'))
        # camera_sphere = CollisionSphere(0, 0, 0, 1.3)
        # avatar_radius = 0.3
        avatar_radius = 1
        camera_sphere = CollisionSphere(0, 0, 0, avatar_radius)
        self.sphere_node_path = self.make_coll_node_path(sphere_node, camera_sphere)
        self.sphere_node_path.node().setIntoCollideMask(0)
        self.sphere_node_path.node().setFromCollideMask(sphere_mask)

        # into collide masks are set with level variables, since we change
        # whether between using the sphere or the ray for detecting collisions,
        # depending on which level we are on.

        self.base.cTrav.addCollider(self.ray_node_path, self.collHandler)
        self.base.cTrav.addCollider(self.sphere_node_path, self.collHandler)
        # self.base.cTrav.showCollisions(self.base.render)
        # self.ray_node_path.show()
        # self.sphere_node_path.show()
        # self.banana_node_path.show()
        # self.base.render.find('**/+CollisionNode').show()

        # Camera
        self.base.camLens.setFov(60)

        # set avatar position/heading
        # Default positions
        self.avatar_pos = Point3(0, -1.5, 1)
        self.avatar_h = 0
        self.screen_edge = 30
        self.config_avatar_d = -config['avatar_start_d']
        self.config_avatar_h = config['avatar_start_h']

        # Cross hair
        # color changes for crosshair
        self.x_start_c = Point4(1, 1, 1, self.x_alpha)
        self.x_stop_c = Point4(1, 0, 0, self.x_alpha)
        self.crosshair = TextNode('crosshair')
        self.crosshair.setText('+')
        text_node_path = self.base.aspect2d.attachNewNode(self.crosshair)
        text_node_path.setScale(0.2)
        # crosshair is always in center, but
        # need it to be in same place as collisionRay is, but it appears that center is
        # at the bottom left of the collisionRay, and the top right of the text, so they
        # don't have center in the same place. Makes more sense to move text than ray.
        # These numbers were scientifically determined. JK, moved around until the cross looked
        # centered on the ray
        # crosshair_pos = Point3(0, 0, 0)
        # crosshair_pos = Point3(-0.07, 0, -0.05)
        crosshair_pos = Point3(-0.055, 0, -0.03)

        # print text_node_path.getPos()
        text_node_path.setPos(crosshair_pos)

        # set level
        # setup variables related to training levels
        # initialize training variables
        # will be set to proper levels in set_level_variables method
        self.free_move = 0
        self.must_release = False
        self.random_banana = False
        self.require_aim = False
        self.go_forward = False
        #self.set_level_variables(self.training)

        # setup keyboard/joystick inputs
        self.setup_inputs()
        # Initialize more variables

        # These variables are set to their initial states in reset_variables, so
        # does not matter what they are set to here.
        # DO NOT SET VARIABLES HERE, GO TO RESET_VARIABLES!!!
        # variable used to notify when changing direction of new target
        self.new_dir = None
        # and variable to notify when changing levels
        self.change_level = False
        self.max_angle = None
        self.min_angle = None
        self.delay_start = False
        self.yay_reward = False
        self.reward_delay = False
        self.reward_on = True
        self.reward_count = 0
        self.x_mag = 0
        self.y_mag = 0
        self.speed = self.initial_speed  # factor to slow down movement of joystick and control acceleration
        # speed for going in the wrong direction, when same speed as initial speed, then no change
        self.forward_speed = self.initial_forward_speed
        self.wrong_speed = 0.005
        self.slow_speed = self.wrong_speed
        # toggle for whether moving is allowed or not
        self.moving = True
        # toggle for making sure stays on banana for min time for 2.3
        self.set_zone_time = False
        # keeps track of how long we have held
        self.hold_time = 0
        self.check_zone = False
        # self.check_time = 0
        # toggle for when trial begins
        self.start_trial = True
        # print self.avatar_h
        # print self.base.camera.getH()
        # print self.avatar_pos
        # print self.base.camera.getPos()
        # print self.base.camLens.getFov()
        # print self.base.camLens.getNear()
        # print self.base.camLens.getFar()
        # print self.base.camLens.getAspectRatio()
        self.base.camLens.setNear(avatar_radius/3.0)
        # print self.banana.getPos()
        # set variables to their actual starting values
        self.reset_variables()
        self.set_level_variables(self.training)
        # print 'set level'
        self.set_camera()
        # print 'set camera'
        # start stuff happening!
        self.start_task()

    def frame_loop(self, task):
        # print self.training
        # print 'loop'
        dt = task.time - task.last
        task.last = task.time
        # print('dt', dt)
        # delay_start means we just gave reward and need to set wait
        # until reward pump is done to do anything
        if self.delay_start:
            task.delay = task.time + self.reward_time
            # print('time now', task.time)
            # print('delay until', task.delay)
            self.delay_start = False
            # self.reward_delay = True
            return task.cont
        # set_zone_time means we have the crosshair over the banana,
        # and have to set how long to leave it there
        if self.set_zone_time:
            # print 'reset zone time'
            self.hold_time = task.time + self.hold_aim
            self.set_zone_time = False
            self.check_zone = True
        # reward delay is over, on to regularly scheduled program
        if task.time > task.delay:
            # print 'past delay'
            # check for reward
            # print('beeps so far', self.reward_count)
            # print self.yay_reward
            if self.yay_reward == 'partial':
                # print 'giving partial reward'
                self.give_reward()
                self.yay_reward = None
                self.go_forward = True
                # since none, don't need to return, won't give more reward, but
                # will go on to let move
            elif self.yay_reward and self.reward_count < self.num_beeps:
                # print 'gave reward'
                self.reward_count += 1
                self.give_reward()
                return task.cont
            elif self.yay_reward and self.reward_count == self.num_beeps:
                # print 'gave final reward'
                # done giving reward, time to start over, maybe
                # hide the banana
                self.banana.stash()
                # change the color of the crosshair
                self.x_change_color(self.x_start_c)
                # before we can proceed, subject may need to let go of the joystick
                if self.must_release:
                    # print 'checking for release'
                    # print self.x_mag
                    if abs(self.x_mag) > 0 or abs(self.y_mag) > 0:
                        # print('let go!')
                        return task.cont
                # and now we can start things over again
                # print('start over')
                self.restart_bananas()
                # check_time is used to see how long it takes subject
                # to get banana from time plotted
                # self.check_time = task.time
                return task.cont
            # check to see if we are moving
            if self.moving:
                # moving, forward first, only bother checking if possible to go forward
                if self.go_forward:
                    # forward needs a little speed boost compared to turning
                    if self.start_trial or self.y_mag == 0:
                        self.forward_speed = self.initial_forward_speed
                        self.start_trial = False
                    else:
                        # self.y_mag (how much you push the joystick) affects
                        # acceleration as well as speed
                        self.forward_speed += self.initial_forward_speed * abs(self.y_mag)
                    position = self.base.camera.getPos()
                    # print(position)
                    # print('y_mag', self.y_mag)
                    # print('speed', self.speed)
                    # print('dt', dt)
                    # print('change in position', self.y_mag * self.speed * dt)
                    position[1] += self.y_mag * self.forward_speed * dt
                    # if this puts us past center, stay at center
                    if position[1] > 0:
                        position[1] = 0
                    self.base.camera.setPos(position)
                # Now check for rotation. Don't need to check this if going forward
                if not self.go_forward:
                    # print 'rotating'
                    heading = self.base.camera.getH()
                    delta_heading = self.get_new_heading(heading, dt)
                    self.base.camera.setH(heading + delta_heading)
                    # print('camera heading', self.base.camera.getH())
                # check for collision:
                collide_banana = self.check_banana()
                # print('collide', collide_banana)
                # if we need to be stopping and leaving (holding) crosshair over banana,
                # make sure still in target zone.
                if self.check_zone:
                    # print('check hold')
                    # not sure if I will use a zone for going forward yet
                    # The 'zone' is whenever the ray is colliding with the banana.
                    # use zone for both left-right training and for forward training,
                    # whenever self.require_aim is true.
                    # with forward training, use to see if we went off course, and then
                    # lined up the crosshair and banana again.
                    # print collide_banana
                    if collide_banana:
                        # print('still in the zone')
                        if task.time > self.hold_time:
                            # print('hold aim', self.hold_aim)
                            # print('ok, get reward')
                            # print self.free_move
                            # print('hold time', task.time > self.hold_time)
                            # stop moving and get reward
                            if self.free_move == 4:
                                # partial reward for lining up banana in level 4.x
                                # print 'partial reward'
                                self.yay_reward = 'partial'
                                self.check_zone = False
                            elif self.yay_reward is not None:
                                self.x_change_color(self.x_stop_c)
                                self.moving = False
                                self.yay_reward = True
                                self.check_zone = False
                        else:
                            pass
                            # print('keep holding')
                            # print('time', task.time)
                            # print('hold until', self.hold_time)
                    else:
                        # print('left zone, wait for another collision')
                        self.x_change_color(self.x_start_c)
                        # print('require aim', self.require_aim)
                        if self.require_aim == 'slow':
                            # print 'aim slow'
                            self.check_zone = None
                        else:
                            # print "don't slow down"
                            self.check_zone = False
                else:
                    # not currently checking zone, so either collide_banana means reward immediately
                    # or start timer to check if leaving zone
                    # print('camera heading before collision', self.base.camera.getH())
                    if collide_banana:
                        # print('time took: ', task.time - self.check_time)
                        # print 'collision'
                        # print 'change xhair color to red'
                        self.x_change_color(self.x_stop_c)
                        # if we require aim, we start timer when we have a collision,
                        # but if self.go_forward, than we have already aimed.
                        if self.require_aim and not self.go_forward:
                            self.set_zone_time = True
                        else:
                            # print 'yes'
                            # reward time!
                            # stop moving
                            self.moving = False
                            # move to center
                            if self.base.camera.getH != 0:
                                pass
                                # print 'moved camera'
                                # self.base.camera.setH(0)
                            self.yay_reward = True
                    elif collide_banana is None:
                        # partial reward for lining up banana in level 4.x
                        # print 'partial reward'
                        self.yay_reward = 'partial'
                        # self.yay_reward = True
                        # self.reward_count = self.num_beeps - 1
        return task.cont

    def give_reward(self):
        # print('beep')
        if self.reward:
            self.reward.pumpOut()
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'reward' + '\n')
        self.delay_start = True

    def check_banana(self):
        # print 'check banana'
        collide_banana = False
        # print self.base.camera.getPos()
        # if we are doing only forward, or only side, only need to check for entries,
        # but if doing both movement, have to check for whichever we are currently
        # interested in.
        if self.free_move == 4:
            # why doesn't the camera show that we see the banana, ever? wrong camera?
            # print self.base.camNode.isInView(self.banana.getPos())
            for i in range(self.collHandler.getNumEntries()):
                entry = self.collHandler.getEntry(i)
                # in_view = self.base.camNode.isInView(entry.getIntoNodePath().getPos())
                # print in_view
                # print entry.getIntoNodePath().getPos()
                if entry.getFromNodePath() == self.sphere_node_path:
                    # print 'ran into banana going forward'
                    collide_banana = True
                    self.moving = False
                elif entry.getFromNodePath() == self.ray_node_path:
                    # print 'collide ray'
                    # print self.yay_reward
                    # if we are requiring aim, than use collide_banana = True,
                    # since this will automatically get diverted before full reward
                    if self.yay_reward is not None and not self.require_aim:
                        # print 'lined up banana from side'
                        collide_banana = None
                    elif self.yay_reward is not None and self.require_aim:
                        # print 'lined up banana from side, need to aim'
                        collide_banana = True
                # print entry.getFromNodePath()
        elif self.collHandler.getNumEntries() > 0:
            # print 'collided'
            # the only object we can be running into is the banana, so there you go...
            collide_banana = True
            # print self.collHandler.getEntries()
            # print self.base.camera.getH()
            # print self.base.camera.getPos()
            # print self.banana.getPos()
        return collide_banana

    def restart_bananas(self):
        # print 'restarted'
        # print('training', self.training)
        # reset a couple of variables
        self.yay_reward = False
        self.reward_count = 0
        # self.check_time = 0
        # used to reset speed
        self.start_trial = True
        # print self.multiplier
        # check to see if we are switching the banana to the other side
        if self.new_dir is not None:
            self.multiplier = self.new_dir
            self.new_dir = None
            # for some versions, subject could still be holding joystick at this point.
            # (for example, was going to the right, but now is suppose to be going to the left,
            # but since we only detect when the joystick position has changed, and it has
            # not, may not realize that that we are now going what is considered a 'wrong' direction
            # so we are essentially re-checking the the joystick position, given the other updated
            # parameters).
            # send the current joystick position through the move method to correct that.
            # the original signal had its sign changed, so switch the sign here as well.
            # print 'move'
            self.move('x', -self.x_mag)
            #print('change direction', -self.x_mag)
        if self.change_level:
            # print 'actually change level now'
            self.set_level_variables(self.change_level)
            print('angle', self.base.camera.getH())
            self.change_level = False
        # check to see if banana is on random
        if self.random_banana:
            # print 'random'
            # make side not entirely random. Don't want too many in a row on one side
            # for MP, because he is a bit of an idiot.
            # First check if we care about the next direction
            if self.side_bias and abs(self.last_multiplier) > 1:
                # if there have been two in a row in the same direction, pick the opposite
                # direction, otherwise choose randomly
                # print 'change, self.last_multiplier is zero'
                self.multiplier = - self.multiplier
            else:
                # print 'random'
                self.multiplier = random.choice([1, -1])
            # print('next up', self.multiplier)
            # multiplier should never be zero when doing this comparison
            # last_multiplier is the only one that can be zero, and only
            # very briefly
            # if this gives you a negative 1, than we are switching sides,
            # if we don't care about side_bias, we don't look at last_multiplier,
            # and this doesn't matter
            if self.last_multiplier/self.multiplier != 1:
                # print 'reset'
                self.last_multiplier = 0
            self.last_multiplier += self.multiplier
            # print('last currently', self.last_multiplier)
            self.avatar_h = random.choice(self.random_choices)
            # for some versions, subject could still be holding joystick at this point.
            # this means we x_mag is at a position that might no longer be
            # allowed, so we are going to send the current joystick position
            # through the move method to correct that. move switches the sign, so switch
            # the sign here as well.
            # print 'move'
            self.move('x', -self.x_mag)
        self.set_camera()
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'banana position, ' +
                                 str(self.multiplier * self.avatar_h) + '\n')
        # print('min time to reward:', sqrt(2 * self.avatar_h / 0.05 * 0.01))
        # for training 4, switch from going forward to left/right
        if self.free_move == 4:
            self.go_forward = False
        # un-hide banana
        self.banana.unstash()
        # print 'avatar can move again, new trial starting'
        self.moving = True
        # print('yay', self.yay_reward)

    def start_task(self):
        self.frameTask = self.base.taskMgr.add(self.frame_loop, "frame_loop")
        self.frameTask.delay = -0.1  # want initial delay less than zero
        self.frameTask.last = 0  # task time of the last frame
        #print 'set task'
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'banana position, ' +
                                 str(self.multiplier * self.avatar_h) + '\n')

    def set_camera(self):
        self.base.camera.setH(self.multiplier * abs(self.avatar_h))
        self.base.camera.setPos(self.avatar_pos)
        #print self.base.camera.getPos()
        #print self.banana.getPos()
        # print self.base.camera.getH()
        sys.stdout.write('current angle: ' + str(self.base.camera.getH()) + '\n')

    def x_change_color(self, color):
        # print self.crosshair.getColor()
        self.crosshair.setTextColor(color)
        # self.cross.setColor(Point4(1, 0, 0, 1))

    def move(self, js_dir, js_input):
        # most restrictions on movement handled in frame_loop,
        # both due to levels and due to environment
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 str(js_dir) + ', ' +
                                 str(-js_input) + '\n')
            # print(js_dir, js_input)
        # Threshold. If too low, noise will create movement.
        if abs(js_input) < 0.1:
            js_input = 0
        # we are moving the camera in the opposite direction of the joystick,
        # x and y inputs will both be inverted
        if js_dir == 'x' or js_dir == 'x_key':
            # print js_input
            # x direction is reversed
            self.x_mag = -js_input
            # print('x_mag', self.x_mag)
            # hack for Mr. Peepers...
            # barely touch joystick and goes super speedy. speed not dependent
            # on how hard he touches joystick (always 2)
            # if self.subject == 'MP' and js_input != 0:
            #    # print 'yes'
            #    # need it to be the same direction as negative of js_input
            #    self.x_mag = js_input/abs(js_input) * -2
            # new hack for Mr. Peepers...
            # joystick pressure has more of an effect than acceleration
            # (0 to 2 instead of 0 to 1, trying to get him to push harder on
            # on the joystick)
            if self.subject == 'MP' and js_input != 0:
                self.x_mag = js_input * -2
            # print('x', self.x_mag)
        else:
            # y direction is also reversed,
            # not allowed to go backward, ever
            if js_input < 0:
                self.y_mag = -js_input
            else:
                self.y_mag = 0

    def restrict_forward(self):
        """
        :return:
        As self.forward_limit increases, we require the subject to 'go straighter',
        iow, the subject should not be pushing the joystick to the side, only forward
        When forward_limit hits one, can only go forward (any side movement means don't
        go anywhere)
        """
        self.go_forward = True
        if self.x_mag > self.forward_limit:
            self.go_forward = False

    def get_new_heading(self, heading, dt):
        # print 'get new heading'
        # set new turning speed.
        # if new trial or subject stopped moving, reverts to initial speed
        if self.start_trial or self.x_mag == 0:
            self.speed = self.initial_speed
            self.slow_speed = self.wrong_speed
            self.start_trial = False
        else:
            # the larger the push on the joystick,
            # the more the speed increases.
            self.slow_speed += self.wrong_speed * abs(self.x_mag)
            # self.speed += 0.05 * abs(self.x_mag)
            self.speed += self.initial_speed * abs(self.x_mag)
        # determine if moving towards the banana
        to_banana = False
        # first make sure we don't divide by zero,
        if self.x_mag != 0 and heading != 0:
            if self.x_mag/abs(self.x_mag) * heading/abs(heading) < 0:
                to_banana = True
        # unless there is a reason to stop movement, this is the heading
        delta_heading = self.x_mag * self.speed * dt
        # if not allowed to go past banana, stop directly at center
        # if self.free_move == 1:
        # if heading + delta_heading switches it from + to -
        # if heading away from banana, many opportunities to slow or
        # stop movement...
        if not to_banana:
            if abs(heading) >= self.screen_edge:
                # block off edge of screen
                # print 'hit a wall'
                delta_heading = 0
            elif self.check_zone is None:
                # if check_zone is None, than went past banana target zone,
                # and we want to go slow
                # print 'went past zone'
                delta_heading = self.x_mag * self.slow_speed * dt
                # delta_heading = self.x_mag * self.initial_speed * dt
            elif self.free_move == 1:
                # print 'free move is 1'
                # self.free_move is one, only allowed to go towards banana
                delta_heading = 0
            elif self.free_move == 2:
                # print 'free move is 2'
                # self.free_move is two, both directions allowed, but go
                # in direction away from banana more slowly.
                # print 'slow'
                # self.x_mag /= self.wrong_speed
                delta_heading = self.x_mag * self.slow_speed * dt
                # print self.slow_speed
                # delta_heading = self.x_mag * self.speed * dt
        # print('delta heading', delta_heading)
        return delta_heading

    def inc_angle(self):
        # print('old pos', self.avatar_h)
        # self.avatar_h[0] = self.avatar_h[0] * 1.5
        # self.avatar_h *= 1.5
        self.avatar_h *= 1.1
        # print('would be', self.avatar_h)
        if abs(self.avatar_h) > self.max_angle:
            self.avatar_h = self.multiplier * self.max_angle
        # y is always going to be positive
        # self.avatar_h[1] = sqrt(25 - self.avatar_h[0] ** 2)
        sys.stdout.write('increase angle, new angle: ' + str(self.avatar_h) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, increase angle ' +
                                 str(self.multiplier * self.avatar_h) + '\n')
        # print('min time to reward:', sqrt(2 * self.avatar_h / 0.05 * 0.01))

    def dec_angle(self):
        # print('old pos', self.avatar_h)
        # self.avatar_h /= 1.5
        self.avatar_h /= 1.1
        if abs(self.avatar_h) < self.min_angle:
            self.avatar_h = self.multiplier * self.min_angle
        # self.banana_pos[0] = x_sign * (abs(self.banana_pos[0]) - 1)
        # self.banana_pos[1] = sqrt(25 - self.banana_pos[0] ** 2)
        sys.stdout.write('decrease angle, new angle: ' + str(self.avatar_h) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, decrease angle ' +
                                 str(self.multiplier * self.avatar_h) + '\n')
        # print('min time to reward:', sqrt(2 * self.avatar_h / 0.05 * 0.01))

    def inc_reward(self):
        self.num_beeps += 1
        sys.stdout.write('increase reward, new reward: ' + str(self.num_beeps) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, increase reward ' +
                                 str(self.num_beeps) + '\n')

    def dec_reward(self):
        self.num_beeps -= 1
        sys.stdout.write('decrease reward, new reward: ' + str(self.num_beeps) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, decrease reward ' +
                                 str(self.num_beeps) + '\n')

    def inc_level(self):
        # increase the level, if we are jumping multiple levels,
        # at once, self.training will not have increased yet, so
        # check to see what self.change_level is first (don't want
        # to change levels in the middle of a trial)
        training = self.training
        if self.change_level:
            training = self.change_level
        # print('old level', training)
        # get current position in sequence:
        seq_num = self.get_seq_num(training)
        if training == self.levels_available[-1][-1]:
            sys.stdout.write('already at most difficult level \n')
            self.change_level = training
        elif training == self.levels_available[seq_num][-1]:
            sys.stdout.write('switching to new sequence \n')
            self.change_level = self.levels_available[seq_num + 1][0]
        else:
            self.change_level = round(training + 0.1, 2)
        sys.stdout.write('increase level, new level: ' + str(self.change_level) + '\n')
        # print('new level', self.change_level)
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, increase level ' +
                                 str(self.change_level) + '\n')

    def dec_level(self):
        # decrease the level, if we are jumping multiple levels,
        # at once, self.training will not have increased yet, so
        # check to see what self.change_level is first (don't want
        # to change levels in the middle of a trial)
        training = self.training
        if self.change_level:
            training = self.change_level
        # print('old level', training)
        # get current position in sequence:
        seq_num = self.get_seq_num(training)
        if training == self.levels_available[0][0]:
            sys.stdout.write('already at easiest level \n')
            self.change_level = training
        elif training == self.levels_available[seq_num][0]:
            sys.stdout.write('switching to new sequence \n')
            self.change_level = self.levels_available[seq_num - 1][-1]
        else:
            self.change_level = round(training - 0.1, 2)
        sys.stdout.write('increase level, new level: ' + str(self.change_level) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, decrease level ' +
                                 str(self.change_level) + '\n')

    def get_seq_num(self, training):
        seq_num = 0
        for seq_num, sequence in enumerate(self.levels_available):
            if sequence.count(training) > 0:
                if sequence.index(training) is not None:
                    break
        return seq_num

    def inc_wrong_speed(self):
        if self.wrong_speed >= self.initial_speed:
            self.wrong_speed = self.initial_speed
            sys.stdout.write('now same speed as towards the banana \n')
        else:
            self.wrong_speed += 0.01
        sys.stdout.write('increase speed in wrong direction, new: ' + str(self.wrong_speed) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, increase wrong speed ' +
                                 str(self.wrong_speed) + '\n')

    def dec_wrong_speed(self):
        self.wrong_speed -= 0.01
        sys.stdout.write('decrease speed in wrong direction, new: ' + str(self.wrong_speed) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, decrease wrong speed ' +
                                 str(self.wrong_speed) + '\n')

    def inc_random(self):
        if self.current_choice == len(self.all_random_selections) - 1:
            sys.stdout.write('already at max \n')
        else:
            # current is the current length, which conveniently
            # enough is the next number to use, because of zero indexing
            self.current_choice += 1
            self.random_choices = self.all_random_selections[self.current_choice]
        sys.stdout.write('increase selection of random bananas, new: ' + str(self.random_choices) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, increase random selection ' +
                                 str(self.random_choices) + '\n')

    def dec_random(self):
        if self.current_choice == 0:
            sys.stdout.write('already at min \n')
        else:
            # current is the current length, so we need to subtract
            # by two, because of zero indexing
            self.current_choice -= 1
            self.random_choices = self.all_random_selections[self.current_choice]
        sys.stdout.write('decrease selection of random bananas, new: ' + str(self.random_choices) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, decrease random selection ' +
                                 str(self.random_choices) + '\n')

    def inc_forward_speed(self):
        self.initial_forward_speed += 0.01
        sys.stdout.write('increase forward speed, new: ' + str(self.initial_forward_speed) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, increase forward speed ' +
                                 str(self.initial_forward_speed) + '\n')

    def dec_forward_speed(self):
        self.initial_forward_speed -= 0.01
        sys.stdout.write('decrease forward speed, new: ' + str(self.initial_forward_speed) + '\n')
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, decrease forward speed ' +
                                 str(self.initial_forward_speed) + '\n')

    def change_left(self):
        self.new_dir = -1
        sys.stdout.write('new dir: left \n')
        print('new direction', self.new_dir)
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, new dir left' + '\n')

    def change_right(self):
        self.new_dir = 1
        sys.stdout.write('new dir: right \n')
        print('new direction', self.new_dir)
        if not unittest:
            self.data_file.write(str(self.frameTask.time) + ', ' +
                                 'keypress, new dir right' + '\n')

    def extra_reward(self):
        sys.stdout.write('beep \n')
        if self.reward:
            self.reward.pumpOut()

    def reset_variables(self):
        # this is only called once, from init
        self.base.taskMgr.remove("frame_loop")
        # set/reset to the original state of variables
        # self.max_angle = 26
        self.max_angle = 40
        self.min_angle = 1.5
        self.delay_start = False
        self.yay_reward = False
        self.reward_delay = False
        self.reward_on = True
        self.reward_count = 0
        self.x_mag = 0
        self.y_mag = 0
        self.speed = self.initial_speed  # factor to change speed of joystick and control acceleration
        self.forward_speed = self.initial_forward_speed
        # speed for going in the wrong direction, when same speed as initial speed, then no change
        self.wrong_speed = 0.005
        self.slow_speed = self.wrong_speed
        # toggle for whether moving is allowed or not
        self.moving = True
        # toggle for making sure stays on banana for min time for 2.3
        self.set_zone_time = False
        # amount need to hold crosshair on banana to get reward (2.3)
        # must be more than zero. At 1.5 distance, must be greater than
        # 0.5 to require stopping
        self.hold_aim = 0.6
        if unittest:
            self.hold_aim = 0.1
        # keeps track of how long we have held
        self.hold_time = 0
        # check_zone is a toggle that happens when lined up crosshair with banana
        # if check_zone is False, not currently in the zone, if true checking to
        # see if we have left the zone. if none, left the zone and in mode where
        # slows down after leaving the zone.
        self.check_zone = False
        # self.check_time = 0
        # speed for going in the wrong direction, 1 is no change, higher numbers slower
        self.wrong_speed = 0.005
        self.slow_speed = self.wrong_speed
        # toggle for when trial begins
        self.start_trial = True

    def set_level_variables(self, training):
        #print 'really setting level variables'
        # default is lowest training level
        self.training = training
        self.free_move = 1
        self.must_release = False
        self.random_banana = False
        self.require_aim = False
        self.go_forward = False
        self.banana_coll_node.setIntoCollideMask(self.mask_list[0])
        self.avatar_h = self.config_avatar_h
        self.avatar_pos = Point3(0, -1.5, 1)
        self.banana_node_path.setScale(0.1)
        if training > self.levels_available[0][0]:
            # print '2.1'
            self.must_release = True
        if training > self.levels_available[0][1]:
            # print '2.2'
            self.random_banana = True
        if training > self.levels_available[0][2]:
            # print '2.3'
            self.free_move = 2
        if training > self.levels_available[0][3]:
            # print '2.4'
            self.free_move = 3
        if training > self.levels_available[0][4]:
            # print '2.5'
            self.require_aim = 'slow'
        if training > self.levels_available[0][5]:
            # print '2.6'
            self.require_aim = True
        # print self.levels_available[0][-1]
        # level 3 training
        if training > self.levels_available[0][-1]:
            # print '3.0'
            self.avatar_pos = Point3(0.01, self.config_avatar_d, 1)
            self.banana_coll_node.setIntoCollideMask(self.mask_list[1])
            # defaults for level 3 training
            self.go_forward = True
            self.free_move = 0
            self.must_release = False
            self.random_banana = False
            self.require_aim = True
        if training > self.levels_available[1][0]:
            # print '3.1'
            self.must_release = True
        # level 4 training
        if training > self.levels_available[1][-1]:
            #self.banana_node_path.setScale(0.2)
            # print '4.0'
            self.banana_coll_node.setIntoCollideMask(self.mask_list[2])
            self.go_forward = False
            self.free_move = 4
            self.must_release = False
            self.random_banana = False
            self.require_aim = False
        if training > self.levels_available[2][0]:
            # print '4.1'
            self.random_banana = True
        if training > self.levels_available[2][1]:
            # print '4.2'
            self.require_aim = 'slow'
        if training > self.levels_available[2][2]:
            # print '4.3'
            self.require_aim = True
        #print('what sequence?', self.get_seq_num(training))
        # In case random_bananas changed:
        if self.random_banana:
            self.random_choices = self.all_random_selections[self.current_choice]
            self.avatar_h = random.choice(self.random_choices)
            sys.stdout.write('current angles available ' + str(self.random_choices) + '\n')
        elif self.get_seq_num(training) == 1:
            # really should have started out with training zero,
            # then numbering would be better...
            # print 'sequence 3?'
            self.avatar_h = 0
        else:
            self.avatar_h = self.config_avatar_h
        # print self.banana.getH()
        # print self.avatar_pos
        # print self.avatar_h
        sys.stdout.write('forward: ' + str(self.go_forward) + '\n')
        sys.stdout.write('free move: ' + str(self.free_move) + '\n')
        sys.stdout.write('random: ' + str(self.random_banana) + '\n')
        sys.stdout.write('require aim: ' + str(self.require_aim) + '\n')

    def load_fruit(self, fruit):
        if fruit == 'banana':
            self.banana = self.base.loader.loadModel("models/bananas/banana.bam")
            self.banana.setH(280)
            # self.banana.setH(0)
            self.banana.setScale(0.5)
            # banana always in the same position, just move avatar.
            self.banana.setPos(Point3(0, 0, 1))
            self.banana_node_path = self.banana.find('**/+CollisionNode')
            self.banana.reparentTo(self.base.render)
        elif fruit == 'cherry':
            # or cherry as banana?
            self.banana = self.base.render.attachNewNode('root')
            # banana center is off, re-center with new node
            new_node_path = self.base.loader.loadModel("models/fruit/cherries_no_cn.egg")
            new_node_path.reparentTo(self.banana)
            new_node_path.setPos(0, 0, 0)
            #new_node_path.setScale(0.08)
            self.banana.setScale(0.08)  # cherry
            # move the center of the cherries
            self.banana.setPos(Point3(0.08, 0, 1))
            # can't get built in cherry collision node to work properly...
            cs = CollisionSphere(-10, 0, 0, 11)
            self.banana_node_path = new_node_path.attachNewNode(CollisionNode('c_node'))
            self.banana_node_path.node().addSolid(cs)

        # usually 0.1 for banana
        # self.banana_node_path = self.banana.find('**/+CollisionNode')
        # self.banana_node_path.setScale(1)
        self.banana_mask = BitMask32(0x1)
        # banana intoCollideMask will change depending on which level we
        # are training on.
        self.banana_coll_node = self.banana_node_path.node()
        self.banana_coll_node.setIntoCollideMask(self.mask_list[0])

    def open_data_file(self, config):
        # open file for recording eye data
        data_dir = 'data/' + config['subject']
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
        self.data_file_name = data_dir + '/' + config['subject'] + '_TR_' + \
                              datetime.datetime.now().strftime("%y_%m_%d_%H_%M")
        sys.stdout.write('data file: ' + str(self.data_file_name) + '\n')
        # open file for recording eye positions
        self.data_file = open(self.data_file_name, 'w')
        self.data_file.write('timestamp, joystick input, for subject: ' + config['subject'] + '\n')

    # Closing methods
    def close_files(self):
        self.data_file.close()

    def close(self):
        if not unittest:
            self.close_files()
        sys.exit()

    def setup_inputs(self):
        self.accept('x_axis', self.move, ['x'])
        self.accept('y_axis', self.move, ['y'])
        self.accept('arrow_right', self.move, ['x_key', 0.5])
        self.accept('arrow_left', self.move, ['x_key', -0.5])
        self.accept('arrow_right-up', self.move, ['x_key', 0])
        self.accept('arrow_left-up', self.move, ['x_key', 0])
        self.accept('arrow_right-repeat', self.move, ['x_key', 0.5])
        self.accept('arrow_left-repeat', self.move, ['x_key', -0.5])
        self.accept('arrow_up', self.move, ['y_key', -0.5])
        self.accept('arrow_up-up', self.move, ['y_key', 0])
        self.accept('arrow_up-repeat', self.move, ['y_key', -0.5])
        self.accept('q', self.close)
        self.accept('w', self.inc_reward)
        self.accept('s', self.dec_reward)
        self.accept('e', self.inc_angle)
        self.accept('d', self.dec_angle)
        self.accept('t', self.inc_level)
        self.accept('g', self.dec_level)
        self.accept('y', self.inc_wrong_speed)
        self.accept('h', self.dec_wrong_speed)
        self.accept('u', self.inc_random)
        self.accept('j', self.dec_random)
        self.accept('i', self.inc_forward_speed)
        self.accept('k', self.dec_forward_speed)
        self.accept('r', self.change_right)
        self.accept('l', self.change_left)
        self.accept('space', self.extra_reward)

    @staticmethod
    def make_coll_node_path(node_path, solid):
        # Creates a collision node and attaches the collision solid to the
        # supplied NodePath. Returns the nodepath of the collision node.

        # Creates a collision node named after the name of the NodePath.
        coll_node = CollisionNode("%s c_node" % node_path.getName())
        coll_node.addSolid(solid)
        collision_node_path = node_path.attachNewNode(coll_node)
        # Show the collision node, which makes the solids show up.
        # actually, it appears to do nothing...
        # collision_node_path.show()
        return collision_node_path
예제 #20
0
class Physics:
    def __init__(self):
        self.rayCTrav = CollisionTraverser("collision traverser for ray tests")
        #self.pusher = PhysicsCollisionHandler()
        self.pusher = CollisionHandlerPusher()
        self.pusher.addInPattern('%fn-in-%in')
        self.pusher.addOutPattern('%fn-out-%in')
        self.pusher.addInPattern('%fn-in')
        self.pusher.addOutPattern('%fn-out')

    def startPhysics(self):
        #self.actorNode = ActorNode("playerPhysicsControler")
        #base.physicsMgr.attachPhysicalNode(self.actorNode)
        #self.actorNode.getPhysicsObject().setMass(self.player_mass)
        #self.mainNode = render.attachNewNode(self.actorNode)
        self.mainNode = render.attachNewNode("CharacterColliders")
        self.reparentTo(self.mainNode)

        charCollisions = self.mainNode.attachNewNode(
            CollisionNode(self.char_collision_name))
        #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0, self.player_height/4.0))
        #charCollisions.node().addSolid(CollisionSphere(0, 0, self.player_height/4.0*3.05, self.player_height/4.0))
        charCollisions.node().addSolid(
            CollisionSphere(0, 0, self.player_height / 2.0,
                            self.player_height / 4.0))
        charCollisions.node().setIntoCollideMask(BitMask32(0x80))  # 1000 0000
        if self.show_collisions:
            charCollisions.show()
        self.pusher.addCollider(charCollisions, self.mainNode)
        base.cTrav.addCollider(charCollisions, self.pusher)

        charFFootCollisions = self.attachNewNode(CollisionNode("floor_ray"))
        charFFootCollisions.node().addSolid(CollisionRay(0, 0, 0.5, 0, 0, -1))
        #charFFootCollisions.node().addSolid(CollisionSegment((0, 0, 0.2), (0, 0, -1)))
        charFFootCollisions.node().setIntoCollideMask(BitMask32.allOff())
        charFFootCollisions.node().setFromCollideMask(
            BitMask32(0x7f))  # 0111 1111
        if self.show_collisions:
            charFFootCollisions.show()

        self.floor_handler = CollisionHandlerFloor()
        self.floor_handler.addCollider(charFFootCollisions, self.mainNode)
        #self.floor_handler.setOffset(0)
        self.floor_handler.setMaxVelocity(5)
        base.cTrav.addCollider(charFFootCollisions, self.floor_handler)

        self.accept("{}-in".format(self.char_collision_name),
                    self.checkCharCollisions)

        self.raytest_segment = CollisionSegment(0, 1)
        self.raytest_np = render.attachNewNode(CollisionNode("testRay"))
        self.raytest_np.node().addSolid(self.raytest_segment)
        self.raytest_np.node().setIntoCollideMask(BitMask32.allOff())
        self.raytest_np.node().setFromCollideMask(BitMask32(0x7f))  # 0111 1111
        if self.show_collisions:
            self.raytest_np.show()

        self.raytest_queue = CollisionHandlerQueue()
        self.rayCTrav.addCollider(self.raytest_np, self.raytest_queue)

    def stopPhysics(self):
        self.raytest_segment.removeNode()
        self.pusher.clearColliders()
        self.floor_handler.clearColliders()
        self.rayCTrav.clearColliders()

    def updatePlayerPos(self, speed, heading, dt):
        if heading is not None:
            self.mainNode.setH(camera, heading)
            self.mainNode.setP(0)
            self.mainNode.setR(0)
        self.mainNode.setFluidPos(self.mainNode, speed)
        self.doStep()

    def checkCharCollisions(self, args):
        self.doStep()

    def doStep(self):
        # do the step height check
        tmpNP = self.mainNode.attachNewNode("temporary")
        tmpNP.setPos(self.mainNode, 0, 0, -self.stepheight)
        pointA = self.mainNode.getPos(render)
        pointA.setZ(pointA.getZ() + self.player_height / 1.8)
        pointB = tmpNP.getPos(render)
        if pointA == pointB: return
        char_step_collision = self.getFirstCollisionInLine(pointA, pointB)
        tmpNP.removeNode()
        if char_step_collision is not None:
            self.mainNode.setFluidZ(char_step_collision.getZ())
            return True
        return False

    def getFirstCollisionInLine(self, pointA, pointB):
        """A simple raycast check which will return the first collision point as
        seen from point A towards pointB"""
        self.raytest_segment.setPointA(pointA)
        self.raytest_segment.setPointB(pointB)
        self.rayCTrav.traverse(render)
        self.raytest_queue.sortEntries()
        pos = None
        if self.raytest_queue.getNumEntries() > 0:
            pos = self.raytest_queue.getEntry(0).getSurfacePoint(render)
        return pos
예제 #21
0
class Enemy():
    def __init__(self, pos, index, app, manager, level, style):
        self.position = pos
        self.app = app
        self.np = app.render.attachNewNode("enemy%d" % index)

        if style == 1:
            self.np.setColorScale(1.0, 1.0, 1.0, 1.0)
            self.movespeed = 2.5
            self.max_movespeed = 30
        else:
            self.movespeed = 0.5
            self.max_movespeed = 25

        if style == 2:
            self.activate_delay = 0.01
            self.np.setColorScale(0.6, 1.0, 1.0, 1.0)
        else:
            self.activate_delay = 0.1

        if style == 3:
            self.hp = 50 * level
            self.np.setColorScale(0.0, 1.0, 0.5, 1.0)
        else:
            self.hp = 100 * level

        if style == 4:
            self.damage = 20
            self.np.setColorScale(1.0, 1.0, 0.0, 1.0)
        else:
            self.damage = 10

        self.dead = 0.0
        self.level = level
        self.style = style
        self.particle_clean = False

        # this allows us to detach the instance nodepath
        # on death, but keep one with no model to attach particle effects
        self.dnp = app.render.attachNewNode("enemy_top%d" % index)

        self.np.setPos(self.position)

        self.np.setHpr(uniform(1,360),0,0)
        self.np.setScale(level)

        colsize = 3.0
        self.cn = self.np.attachNewNode(CollisionNode('enemy_cn_%d' % index))
        self.cs0 = CollisionSphere(0.0, colsize/2,0.0,colsize)
        self.cs1 = CollisionSphere(0.0, -colsize/2,0.0,colsize)
        self.cs2 = CollisionSphere(0.0, -colsize/3*4,0.0,colsize/2)
        self.cn.node().addSolid(self.cs0)
        self.cn.node().addSolid(self.cs1)
        self.cn.node().addSolid(self.cs2)
        #self.cn.show() # debug

        self.cqueue = CollisionHandlerQueue()
        app.cTrav.addCollider(self.cn, self.cqueue)

        self.cn.node().setIntoCollideMask(BitMask32(0x01))
        self.cn.node().setFromCollideMask(BitMask32(0x10))

        self.last_activated = 0.0

        manager.add_instance(self)


        # name, nodepath, mass, move_force, max_force
        self.ai_char = AICharacter('enemy_ai_%d' % index, self.np, 100, self.movespeed, self.max_movespeed)
        app.ai_world.addAiChar(self.ai_char)
        self.ai_b = self.ai_char.getAiBehaviors()
        self.ai_b.pursue(app.player.np)

        self.load_particle_config()
    
    def update(self, time):

        a = 0
        # Handle collsions
        for i in range(self.cqueue.getNumEntries()):
           collided_name = self.cqueue.getEntry(i).getIntoNodePath().getName()
           #handle bullets
           if collided_name[0] == 'b': 
               bullet = self.app.bullet_manager.get_bullet(collided_name)
               bullet.apply_effect(self)
               self.app.bullet_manager.remove_bullet(collided_name)

        if self.cqueue.getNumEntries() != 0:
            self.np.setColorScale(1.0, self.hp / 100.0, self.hp / 100.0, 1.0)
       
        """
        desired = self.app.player.position - self.np.getPos()
        angle = degrees(atan2(desired.y, desired.x))
        
        hpr = self.np.getHpr()
        if hpr.x > 360:
            hpr.x = hpr.x - 360
        if hpr.x < -360:
            hpr.x = hpr.x + 360

        diff = angle - hpr.x 

        if diff > 180.0:
            diff = diff - 360

        if diff < -180.0:
            diff = diff + 360

        if diff > 5.0:
            diff = 5.0
        if diff < -5.0:
            diff = -5.0

        new = Vec3(diff, 0, 0) + hpr
        #self.np.setHpr(new)
        
        # move forward
        r = radians(new.x)
        curr = self.np.getPos()
        diff = Vec3(self.movespeed * cos(r), self.movespeed * sin(r), 0)
        self.np.setPos(curr + diff)"""

        if self.hp < 0.0 and self.dead == 0.0:
            self.dead = time 
            self.app.scene.remove(self)
            # Create particle effect before we go
            self.dnp.setPos(self.np.getPos())
            self.particles.start(parent = self.dnp, renderParent = self.app.render)
            self.np.detachNode()

            # Drop some loot
            self.app.item_manager.add_item(self.np.getPos(), "soul", self.level)
            # Give the player some points
            self.app.player.score = self.app.player.score + 100

    def apply_effect(self, target, timer):
        if self.last_activated - timer + self.activate_delay < 0.0:
            self.last_activated = timer
            target.hp = target.hp - self.damage
        if target.np.getName()[0] == 't':
            target.pursuers.append(self)
            #self.ai_b = self.ai_char.getAiBehaviors()
            #self.ai_b.pursue(self.np.getPos())
            self.ai_b.pauseAi("pursue")

    def load_particle_config(self):
        self.particles = ParticleEffect()
        self.particles.reset()
        self.particles.setPos(0.000, 0.000, 0.000)
        self.particles.setHpr(0.000, 0.000, 0.000)
        self.particles.setScale(1.000, 1.000, 1.000)
        p0 = Particles('particles-1')
        # Particles parameters
        p0.setFactory("PointParticleFactory")
        p0.setRenderer("SpriteParticleRenderer")
        p0.setEmitter("SphereVolumeEmitter")
        p0.setPoolSize(20)
        p0.setBirthRate(0.0100)
        p0.setLitterSize(20)
        p0.setLitterSpread(0)
        p0.setSystemLifespan(1.0100)
        p0.setLocalVelocityFlag(1)
        p0.setSystemGrowsOlderFlag(1)
        # Factory parameters
        p0.factory.setLifespanBase(1.0000)
        p0.factory.setLifespanSpread(0.0000)
        p0.factory.setMassBase(1.0000)
        p0.factory.setMassSpread(0.0100)
        p0.factory.setTerminalVelocityBase(1200.0000)
        p0.factory.setTerminalVelocitySpread(0.0000)
        # Point factory parameters
        # Renderer parameters
        p0.renderer.setAlphaMode(BaseParticleRenderer.PRALPHAOUT)
        p0.renderer.setUserAlpha(0.05)
        # Sprite parameters
        p0.renderer.setTexture(self.app.loader.loadTexture('effects/dust.png'))
        p0.renderer.setColor(Vec4(1.00, 0.10, 0.10, 0.50))
        p0.renderer.setXScaleFlag(2)
        p0.renderer.setYScaleFlag(2)
        p0.renderer.setAnimAngleFlag(0)
        p0.renderer.setInitialXScale(0.100 * self.level)
        p0.renderer.setFinalXScale(0.200 * self.level)
        p0.renderer.setInitialYScale(0.100 * self.level)
        p0.renderer.setFinalYScale(0.200 * self.level)
        p0.renderer.setNonanimatedTheta(0.0000)
        p0.renderer.setAlphaBlendMethod(BaseParticleRenderer.PPBLENDLINEAR)
        p0.renderer.setAlphaDisable(0)
        # Emitter parameters
        p0.emitter.setEmissionType(BaseParticleEmitter.ETRADIATE)
        p0.emitter.setAmplitude(1.0000)
        p0.emitter.setAmplitudeSpread(0.0000)
        p0.emitter.setOffsetForce(Vec3(0.0000, 0.0000, 0.0000))
        p0.emitter.setExplicitLaunchVector(Vec3(1.0000, 0.0000, 0.0000))
        p0.emitter.setRadiateOrigin(Point3(0.0000, 0.0000, 0.0000))
        # Sphere Volume parameters
        p0.emitter.setRadius(0.1000)
        self.particles.addParticles(p0)
        f0 = ForceGroup('gravity')
        # Force parameters
        self.particles.addForceGroup(f0)
예제 #22
0
class PlayerInput(DirectObject):
	
	"""
	PlayerInput Class:
	Handels all inputs.
	"""
	
	def __init__(self):
		
		# Should make a method to get active players.
		self.activePlayer = ACTIVE_ACTORS['Player'].playerActor
		self.activePlayerSpeed = ACTIVE_ACTORS['Player'].playerSpeed
		
		# Set the control maps.
		self.controlMap = {"left": 0, "right": 0, "forward": 0, "backward": 0, "jump": 0, "wheel-in": 0, "wheel-out": 0}  
		self.mousebtn = [0, 0, 0]
		
		# Create a floater object.  We use the "floater" as a temporary
		# variable in a variety of calculations.
		self.floater = NodePath(PandaNode("floater"))
		self.floater.reparentTo(render)
		
		### SETUP KEYBOARD ###
		# Setup the control [KEYS] for movement w,a,s,d.
		self.accept("escape", sys.exit)
		self.accept("w", self.setControl, ["forward", 1])
		self.accept("a", self.setControl, ["left", 1])
		self.accept("s", self.setControl, ["backward", 1])
		self.accept("d", self.setControl, ["right", 1])
		self.accept("space", self.setControl, ["jump", 1])
		
		self.accept("w-up", self.setControl, ["forward", 0])
		self.accept("a-up", self.setControl, ["left", 0])
		self.accept("s-up", self.setControl, ["backward", 0])
		self.accept("d-up", self.setControl, ["right", 0])
		self.accept("space-up", self.setControl, ["jump", 0])
		
		# Setup mouse [ZOOM].
		self.accept("wheel_up", self.setControl, ["wheel-in", 1])
		self.accept("wheel_down", self.setControl, ["wheel-out", 1])
		
		# Add the "moveTask"
		taskMgr.add(self.move, "moveTask")
		
		# Game State Variable.
		self.isMoving = False
		###>
		
		###  SETUP CAMERA  ###
		# Reparent the -main- Camera to playerActor.
		base.camera.reparentTo(self.activePlayer)
		self.cameraTargetHeight = 6.0
		self.cameraDistance = 30
		self.cameraPitch = 10 
		base.disableMouse()
		# This should be used together with a right click function, for the camera rotate. Like in wow.
		WinProps = WindowProperties()
		# Hide the cursor. | This will change with the rightClick function. 
		# Giving us the cursor when not rotating. If the player wants to rotate basic [KEYS] left/right can turn while cursor is active.
		WinProps.setCursorHidden(True) 
		base.win.requestProperties(WinProps)
		#base.camera.setPos(self.activePlayer.getX(),self.activePlayer.getY()+10,2)
		
		# FROM THE ROAMING RALPH TUT>
		# 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.actorGroundRay = CollisionRay()
		self.actorGroundRay.setOrigin(0,0,1000)
		self.actorGroundRay.setDirection(0,0,-1)
		self.actorGroundCol = CollisionNode('actorRay')
		self.actorGroundCol.addSolid(self.actorGroundRay)
		self.actorGroundCol.setFromCollideMask(BitMask32.bit(0))
		self.actorGroundCol.setIntoCollideMask(BitMask32.allOff())
		self.actorGroundColNp = self.activePlayer.attachNewNode(self.actorGroundCol)
		self.actorGroundHandler = CollisionHandlerQueue()
		cTrav.addCollider(self.actorGroundColNp, self.actorGroundHandler)

		# We will detect anything obstructing the camera's view of the player 
 
		self.cameraRay = CollisionSegment((0,0,self.cameraTargetHeight),(0,5,5)) 
		self.cameraCol = CollisionNode('cameraRay') 
		self.cameraCol.addSolid(self.cameraRay) 
		self.cameraCol.setFromCollideMask(BitMask32.bit(0)) 
		self.cameraCol.setIntoCollideMask(BitMask32.allOff()) 
		self.cameraColNp = self.activePlayer.attachNewNode(self.cameraCol) 
		self.cameraColHandler = CollisionHandlerQueue() 
		cTrav.addCollider(self.cameraColNp, self.cameraColHandler) 

		# Uncomment this line to see the collision rays
		self.actorGroundColNp.show()
		self.cameraColNp.show()
	   
		# Uncomment this line to show a visual representation of the 
		# collisions occuring
		cTrav.showCollisions(render)
		
		###>
		
	# Check the state of the KB.
	def setControl(self, key, value):
		self.controlMap[key] = value
		
	def move(self, task):
		
		self.actorPos = self.activePlayer.getPos()
		# Check if a-move key is pressed, if so move.
		# Forward.
		if (self.controlMap["forward"] != 0):
			self.activePlayer.setY(self.activePlayer, -self.activePlayerSpeed * globalClock.getDt())
		# Backward.
		if (self.controlMap["backward"] != 0):
			self.activePlayer.setY(self.activePlayer, self.activePlayerSpeed * globalClock.getDt())
		# Left.
		if (self.controlMap["left"] != 0):
			self.activePlayer.setX(self.activePlayer, self.activePlayerSpeed * globalClock.getDt())
		# Right.
		if (self.controlMap["right"] != 0):
			self.activePlayer.setX(self.activePlayer, -self.activePlayerSpeed * globalClock.getDt())
			
		if (self.controlMap["jump"] != 0):
			print "Jump now...!?"
		
		# Check for zooming and Do.
		if (self.controlMap["wheel-in"] != 0):
			self.cameraDistance -= 0.1 * self.cameraDistance
			if  (self.cameraDistance < 5):
				self.cameraDistance = 5
			self.controlMap["wheel-in"] = 0
		
		elif (self.controlMap["wheel-out"] != 0):
			self.cameraDistance += 0.1 * self.cameraDistance
			if (self.cameraDistance > 250):
				self.cameraDistance = 250
			self.controlMap["wheel-out"] = 0
			
		# Make use of mouse, to turn.
		if base.mouseWatcherNode.hasMouse():
			
			# get changes in mouse position
			md = base.win.getPointer(0)
			x = md.getX()
			y = md.getY()
			
			deltaX = md.getX() - 200
			deltaY = md.getY() - 200
			
			# reset mouse cursor position
			base.win.movePointer(0, 200, 200)
			
			# Mouse speed setting
			mouseSpeed = 0.3
			
			# alter the actor yaw by an amount proportionate to deltaX
			self.activePlayer.setH(self.activePlayer.getH() - mouseSpeed* deltaX)

			# find the new camera pitch and clamp it to a reasonable range
			self.cameraPitch = self.cameraPitch + 0.1 * deltaY
			if (self.cameraPitch < -60): self.cameraPitch = -60
			if (self.cameraPitch >  80): self.cameraPitch =  80
			base.camera.setHpr(0,self.cameraPitch,0)
			
			# set the camera at around middle of the ship
			# We should pivot around here instead of the view target which is noticebly higher
			base.camera.setPos(0,0,self.cameraTargetHeight/2)
			# back the camera out to its proper distance
			base.camera.setY(base.camera,self.cameraDistance)
		
		# point the camera at the view target 
		viewTarget = Point3(0,0,self.cameraTargetHeight) 
		base.camera.lookAt(viewTarget) 
		# reposition the end of the  camera's obstruction ray trace 
		self.cameraRay.setPointB(base.camera.getPos())
		
		# If ralph is moving, loop the run animation.
		# If he is standing still, stop the animation.

		if (self.controlMap["forward"]!=0) or (self.controlMap["left"]!=0) or (self.controlMap["right"]!=0):
			if self.isMoving is False:
				self.activePlayer.loop("run")
				self.isMoving = True
		else:
			if self.isMoving:
				self.activePlayer.stop()
				self.activePlayer.pose("walk",5)
				self.isMoving = False
		
		# Now check for collisions.

		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.actorGroundHandler.getNumEntries()):
			entry = self.actorGroundHandler.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() == "ground"):
			self.activePlayer.setZ(entries[0].getSurfacePoint(render).getZ())
		else:
			self.activePlayer.setPos(self.actorPos)
		
		# Go through the BALL_DICT which is not a list and needs a new name :P 
		# And find the ball being colided with. and then del. it
		for ball in BALL_LIST:
			if (len(entries)>0) and (entries[0].getIntoNode().getName() == str(ball)):
				print "Collide with ", entries[0].getIntoNode().getName()
				del BALL_LIST[ball]
				BALL_LIST[ball] = None



		# Keep the camera at one foot above the terrain,
		# or two feet above ralph, whichever is greater.
		
		entries = [] 
		for i in range(self.cameraColHandler.getNumEntries()): 
			entry = self.cameraColHandler.getEntry(i) 
			entries.append(entry) 
		entries.sort(lambda x,y: cmp(-y.getSurfacePoint(self.activePlayer).getY(), 
									 -x.getSurfacePoint(self.activePlayer).getY())) 
		if (len(entries)>0): 
			collisionPoint =  entries[0].getSurfacePoint(self.activePlayer) 
			collisionVec = ( viewTarget - collisionPoint) 
			if ( collisionVec.lengthSquared() < self.cameraDistance * self.cameraDistance ): 
				base.camera.setPos(collisionPoint) 
				if (entries[0].getIntoNode().getName() == "ground"): 
					base.camera.setZ(base.camera, 0.2) 
				base.camera.setY(base.camera, 0.3) 
				
		return task.cont   
예제 #23
0
class World(DirectObject):
    def __init__(self):
        ## Add the default values to the dictionary.
        self.keyMap = {"left":0, "right":0, "forward":0, \
                       "boost":0, "strafeL":0, "strafeR":0, \
                       "cam-left":0, "cam-right":0}

        base.win.setClearColor(Vec4(0, 0, 0, 1))
        self.jump = False
        self.jumped = False

        # Post the instructions
        self.title = addTitle(
            "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward")
        self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left")
        self.inst7 = addInstructions(0.65, "[D]: Rotate Camera Right")
        self.inst8 = addInstructions(0.60, "[B]: Ralph Boost")
        self.inst9 = addInstructions(0.55, "[V]: Strafe Left")
        self.inst10 = addInstructions(0.50, "[N]: Strafe Right")

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)
        self.environ.setPos(0, 0, 0)

        ## Stops the sound as soon as the world renders
        ## Note:Sound won't play very long becasue the game takes seconds to compile and load
        ## Remove loading screen after world is rendered and ready to go.

        loadingText.cleanup()
        mySound.stop()

        # Create the main character, Ralph

        ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor("models/ralph", {
            "run": "models/ralph-run",
            "walk": "models/ralph-walk"
        })
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos)

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("arrow_up", self.setKey, ["forward", 1])
        self.accept("a", self.setKey, ["cam-left", 1])
        self.accept("d", self.setKey, ["cam-right", 1])
        self.accept("b", self.setKey, ["boost", 1])
        self.accept("v", self.setKey, ["strafeL", 1])
        self.accept("n", self.setKey, ["strafeR", 1])

        ## -up to signify what happens when you let go of the key
        self.accept("b-up", self.setKey, ["boost", 0])
        self.accept("v-up", self.setKey, ["strafeL", 0])
        self.accept("n-up", self.setKey, ["strafeR", 0])
        self.accept("arrow_left-up", self.setKey, ["left", 0])
        self.accept("arrow_right-up", self.setKey, ["right", 0])
        self.accept("arrow_up-up", self.setKey, ["forward", 0])
        self.accept("a-up", self.setKey, ["cam-left", 0])
        self.accept("d-up", self.setKey, ["cam-right", 0])

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera

        base.disableMouse()
        base.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2)

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

        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 1000)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 1000)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

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

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

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

    def setZ(self, task):
        x = self.ralph.getX()
        y = self.ralph.getY()
        z = self.ralph.getZ()
        self.ralph.setPos(x, y, 0)
        self.jumped = False

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

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        base.camera.lookAt(self.ralph)
        if (self.keyMap["cam-left"] != 0):
            base.camera.setX(base.camera, -50 * globalClock.getDt())

        # Increased camera rotation speed to match rotation speed of Ralph
        if (self.keyMap["cam-right"] != 0):
            base.camera.setX(base.camera, +50 * globalClock.getDt())

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

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if (self.keyMap["left"] != 0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"] != 0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"] != 0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())
        ## What to do if b was pressed?
        if (self.keyMap["boost"] != 0):
            self.jump = True

        # What to do if n is pressed
        # Ralph will strafe right. If b is also pressed, Ralph will strafe to the right quicker
        if (self.keyMap["strafeR"] != 0):
            self.ralph.setX(self.ralph, -25 * globalClock.getDt())
        if (self.keyMap["strafeL"] != 0):
            self.ralph.setX(self.ralph, 25 * globalClock.getDt())

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        # Function to make Ralph jump up the y-axis and fall back down
        # when 'j' is released

        ## Add boost, strafeL, and strafeR to the animation alteration conditions here.
        if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) \
           or (self.keyMap["right"]!=0) or (self.keyMap["boost"]!=0) \
           or (self.keyMap["strafeL"]!=0) or (self.keyMap["strafeR"]!=0):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec * (5 - camdist))
            camdist = 5.0

        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(
            y.getSurfacePoint(render).getZ(),
            x.getSurfacePoint(render).getZ()))
        if (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                   == "terrain"):
            if self.jump is True:
                self.ralph.setZ(entries[0].getSurfacePoint(render).getZ() + 1)
                self.jumped = True
                self.jump = False
            else:
                if self.jumped is True:
                    taskMgr.doMethodLater(0.1, self.setZ, 'setZ')
                else:
                    self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())

        else:
            self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.

        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(
            y.getSurfacePoint(render).getZ(),
            x.getSurfacePoint(render).getZ()))
        if (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                   == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.camera.setZ(self.ralph.getZ() + 2.0)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.

        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        return task.cont
예제 #24
0
class World(DirectObject):



    def __init__(self):
        #Let's start the Music
        mySound = base.loader.loadSfx("music/music.mp3")
        mySound.setLoopCount(0) #And Keep it On Loop
        mySound.play()
       

        base.setFrameRateMeter(True) #Shows the FrameRate in The Top Corner

        self.walking = Vec3()
        self.isMoving = False
        self.dest = None
        base.win.setClearColor(Vec4(0,0,0,1))


        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0}
        base.win.setClearColor(Vec4(0,0,0,1))

        #Here is the number of collectibles in the game
        
        self.rare = 1; 
        self.vasenum = 10;
        self.coinnum = 30;
        self.silvernum = 5;
        self.chestnum = 2;

        #Here is the Obstacles in the game
        self.rocknum = 500;

        #Here is the Score
        self.score = 0;

        #Here is the total Number of Objects to collect
        self.numObjects = self.rare + self.vasenum + self.coinnum + self.silvernum + self.chestnum
   
        # print the number of objects
        printNumObj(self.score)

        # Post the instructions
        self.title = addTitle("Mighty Mountain")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[A]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.85, "[D]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.80, "[W]: Run Ralph Forward")
        self.inst5 = addInstructions(0.75, "[S]: Run Ralph Backward")
        self.inst6 = addInstructions(0.70, "[Space]: Run, Ralph, Run")
        
        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.  

        self.environ = loader.loadModel("models/world")      
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)
        
        # Timer to increment in the move task
        self.time = 0
        
        # Get bounds of environment
        min, max = self.environ.getTightBounds()
        self.mapSize = max-min
        
        # Create the main character, Ralph
        self.ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor("models/ralph",
                                 {"run":"models/ralph-run",
                                  "walk":"models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(self.ralphStartPos)


        # ralph's stamina
        self.stamina = 200
        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation
        self.accept("escape", self.endgame)
        
        # these don't work well in combination with the space bar
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_down", self.setKey, ["backward",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("arrow_down-up", self.setKey, ["backward",0])
        
        self.accept("space", self.runRalph, [True])
        self.accept("space-up", self.runRalph, [False])
        
        self.accept("a", self.setKey, ["left",1])
        self.accept("d", self.setKey, ["right",1])
        self.accept("w", self.setKey, ["forward",1])
        self.accept("s", self.setKey, ["backward",1])
        self.accept("a-up", self.setKey, ["left",0])
        self.accept("d-up", self.setKey, ["right",0])
        self.accept("w-up", self.setKey, ["forward",0])
        self.accept("s-up", self.setKey, ["backward",0])

        # Game state variables
        self.isMoving = False
        self.isRunning = False

        # Set up the camera
        base.disableMouse()
        #base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,2)
        base.camera.setPos(0, 0, 0)
        base.camera.reparentTo(self.ralph)
        base.camera.setPos(0, 40, 2)
        base.camera.lookAt(self.ralph)
        
        # 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.

        base.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,300)
        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()
        base.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        # camera ground collision handler
        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0,0,300)
        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()
        base.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        
        # Place the collectibles
        self.placeCollectibles() #Platinum 
        self.placeVases()
        self.placeCoins()
        self.placeSilver()
        self.placeGold()
        self.placeChests()

        #Place the obstacles
        self.placeRocks() #Cactus 
       
        # Uncomment this line to show a visual representation of the 
        # collisions occuring
        #base.cTrav.showCollisions(render)
        
        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))
        
        taskMgr.add(self.move,"moveTask")


    #Reinitialize all necessary parts of the game
    def restart(self):

        #self.numObjects = 10
        self.score = 0
        printNumObj(self.score)
        self.ralph.setPos(self.ralphStartPos)
        self.stamina = 200
        self.time = 0
        base.camera.setPos(0, 0, 0)
        base.camera.reparentTo(self.ralph)
        base.camera.setPos(0, 40, 2)
        base.camera.lookAt(self.ralph)
        
        # Place the collectibles
        self.placeCollectibles() #Platinum 
        self.placeVases()
        self.placeCoins()
        self.placeSilver()
        self.placeGold()
        self.placeChests()

        #Place the obstacles
        self.placeRocks()

        #Total number of obstacles
        self.numObjects = self.rare + self.vasenum + self.coinnum + self.silvernum + self.chestnum

        taskMgr.add(self.move,"moveTask")
   
    
   
    # Display ralph's stamina
    def displayStamina(self):
        sprintBar['scale'] = (self.stamina*0.01*BAR_WIDTH,0.2,0.2)
    
#Collects the item and modifies score

    def collectCollectibles(self, entry): #Platinum 
        #Remove the collectible
        entry.getIntoNodePath().getParent().removeNode()
        # Update the number of objects
        self.score = self.score * self.numObjects + 500
        self.numObjects = self.numObjects - 1
        printNumObj(self.score)
        

    def collectVase(self, entry):
        # Remove the collectible
        entry.getIntoNodePath().getParent().removeNode()
        # Update the number of objects
        self.score = self.score + 10
        self.numObjects = self.numObjects - 1
        printNumObj(self.score)
    
    def collectCoins(self, entry):
        # Remove the collectible
        entry.getIntoNodePath().getParent().removeNode()
        # Update the number of objects
        self.score = self.score + 1
        printNumObj(self.score)
        self.numObjects = self.numObjects - 1


    def collectSilver(self, entry):
        # Remove the collectible
        entry.getIntoNodePath().getParent().removeNode()
        # Update the number of objects
        self.score = self.score + 20
        printNumObj(self.score)
        self.numObjects = self.numObjects - 1


    def collectGold(self, entry):
        # Remove the collectible
        entry.getIntoNodePath().getParent().removeNode()
        # Update the number of objects
        self.score = self.score + 30
        printNumObj(self.score)
        self.numObjects = self.numObjects - 1

    def collectChest(self, entry):
        # Remove the collectible
        entry.getIntoNodePath().getParent().removeNode()
        # Update the number of objects
        self.score = self.score + 100
        printNumObj(self.score)
        self.numObjects = self.numObjects - 1

#Unique function which handles collisions with a deduction obstacles.
    def deductRocks(self, entry):
        # Remove the collectible
        entry.getIntoNodePath().getParent().removeNode()
        # Update the number of objects
        if self.score > 500:
            randomnum = random.randint(1,2)
            if randomnum == 1:
             self.score = self.score - 100 #Removes Score
            if randomnum == 2:
             self.score = self.score + 100 #Removes Score

        if self.score < 500:
            self.score = self.score - 100

        randomnum = random.randint(1,2)

        if randomnum == 1:
            result =buttonbox(msg='A kind wizard wishes to help you on your quest? Trust him?', title='Alert!', choices=("Yes", "No"))

            if result == "Yes":
                othernum = random.randint(1,100)
                othernum = othernum * self.score + self.numObjects #Y = MX + B

                if othernum > 1000:
                    msgbox("Good choice! Add 1,000 Points to your Score!")
                    self.score = self.score + 1000
                if othernum < 1000:
                    msgbox("The wizard tricked you!He stole 100 Points!")
                    self.score = self.score - 100

        printNumObj(self.score)
      
      
        
    # Places an item randomly on the map    
    def placeItem(self, item):
        # Add ground collision detector to the health item
        self.collectGroundRay = CollisionRay()
        self.collectGroundRay.setOrigin(0,0,300)
        self.collectGroundRay.setDirection(0,0,-1)
        self.collectGroundCol = CollisionNode('colRay')
        self.collectGroundCol.addSolid(self.collectGroundRay)
        self.collectGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.collectGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.collectGroundColNp = item.attachNewNode(self.collectGroundCol)
        self.collectGroundHandler = CollisionHandlerQueue()
        base.cTrav.addCollider(self.collectGroundColNp, self.collectGroundHandler)
        
        placed = False;
        while placed == False:
            # re-randomize position
            item.setPos(-random.randint(0,140),-random.randint(0,40),0)
            
            base.cTrav.traverse(render)
            
            # Get Z position from terrain collision
            entries = []
            for j in range(self.collectGroundHandler.getNumEntries()):
                entry = self.collectGroundHandler.getEntry(j)
                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"):
                item.setZ(entries[0].getSurfacePoint(render).getZ()+1)
                placed = True
                
        # remove placement collider
        self.collectGroundColNp.removeNode()
    
   
#Places all obstacles on map.          
    def placeCollectibles(self):
        self.placeCol = render.attachNewNode("Collectible-Placeholder")
        self.placeCol.setPos(0,0,0)
        
        # Add the health items to the placeCol node
        for i in range(self.rare):
            # Load in the health item model
            self.collect = loader.loadModel("models/moneyBag")
            self.collect.setPos(0,0,0)
            self.collect.reparentTo(self.placeCol)
            
            self.placeItem(self.collect)
            
            # Add spherical collision detection
            colSphere = CollisionSphere(0,0,0,1)
            sphereNode = CollisionNode('colSphere')
            sphereNode.addSolid(colSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.collect.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)

    def placeVases(self):
        self.placeV = render.attachNewNode("Collectible-Placeholder")
        self.placeV.setPos(0,0,0)
        
        # Add the health items to the placeCol node
        for i in range(self.vasenum):
            # Load in the health item model
            self.collect = loader.loadModel("models/jar.egg")
            self.collect.setPos(0,0,0)
            self.collect.reparentTo(self.placeV)
            
            self.placeItem(self.collect)
            
            # Add spherical collision detection
            vaseSphere = CollisionSphere(0,0,0,1)
            sphereNode = CollisionNode('vaseSphere')
            sphereNode.addSolid(vaseSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.collect.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)

    def placeCoins(self):
        self.placeC = render.attachNewNode("Collectible-Placeholder")
        self.placeC.setPos(0,0,0)
        
        # Add the health items to the placeCol node
        for i in range(self.coinnum):
            # Load in the health item model
            self.collect = loader.loadModel("models/Cookie.egg")
            self.collect.setPos(0,0,0)
            self.collect.reparentTo(self.placeC)
            
            self.placeItem(self.collect)
            
            # Add spherical collision detection
            coinSphere = CollisionSphere(0,0,0,1)
            sphereNode = CollisionNode('coinSphere')
            sphereNode.addSolid(coinSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.collect.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)

    def placeSilver(self):
        self.placeS = render.attachNewNode("Collectible-Placeholder")
        self.placeS.setPos(0,0,0)
        
        # Add the health items to the placeCol node
        for i in range(self.silvernum):
            # Load in the health item model
            self.collect = loader.loadModel("models/Anvil.egg")
            self.collect.setPos(0,0,0)
            self.collect.reparentTo(self.placeS)
            
            self.placeItem(self.collect)
            
            # Add spherical collision detection
            silverSphere = CollisionSphere(0,0,0,1)
            sphereNode = CollisionNode('silverSphere')
            sphereNode.addSolid(silverSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.collect.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)

    def placeGold(self):
        self.placeG = render.attachNewNode("Collectible-Placeholder")
        self.placeG.setPos(0,0,0)
        
        # Add the health items to the placeCol node
        for i in range(self.silvernum):
            # Load in the health item model
            self.collect = loader.loadModel("models/key.egg")
            self.collect.setPos(0,0,0)
            self.collect.reparentTo(self.placeS)
            
            self.placeItem(self.collect)
            
            # Add spherical collision detection
            goldSphere = CollisionSphere(0,0,0,1)
            sphereNode = CollisionNode('goldSphere')
            sphereNode.addSolid(goldSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.collect.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)
    def placeChests(self):
        self.placeCh = render.attachNewNode("Collectible-Placeholder")
        self.placeCh.setPos(0,0,0)
        
        # Add the health items to the placeCol node
        for i in range(self.chestnum):
            # Load in the health item model
            self.collect = loader.loadModel("models/Keg.a2c.cr.egg")
            self.collect.setPos(0,0,0)
            self.collect.reparentTo(self.placeCh)
            
            self.placeItem(self.collect)
            
            # Add spherical collision detection
            chestSphere = CollisionSphere(0,0,0,1)
            sphereNode = CollisionNode('chestSphere')
            sphereNode.addSolid(chestSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.collect.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)

    def placeRocks(self):
        self.placeR = render.attachNewNode("Collectible-Placeholder")
        self.placeR.setPos(0,0,0)
        
        # Add the health items to the placeCol node
        for i in range(self.rocknum):
            # Load in the health item model
            self.collect = loader.loadModel("models/smallcactus.egg")
            self.collect.setScale(0.2)
            self.collect.setPos(0,0,0)
            self.collect.reparentTo(self.placeR)
            
            self.placeItem(self.collect)
            
            # Add spherical collision detection
            rockSphere = CollisionSphere(0,0,0,1)
            sphereNode = CollisionNode('rockSphere')
            sphereNode.addSolid(rockSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.collect.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)



        
    #Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value
    
    # Makes ralph's health decrease over time

    
    # Make ralph's stamina regenerate
    def staminaReg(self, task):
        if (self.stamina >= 200):
            self.stamina = 200
            return task.done
        else:
            self.stamina += 1
            task.setDelay(1)
            return task.again
        
    # Make ralph run
    def runRalph(self, arg):
        self.isRunning = arg
    
    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection


    def move(self, task):
        if self.score < 0:
            self.die()

        if self.numObjects == 0:
            self.endgame()

        randomnum1 = random.randint(1,1000)
        randomnum2 = randomnum1 * self.numObjects + self.score

        if randomnum1 == 1000:
            result =buttonbox(msg='An odd villager wishes to help you on your quest? Trust him?', title='Alert!', choices=("Yes", "No"))
            if result == "Yes":
                if randomnum2 > 20000:
                    msgbox("The villager grants you 4,000 Points!")
                    self.score = self.score + 4000
                if randomnum2 < 20000:
                    msgbox("The villager betrays you! He steal 200 points!")
                    self.score = self.score - 200

        
        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.
        startpos = self.ralph.getPos()
        
        # calculate ralph's speed
        if (self.isRunning and self.stamina > 0):
            taskMgr.remove("staminaTask")
            ralphSpeed = 45
            self.stamina -= 0.5
        else:
            taskMgr.doMethodLater(5, self.staminaReg, "staminaTask")
            ralphSpeed = 25

        # If a move-key is pressed, move ralph in the specified direction.
        # and rotate the camera to remain behind ralph
        if (self.keyMap["left"]!=0):
            self.ralph.setH(self.ralph.getH() + 100 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 100 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -ralphSpeed * globalClock.getDt())
        if (self.keyMap["backward"]!=0):
            self.ralph.setY(self.ralph, ralphSpeed *globalClock.getDt())

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.
        if ((self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) 
            or (self.keyMap["right"]!=0) or (self.keyMap["backward"]!=0)):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk",5)
                self.isMoving = False

        # so the following line is unnecessary
        base.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())
            #base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+5)

        #Adds all the items to the map and handles if they get hit.
        elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "colSphere"):
            self.collectCollectibles(entries[0])
        elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "vaseSphere"):
            self.collectVase(entries[0])
        elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "coinSphere"):
            self.collectCoins(entries[0])
        elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "silverSphere"):
            self.collectSilver(entries[0])
        elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "goldSphere"):
            self.collectGold(entries[0])
        elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "chestSphere"):
            self.collectChest(entries[0])
        elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "rockSphere"):
            self.deductRocks(entries[0])

        else:
            self.ralph.setPos(startpos)
        
        # Keep the camera above the terrain
        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"):
            modZ = entries[0].getSurfacePoint(render).getZ()
            base.camera.setZ(20.0+modZ+(modZ-self.ralph.getZ()))
        
        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ()+2.0)
        base.camera.lookAt(self.floater)
        
        self.displayStamina()

        return task.cont
    #If the user collects all items and/or ends the game through Escape.
    def endgame(self):
         # end all running tasks
        taskMgr.remove("moveTask")
        taskMgr.remove("healthTask")

        # Open database connection and inserts data.
        conn = MySQLdb.connect("sql5.freemysqlhosting.net","sql5106009","DFxbmhVkvG","sql5106009")
        cursor = conn.cursor()
        cursor.execute("INSERT INTO scores (score, username) VALUES (%s, %s)", (self.score, name))
        conn.commit()
        time.sleep(5) #Error without this...

        #Some text
        self.label = DirectLabel(text="End Game!",
                                      scale=.05, pos=(0,0,0.2))

        self.entry = DirectEntry(text="", scale=.05, initialText="",
                                    numLines=1, focus=1, pos=(-0.25,0,0))

        
   
        #Display high score

        self.highscore = OkDialog(dialogName="highscoreDialog", 
                                  text="Your High Score:\n\nName: " + name + "Score: " + str(self.score),
                                  command=sys.exit())

    # Restart or End?
    def die(self):
        # end all running tasks
        taskMgr.remove("moveTask")
        taskMgr.remove("healthTask")

        # Open database connection
        conn = MySQLdb.connect("sql5.freemysqlhosting.net","sql5106009","DFxbmhVkvG","sql5106009")
        cursor = conn.cursor()
        cursor.execute("INSERT INTO scores (score, username) VALUES (%s, %s)", (self.score, name))
        conn.commit()
        time.sleep(5)

        self.label = DirectLabel(text="Game over!",
                                      scale=.05, pos=(0,0,0.2))

        self.entry = DirectEntry(text="", scale=.05, initialText="",
                                    numLines=1, focus=1, pos=(-0.25,0,0))

        
   
        #Display high score

        self.highscore = OkDialog(dialogName="highscoreDialog", 
                                  text="Your High Score:\n\nName: " + name + " " + "Score: " + str(self.score),
                                  command=self.showDialog)


    def showDialog(self, arg):
        # cleanup highscore dialog
        self.highscore.cleanup()
        # display restart or exit dialog
        self.dialog = YesNoDialog(dialogName="endDialog",
                                   text="Would you like to continue?", 
                                   command=self.endResult)
    
    # Handle the dialog result
    def endResult(self, arg):
        if (arg):
            # cleanup the dialog box
            self.dialog.cleanup()
            # restart the game
            self.restart()
        else:
            sys.exit()
class DistributedLevel(DistributedObject):

    """ An instance of these is created and placed in the middle of
    the zone.  It serves to illustrate the creation of AI-side objects
    to populate the world, and a general mechanism for making them
    react to the avatars. """

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        #self.model = loader.loadModel('environment')
        #self.model.setZ(0)
        #self.builder = Builder(self, "map.txt", "development")


        plane = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0)))
        cnode = CollisionNode('cnode')
        cnode.setIntoCollideMask(BitMask32.bit(1))
        cnode.setFromCollideMask(BitMask32.bit(1))
        cnode.addSolid(plane)
        self.planeNP = self.model.attachNewNode(cnode)
        self.planeNP.show()

        # Setup a traverser for the picking collisions
        self.picker = CollisionTraverser()
        # Setup mouse ray
        self.pq = CollisionHandlerQueue()
        # Create a collision Node
        pickerNode = CollisionNode('MouseRay')
        # set the nodes collision bitmask
        pickerNode.setFromCollideMask(BitMask32.bit(1))
        # create a collision ray
        self.pickerRay = CollisionRay()
        # add the ray as a solid to the picker node
        pickerNode.addSolid(self.pickerRay)
        # create a nodepath with the camera to the picker node
        self.pickerNP = base.camera.attachNewNode(pickerNode)
        # add the nodepath to the base traverser
        self.picker.addCollider(self.pickerNP, self.pq)

        print "model loaded"
        #TODO: check how to load multiple levels and set players in specific levels!
        self.accept("mouse1", self.mouseClick)

    def announceGenerate(self):
        """ This method is called after generate(), after all of the
        required fields have been filled in.  At the time of this call,
        the distributed object is ready for use. """
        DistributedObject.announceGenerate(self)

        # Now that the object has been fully manifested, we can parent
        # it into the scene.
        print "render the model"
        self.model.reparentTo(render)

    def disable(self):
        # Take it out of the scene graph.
        self.detachNode()

        DistributedObject.disable(self)

    def checkMousePos(self, mpos, camPos, camHpr):
        lens = LenseNode.copyLens(base.camNode)
        lens.setPos(camPos)
        lens.setHpr(camHpr)
        help(mpos)
        mpos = Point2(mpos.x, mpos.y)
        pos = self.getClickPosition(mpos, lens)
        print "mouse clicked at:", pos

    def mouseClick(self):
        """Send an event to the server that will check where the mouse
        will hit and what action needs to be done"""
        hitPos = (0, 0, 0)
        # check if we have a mouse on the window
        if base.mouseWatcherNode.hasMouse():
            # get the mouse position on the screen
            mpos = base.mouseWatcherNode.getMouse()
            print mpos
            # set the ray's position
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            # Now call the traverse function to let the traverser check for collisions
            # with the added colliders and the levelNP
            self.picker.traverse(self.planeNP)
            # check if we have a collision
            if self.pq.getNumEntries() > 0:
                # sort the entries to get the closest first
                self.pq.sortEntries()
                # This is the point at where the mouse ray and the level plane intersect
                hitPos = self.pq.getEntry(0).getSurfacePoint(render)
        base.messenger.send("clickPosition", [hitPos])
예제 #26
0
파일: picker.py 프로젝트: westmark/redpanda
class MousePicker(object):
    def __init__(self, pickTag="MyPickingTag", nodeName="pickRay", showCollisions=False):
        self.pickTag = pickTag
        self.nodeName = nodeName
        self.showCollisions = showCollisions

    def create(self):
        self.mPickerTraverser = CollisionTraverser()
        self.mCollisionQue = CollisionHandlerQueue()

        self.mPickRay = CollisionRay()
        self.mPickRay.setOrigin(base.camera.getPos(base.render))
        self.mPickRay.setDirection(base.render.getRelativeVector(base.camera, Vec3(0, 1, 0)))

        # create our collison Node to hold the ray
        self.mPickNode = CollisionNode(self.nodeName)
        self.mPickNode.addSolid(self.mPickRay)

        # Attach that node to the camera since the ray will need to be positioned
        # relative to it, returns a new nodepath
        # well use the default geometry mask
        # this is inefficent but its for mouse picking only

        self.mPickNP = base.camera.attachNewNode(self.mPickNode)

        # we'll use what panda calls the "from" node.  This is reall a silly convention
        # but from nodes are nodes that are active, while into nodes are usually passive environments
        # this isnt a hard rule, but following it usually reduces processing

        # Everything to be picked will use bit 1. This way if we were doing other
        # collision we could seperate it, we use bitmasks to determine what we check other objects against
        # if they dont have a bitmask for bit 1 well skip them!
        self.mPickNode.setFromCollideMask(BitMask32(1))

        # Register the ray as something that can cause collisions
        self.mPickerTraverser.addCollider(self.mPickNP, self.mCollisionQue)

        # Setup 2D picker
        self.mPickerTraverser2D = CollisionTraverser()
        self.mCollisionQue2D = CollisionHandlerQueue()

        self.mPickNode2D = CollisionNode("2D PickNode")
        self.mPickNode2D.setFromCollideMask(BitMask32(1))
        self.mPickNode2D.setIntoCollideMask(BitMask32.allOff())

        self.mPick2DNP = base.camera2d.attachNewNode(self.mPickNode2D)

        self.mPickRay2D = CollisionRay()
        self.mPickNode2D.addSolid(self.mPickRay2D)

        self.mPickerTraverser2D.addCollider(self.mPick2DNP, self.mCollisionQue2D)

        if self.showCollisions:
            self.mPickerTraverser.showCollisions(base.render)
            self.mPickerTraverser2D.showCollisions(base.aspect2d)

    def mousePick(self, traverse=None, tag=None):
        # do we have a mouse
        if base.mouseWatcherNode.hasMouse() == False:
            return None, None

        traverse = traverse or base.render
        tag = tag or self.pickTag

        mpos = base.mouseWatcherNode.getMouse()

        # Set the position of the ray based on the mouse position
        self.mPickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
        self.mPickerTraverser.traverse(traverse)

        if self.mCollisionQue.getNumEntries() > 0:
            self.mCollisionQue.sortEntries()

            for entry in self.mCollisionQue.getEntries():
                pickedObj = entry.getIntoNodePath()
                pickedObj = pickedObj.findNetTag(tag)

                if not pickedObj.isEmpty():
                    pos = entry.getSurfacePoint(base.render)
                    return pickedObj, pos

        return None, None

    def mousePick2D(self, traverse=None, tag=None, all=False):
        # do we have a mouse
        if base.mouseWatcherNode.hasMouse() == False:
            return None, None

        traverse = traverse or base.render
        tag = tag or self.pickTag

        mpos = base.mouseWatcherNode.getMouse()

        self.mPickRay2D.setFromLens(base.cam2d.node(), mpos.getX(), mpos.getY())

        self.mPickerTraverser2D.traverse(base.aspect2d)

        if self.mCollisionQue2D.getNumEntries() > 0:
            self.mCollisionQue2D.sortEntries()

            if all:
                return (
                    [
                        (entry.getIntoNodePath().findNetTag(tag), entry.getSurfacePoint(base.aspect2d))
                        for entry in self.mCollisionQue2D.getEntries()
                    ],
                    None,
                )
            else:
                entry = self.mCollisionQue2D.getEntry(0)
                pickedObj = entry.getIntoNodePath()

                pickedObj = pickedObj.findNetTag(tag)
                if not pickedObj.isEmpty():
                    pos = entry.getSurfacePoint(base.aspect2d)
                    return pickedObj, pos

        return None, None
class LocationSeeker:
    def __init__(self, avatar, minDistance, maxDistance, shadowScale=1):
        self.dropShadowPath = 'phase_3/models/props/square_drop_shadow.bam'
        self.rejectSoundPath = 'phase_4/audio/sfx/ring_miss.ogg'
        self.moveShadowTaskName = 'Move Shadow'
        self.locationSelectedName = 'Location Selected'
        self.dropShadow = None
        self.shadowScale = shadowScale
        self.rejectSfx = loader.loadSfx(self.rejectSoundPath)
        self.avatar = avatar
        self.cameraNode = None
        self.cameraRay = None
        self.cameraNP = None
        self.shadowNP = None
        self.shadowRay = None
        self.minDistance = minDistance
        self.maxDistance = maxDistance
        self.legacyMode = False
        self.collHdlFl = CollisionHandlerQueue()
        self.moveShadowEventName = 'LocationSeeker-MoveShadow'
        return

    def startSeeking(self):
        if not self.avatar:
            return
        self.cleanupShadow()
        self.buildShadow()
        scale = self.dropShadow.getScale()
        if scale < 1.0:
            self.maxDistance += 40
        x, y, z = self.avatar.getPos(render)
        self.dropShadow.reparentTo(render)
        self.dropShadow.setPos(x, y + 5, z + 2)
        self.cameraNode = CollisionNode('coll_camera')
        self.cameraNode.setFromCollideMask(CIGlobals.WallBitmask)
        self.cameraRay = CollisionRay()
        self.cameraNode.addSolid(self.cameraRay)
        self.cameraNP = camera.attachNewNode(self.cameraNode)
        base.cTrav.addCollider(self.cameraNP, CollisionHandlerQueue())
        if not self.legacyMode:
            shadowNode = CollisionNode('coll_shadow')
            self.shadowRay = CollisionRay(0, 0, 6, 0, 0, -1)
            shadowNode.addSolid(self.shadowRay)
            shadowNode.setFromCollideMask(CIGlobals.FloorBitmask)
            self.shadowNP = self.dropShadow.attachNewNode(shadowNode)
            base.cTrav.addCollider(self.shadowNP, self.collHdlFl)
        base.taskMgr.add(self.__moveShadow, self.moveShadowTaskName)
        self.avatar.acceptOnce('mouse1', self.locationChosen)

    def stopSeeking(self):
        base.taskMgr.remove(self.moveShadowTaskName)

    def __moveShadow(self, task):
        if base.mouseWatcherNode.hasMouse():
            prevPos = self.dropShadow.getPos(render)

            def PointAtZ(z, point, vec):
                if vec.getZ() != 0:
                    return point + vec * ((z - point.getZ()) / vec.getZ())
                return self.getLocation()

            mouse = base.mouseWatcherNode.getMouse()
            self.cameraRay.setFromLens(base.camNode, mouse.getX(),
                                       mouse.getY())
            nearPoint = render.getRelativePoint(camera,
                                                self.cameraRay.getOrigin())
            nearVec = render.getRelativeVector(camera,
                                               self.cameraRay.getDirection())
            self.dropShadow.setPos(PointAtZ(0.5, nearPoint, nearVec))
            if (prevPos - self.dropShadow.getPos(render)).length() >= 0.25:
                messenger.send(self.moveShadowEventName)
            if self.legacyMode:
                self.dropShadow.setZ(base.localAvatar.getZ(render) + 0.5)
            elif self.collHdlFl.getNumEntries() > 0:
                self.dropShadow.setZ(
                    self.collHdlFl.getEntry(0).getSurfacePoint(render).getZ() +
                    0.5)
        return Task.cont

    def locationChosen(self):
        base.taskMgr.remove(self.moveShadowTaskName)
        distance = self.avatar.getDistance(self.dropShadow)
        x, y, z = self.getLocation()
        if distance >= self.minDistance and distance <= self.maxDistance:
            gag = self.avatar.getBackpack().getActiveGag()
            self.avatar.sendUpdate('setDropLoc', [gag.getID(), x, y, z])
            messenger.send(self.locationSelectedName)
        else:
            self.rejectSfx.play()
            self.avatar.acceptOnce('mouse1', self.locationChosen)
            base.taskMgr.add(self.__moveShadow, self.moveShadowTaskName)

    def buildShadow(self):
        self.cleanupShadow()
        if not self.dropShadowPath or not self.avatar:
            return
        self.dropShadow = loader.loadModel(self.dropShadowPath)
        self.dropShadow.setScale(self.shadowScale)
        self.dropShadow.setName('LocationSeeker_Shadow')

    def setShadowType(self, isCircle=False, scale=1):
        if not isCircle:
            self.dropShadowPath = 'phase_3/models/props/square_drop_shadow.bam'
        else:
            self.dropShadowPath = 'phase_3/models/props/drop_shadow.bam'
        self.shadowScale = scale

    def getDropShadow(self):
        return self.dropShadow

    def getLocation(self):
        if self.dropShadow:
            return self.dropShadow.getPos(render)
        return self.avatar.getPos(render)

    def getLocationSelectedName(self):
        return self.locationSelectedName

    def getShadowMovedName(self):
        return self.moveShadowEventName

    def cleanupShadow(self):
        if self.dropShadow:
            self.dropShadow.removeNode()
            self.dropShadow = None
            if self.cameraNode:
                self.cameraNP.removeNode()
                self.cameraNP = None
                self.cameraNode = None
                self.cameraRay = None
                self.shadowNP.removeNode()
                self.shadowRay = None
                self.shadowNP = None
                self.shadowSphNP = None
        return

    def cleanup(self):
        if self.avatar:
            base.taskMgr.remove(self.moveShadowTaskName)
            self.avatar.ignore('mouse1')
            self.cleanupShadow()
            self.rejectSfx.stop()
            self.rejectSfx = None
            self.avatar = None
            self.dropShadowPath = None
            self.rejectSoundPath = None
            self.locationSelectedName = None
            self.moveShadowTaskName = None
            self.moveShadowEventName = None
            self.collHdlFl = None
            del self.collHdlFl
            del self.minDistance
            del self.maxDistance
            del self.legacyMode
            del self.dropShadow
            del self.cameraNP
            del self.cameraNode
            del self.cameraRay
            del self.shadowNP
            del self.shadowRay
            del self.shadowSphNP
            del self.shadowScale
            del self.rejectSfx
            del self.avatar
            del self.dropShadowPath
            del self.rejectSoundPath
            del self.locationSelectedName
            del self.moveShadowTaskName
            del self.moveShadowEventName
        return
예제 #28
0
class HitscanWeapon(Weapon):
    def __init__(self, mask, damage, knockback, range=None):
        Weapon.__init__(self, mask, range, damage, knockback)

        if range is None:
            self.ray = CollisionRay(0, 0, 0, 0, 1, 0)
        else:
            self.ray = CollisionSegment(0, 0, 0, 1, 0, 0)

        rayNode = CollisionNode("playerRay")
        rayNode.addSolid(self.ray)

        rayNode.setFromCollideMask(mask)
        rayNode.setIntoCollideMask(0)

        self.rayNodePath = render.attachNewNode(rayNode)
        self.rayQueue = CollisionHandlerQueue()

        self.traverser = CollisionTraverser()
        self.traverser.addCollider(self.rayNodePath, self.rayQueue)

    def performRayCast(self, origin, direction):
        if isinstance(self.ray, CollisionRay):
            self.ray.setOrigin(origin)
            self.ray.setDirection(direction)
        else:
            self.ray.setPointA(origin)
            self.ray.setPointB(origin + direction * self.range)

        self.traverser.traverse(render)

        if self.rayQueue.getNumEntries() > 0:
            self.rayQueue.sortEntries()
            rayHit = self.rayQueue.getEntry(0)

            return True, rayHit
        else:
            return False, None

    def fire(self, owner, dt):
        Weapon.fire(self, owner, dt)
        rayDir = owner.weaponNP.getQuat(render).getForward()
        hit, hitEntry = self.performRayCast(owner.weaponNP.getPos(render),
                                            rayDir)

        if hit:
            hitNP = hitEntry.getIntoNodePath()
            if hitNP.hasPythonTag(TAG_OWNER):
                subject = hitNP.getPythonTag(TAG_OWNER)
                subject.alterHealth(-self.damage, rayDir * self.knockback,
                                    self.flinchValue)

    def cleanup(self):
        self.traverser.removeCollider(self.rayNodePath)
        self.traverser = None

        if self.rayNodePath is not None:
            self.rayNodePath.removeNode()
            self.rayNodePath = None

        Weapon.cleanup(self)
class World(DirectObject):
  def __init__(self):
    # This code puts the standard title and instruction text on screen
    self.title = OnscreenText(text="Panda3D: Tutorial - Collision Detection",
                              style=1, fg=(1,1,1,1),
                              pos=(0.7,-0.95), scale = .07)
    self.instructions = OnscreenText(text="Mouse pointer tilts the board",
                                     pos = (-1.3, .95), fg=(1,1,1,1),
                                     align = TextNode.ALeft, scale = .05)
    
    self.accept("escape", sys.exit)        # Escape quits
    base.disableMouse()                    # Disable mouse-based camera control
    camera.setPosHpr(0, 0, 25, 0, -90, 0)  # Place the camera

    # Load the maze and place it in the scene
    self.maze = loader.loadModel("models/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 visable polygons,
    # set a from collide mask to include bit 20
    # 
    # For this example, we will make everything we want the ball to collide with
    # include bit 0
    self.walls.node().setIntoCollideMask(BitMask32.bit(0))
    # CollisionNodes are usually invisible but can be shown. Uncomment the next
    # line to see the collision walls
    # self.walls.show()

    # We will now find the triggers for the holes and set their masks to 0 as
    # well. We also set their names to make them easier to identify during
    # collisions
    self.loseTriggers = []
    for i in range(6):
      trigger = self.maze.find("**/hole_collide" + str(i))
      trigger.node().setIntoCollideMask(BitMask32.bit(0))
      trigger.node().setName("loseTrigger")
      self.loseTriggers.append(trigger)
      # Uncomment this line to see the triggers
      # trigger.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.
    # self.cTrav.showCollisions(render)
    
    # This section deals with lighting for the ball. Only the ball was lit
    # because the maze has static lighting pregenerated by the modeler
    ambientLight = AmbientLight("ambientLight")
    ambientLight.setColor(Vec4(.55, .55, .55, 1))
    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))
    self.ballRoot.setLight(render.attachNewNode(ambientLight))
    self.ballRoot.setLight(render.attachNewNode(directionalLight))
    
    # 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 = 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

    # Create the movement task, but first make sure it is not already running
    taskMgr.remove("rollTask")
    self.mainLoop = taskMgr.add(self.rollTask, "rollTask")
    self.mainLoop.last = 0

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

  # This is the task that deals with making everything interactive
  def rollTask(self, task):
    # Standard technique for finding the amount of time since the last frame
    dt = task.time - task.last
    task.last = task.time

    # If dt is large, then there has been a # hiccup that could cause the ball
    # to leave the field if this functions runs, so ignore the frame
    if dt > .2: return Task.cont   

    # The collision handler collects the collisions. We dispatch which function
    # to handle the collision based on the name of what was collided into
    for i in range(self.cHandler.getNumEntries()):
      entry = self.cHandler.getEntry(i)
      name = entry.getIntoNode().getName()
      if   name == "wall_collide":   self.wallCollideHandler(entry)
      elif name == "ground_collide": self.groundCollideHandler(entry)
      elif name == "loseTrigger":    self.loseGame(entry)

    # Read the mouse position and tilt the maze accordingly
    if base.mouseWatcherNode.hasMouse():
      mpos = base.mouseWatcherNode.getMouse() # get the mouse position
      self.maze.setP(mpos.getY() * -10)
      self.maze.setR(mpos.getX() * 10)

    # Finally, we move the ball
    # Update the velocity based on acceleration
    self.ballV += self.accelV * dt * ACCEL
    # Clamp the velocity to the maximum speed
    if self.ballV.lengthSquared() > MAX_SPEED_SQ:
      self.ballV.normalize()
      self.ballV *= MAX_SPEED
    # Update the position based on the velocity
    self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV * dt))

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

  # If the ball hits a hole trigger, then it should fall in the hole.
  # This is faked rather than dealing with the actual physics of it.
  def loseGame(self, entry):
    # The triggers are set up so that the center of the ball should move to the
    # collision point to be in the hole
    toPos = entry.getInteriorPoint(render)
    taskMgr.remove('rollTask')  # Stop the maze task

    # Move the ball into the hole over a short sequence of time. Then wait a
    # second and call start to reset the game
    Sequence(
      Parallel(
      LerpFunc(self.ballRoot.setX, fromData = self.ballRoot.getX(),
               toData = toPos.getX(), duration = .1),
      LerpFunc(self.ballRoot.setY, fromData = self.ballRoot.getY(),
               toData = toPos.getY(), duration = .1),
      LerpFunc(self.ballRoot.setZ, fromData = self.ballRoot.getZ(),
               toData = self.ballRoot.getZ() - .9, duration = .2)),
      Wait(1),
      Func(self.start)).start()
class World(DirectObject):

    def __init__(self):
        
        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0}
        base.win.setClearColor(Vec4(0,0,0,1))

        # number of collectibles
        self.numObjects = 10;
        
        # print the number of objects
        printNumObj(self.numObjects)

        # Post the instructions
        self.title = addTitle("Roaming Ralph (Edited by Adam Gressen)")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[A]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.85, "[D]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.80, "[W]: Run Ralph Forward")
        self.inst5 = addInstructions(0.75, "[S]: Run Ralph Backward")
        self.inst6 = addInstructions(0.70, "[Space]: Run, Ralph, Run")
        
        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.  

        self.environ = loader.loadModel("models/world")      
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)
        
        # Timer to increment in the move task
        self.time = 0
        
        # Get bounds of environment
        min, max = self.environ.getTightBounds()
        self.mapSize = max-min
        
        # Create the main character, Ralph
        self.ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor("models/ralph",
                                 {"run":"models/ralph-run",
                                  "walk":"models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(self.ralphStartPos)
        
        # ralph's health
        self.health = 100
        
        # ralph's stamina
        self.stamina = 100

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation
        self.accept("escape", sys.exit)
        
        # these don't work well in combination with the space bar
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_down", self.setKey, ["backward",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("arrow_down-up", self.setKey, ["backward",0])
        
        self.accept("space", self.runRalph, [True])
        self.accept("space-up", self.runRalph, [False])
        
        self.accept("a", self.setKey, ["left",1])
        self.accept("d", self.setKey, ["right",1])
        self.accept("w", self.setKey, ["forward",1])
        self.accept("s", self.setKey, ["backward",1])
        self.accept("a-up", self.setKey, ["left",0])
        self.accept("d-up", self.setKey, ["right",0])
        self.accept("w-up", self.setKey, ["forward",0])
        self.accept("s-up", self.setKey, ["backward",0])

        # Game state variables
        self.isMoving = False
        self.isRunning = False

        # Set up the camera
        base.disableMouse()
        #base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,2)
        base.camera.setPos(0, 0, 0)
        base.camera.reparentTo(self.ralph)
        base.camera.setPos(0, 40, 2)
        base.camera.lookAt(self.ralph)
        
        # 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.

        base.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,300)
        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()
        base.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        # camera ground collision handler
        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0,0,300)
        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()
        base.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Place the health items
        self.placeHealthItems()
        
        # Place the collectibles
        self.placeCollectibles()
       
        # Uncomment this line to show a visual representation of the 
        # collisions occuring
        #base.cTrav.showCollisions(render)
        
        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))
        
        taskMgr.add(self.move,"moveTask")
        taskMgr.doMethodLater(0.5, self.healthDec, "healthTask")
    
    # reinitialize all necessary parts of the game
    def restart(self):
        self.numObjects = 10
        printNumObj(self.numObjects)
        self.ralph.setPos(self.ralphStartPos)
        self.health = 100
        self.stamina = 100
        self.time = 0
        base.camera.setPos(0, 0, 0)
        base.camera.reparentTo(self.ralph)
        base.camera.setPos(0, 40, 2)
        base.camera.lookAt(self.ralph)
        self.placeHealthItems()
        self.placeCollectibles()
        taskMgr.add(self.move,"moveTask")
        taskMgr.doMethodLater(0.5, self.healthDec, "healthTask")
    
    # Display ralph's health
    def displayHealth(self):
        healthBar['scale'] = (self.health*0.01*BAR_WIDTH,0.2,0.2)
    
    # Display ralph's stamina
    def displayStamina(self):
        sprintBar['scale'] = (self.stamina*0.01*BAR_WIDTH,0.2,0.2)
    
    # Allow ralph to collect the health items
    def collectHealthItems(self, entry):
        # refill ralph's health
        self.health = 100
        # reposition the collectible
        self.placeItem(entry.getIntoNodePath().getParent())
    
    def collectCollectibles(self, entry):
        # remove the collectible
        entry.getIntoNodePath().getParent().removeNode()
        # update the number of objects
        self.numObjects -= 1
        printNumObj(self.numObjects)
        
    # Places an item randomly on the map    
    def placeItem(self, item):
        # Add ground collision detector to the health item
        self.collectGroundRay = CollisionRay()
        self.collectGroundRay.setOrigin(0,0,300)
        self.collectGroundRay.setDirection(0,0,-1)
        self.collectGroundCol = CollisionNode('colRay')
        self.collectGroundCol.addSolid(self.collectGroundRay)
        self.collectGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.collectGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.collectGroundColNp = item.attachNewNode(self.collectGroundCol)
        self.collectGroundHandler = CollisionHandlerQueue()
        base.cTrav.addCollider(self.collectGroundColNp, self.collectGroundHandler)
        
        placed = False;
        while placed == False:
            # re-randomize position
            item.setPos(-random.randint(0,140),-random.randint(0,40),0)
            
            base.cTrav.traverse(render)
            
            # Get Z position from terrain collision
            entries = []
            for j in range(self.collectGroundHandler.getNumEntries()):
                entry = self.collectGroundHandler.getEntry(j)
                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"):
                item.setZ(entries[0].getSurfacePoint(render).getZ()+1)
                placed = True
                
        # remove placement collider
        self.collectGroundColNp.removeNode()
    
    def placeHealthItems(self):
        self.placeholder = render.attachNewNode("HealthItem-Placeholder")
        self.placeholder.setPos(0,0,0)
        
        # Add the health items to the placeholder node
        for i in range(5):
            # Load in the health item model
            self.healthy = loader.loadModel("models/sphere")
            self.healthy.setPos(0,0,0)
            self.healthy.reparentTo(self.placeholder)
            
            self.placeItem(self.healthy)
            
            # Add spherical collision detection
            healthSphere = CollisionSphere(0,0,0,1)
            sphereNode = CollisionNode('healthSphere')
            sphereNode.addSolid(healthSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.healthy.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)
            
    def placeCollectibles(self):
        self.placeCol = render.attachNewNode("Collectible-Placeholder")
        self.placeCol.setPos(0,0,0)
        
        # Add the health items to the placeCol node
        for i in range(self.numObjects):
            # Load in the health item model
            self.collect = loader.loadModel("models/jack")
            self.collect.setPos(0,0,0)
            self.collect.reparentTo(self.placeCol)
            
            self.placeItem(self.collect)
            
            # Add spherical collision detection
            colSphere = CollisionSphere(0,0,0,1)
            sphereNode = CollisionNode('colSphere')
            sphereNode.addSolid(colSphere)
            sphereNode.setFromCollideMask(BitMask32.allOff())
            sphereNode.setIntoCollideMask(BitMask32.bit(0))
            sphereNp = self.collect.attachNewNode(sphereNode)
            sphereColHandler = CollisionHandlerQueue()
            base.cTrav.addCollider(sphereNp, sphereColHandler)
        
    #Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value
    
    # Makes ralph's health decrease over time
    def healthDec(self, task):
        if (self.health <= 0):
            self.die()
        elif (self.numObjects != 0):
            self.health -= 1
            print self.health
            return task.again
        else:
            return task.done
    
    # Make ralph's stamina regenerate
    def staminaReg(self, task):
        if (self.stamina >= 100):
            self.stamina = 100
            return task.done
        else:
            self.stamina += 1
            task.setDelay(1)
            return task.again
        
    # Make ralph run
    def runRalph(self, arg):
        self.isRunning = arg
    
    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):
        if self.numObjects != 0:
            # print the time
            self.time += globalClock.getDt()
            timeText['text'] = str(self.time)
        else:
            self.die()
        
        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.
        startpos = self.ralph.getPos()
        
        # calculate ralph's speed
        if (self.isRunning and self.stamina > 0):
            taskMgr.remove("staminaTask")
            ralphSpeed = 45
            self.stamina -= 0.5
        else:
            taskMgr.doMethodLater(5, self.staminaReg, "staminaTask")
            ralphSpeed = 25

        # If a move-key is pressed, move ralph in the specified direction.
        # and rotate the camera to remain behind ralph
        if (self.keyMap["left"]!=0):
            self.ralph.setH(self.ralph.getH() + 100 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 100 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -ralphSpeed * globalClock.getDt())
        if (self.keyMap["backward"]!=0):
            self.ralph.setY(self.ralph, ralphSpeed *globalClock.getDt())

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.
        if ((self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) 
            or (self.keyMap["right"]!=0) or (self.keyMap["backward"]!=0)):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk",5)
                self.isMoving = False

        # so the following line is unnecessary
        base.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())
            #base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+5)
        elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "healthSphere"):
            self.collectHealthItems(entries[0])
        elif (len(entries)>0) and (entries[0].getIntoNode().getName() == "colSphere"):
            self.collectCollectibles(entries[0])
        else:
            self.ralph.setPos(startpos)
        
        # Keep the camera above the terrain
        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"):
            modZ = entries[0].getSurfacePoint(render).getZ()
            base.camera.setZ(20.0+modZ+(modZ-self.ralph.getZ()))
        
        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ()+2.0)
        base.camera.lookAt(self.floater)
        
        self.displayHealth()
        self.displayStamina()

        return task.cont
    
    # Restart or End?
    def die(self):
        # end all running tasks
        taskMgr.remove("moveTask")
        taskMgr.remove("healthTask")
        
        # open the file
        f = open('scores.txt', 'r')
        
        # current name, time, and collected items score
        n = f.readline()
        t = f.readline()
        c = f.readline()
        
        # close the file
        f.close()
        
        # number of collected collectibles
        colObj = 10 - self.numObjects
        
        # enter new high score
        if int(c) < colObj or (int(c) == colObj and float(t) > self.time):
            self.label = DirectLabel(text="New High Score! Enter Your Name:",
                                      scale=.05, pos=(0,0,0.2))
            self.entry = DirectEntry(text="", scale=.05, initialText="",
                                      numLines=1, focus=1, pos=(-0.25,0,0),
                                       command=self.submitScore)
        else:
            # display high score
            self.highscore = OkDialog(dialogName="highscoreDialog", 
                                      text="Current High Score:\n\nName: " + n + "Time: " + t + "Items Collected: " + c,
                                      command=self.showDialog)
    
    def showDialog(self, arg):
        # cleanup highscore dialog
        self.highscore.cleanup()
        # display restart or exit dialog
        self.dialog = YesNoDialog(dialogName="endDialog",
                                   text="Would you like to play again?", 
                                   command=self.endResult)
    
    def submitScore(self, name):
        f = open('scores.txt', 'w')
        
        # add new high score
        value = name + '\n' + str(self.time) + '\n' + str(10 - self.numObjects)
        f.write(value)
        
        f.close()
        
        self.entry.remove()
        self.label.remove()
        
        self.dialog = YesNoDialog(dialogName="endDialog",
                                   text="Would you like to play again?",
                                    command=self.endResult)
    
    # Handle the dialog result
    def endResult(self, arg):
        if (arg):
            # cleanup the dialog box
            self.dialog.cleanup()
            # restart the game
            self.restart()
        else:
            sys.exit()
예제 #31
0
class Player(GameObject, ArmedObject):
    def __init__(self, shipSpec):
        GameObject.__init__(self, Vec3(0, 0,
                                       0), None, None, shipSpec.maxShields,
                            shipSpec.maxSpeed, "player", MASK_INTO_PLAYER, 2)
        ArmedObject.__init__(self)

        self.acceleration = shipSpec.acceleration
        self.turnRate = shipSpec.turnRate

        self.numGuns = len(shipSpec.gunPositions)
        self.numMissiles = shipSpec.numMissiles
        self.maxEnergy = shipSpec.maxEnergy
        self.energyRechargeRate = shipSpec.energyRechargeRate
        self.shieldRechargeRate = shipSpec.shieldRechargeRate

        self.energy = shipSpec.maxEnergy

        for gunPos in shipSpec.gunPositions:
            np = self.actor.attachNewNode(PandaNode("gun node"))
            np.setPos(gunPos)

            gun = BlasterWeapon()
            self.addWeapon(gun, 0, np)

        missileSetCounter = 1
        for missilePos in shipSpec.missilePositions:
            np = self.actor.attachNewNode(PandaNode("missile node"))
            np.setPos(missilePos)

            gun = RocketWeapon()
            self.addWeapon(gun, missileSetCounter, np)
            missileSetCounter += 1

        self.numMissileSets = missileSetCounter - 1
        self.missileSetIndex = 0

        light = PointLight("basic light")
        light.setColor(Vec4(1, 1, 1, 1))
        light.setAttenuation((1, 0.01, 0.001))
        self.lightNP = self.root.attachNewNode(light)
        self.lightNP.setZ(1)
        Common.framework.showBase.render.setLight(self.lightNP)

        self.colliderNP.node().setFromCollideMask(MASK_WALLS
                                                  | MASK_FROM_PLAYER)

        Common.framework.pusher.addCollider(self.colliderNP, self.root)
        Common.framework.traverser.addCollider(self.colliderNP,
                                               Common.framework.pusher)

        Common.framework.showBase.camera.reparentTo(self.actor)
        Common.framework.showBase.camera.setPos(0, 0, 0)
        Common.framework.showBase.camera.setHpr(0, 0, 0)

        lens = Common.framework.showBase.camLens

        lens.setNear(0.03)

        ratio = lens.getAspectRatio()

        lens.setFov(75 * ratio)

        self.lastMousePos = Vec2(0, 0)
        self.mouseSpeedHori = 50.0
        self.mouseSpeedVert = 30.0
        self.mouseSensitivity = 1.0

        self.targetingRay = CollisionSegment(0, 0, 0, 0, 100, 0)
        self.targetingRayNode = CollisionNode("lock ray")
        self.targetingRayNode.addSolid(self.targetingRay)
        self.targetingRayNode.setFromCollideMask(MASK_ENEMY_LOCK_SPHERE)
        self.targetingRayNode.setIntoCollideMask(0)
        self.targetingRayNP = self.actor.attachNewNode(self.targetingRayNode)
        self.targetingQueue = CollisionHandlerQueue()

        self.prospectiveLockTarget = None
        self.lockTargetTimer = 0
        self.lockDuration = 1

        Common.framework.traverser.addCollider(self.targetingRayNP,
                                               self.targetingQueue)

        #rayNodePath.show()

        self.uiRoot = aspect2d.attachNewNode(PandaNode("player UI"))

        cardMaker = CardMaker("UI maker")
        cardMaker.setFrame(-1, 1, -1, 1)

        self.centreSpot = self.uiRoot.attachNewNode(cardMaker.generate())
        self.centreSpot.setTexture(
            Common.framework.showBase.loader.loadTexture(
                "../Section2SpaceflightDocking/UI/spot.png"))
        self.centreSpot.setTransparency(True)
        self.centreSpot.setPos(0, 0, 0)
        self.centreSpot.setScale(0.01)
        self.centreSpot.setAlphaScale(0.5)

        self.directionIndicator = self.uiRoot.attachNewNode(
            cardMaker.generate())
        self.directionIndicator.setTexture(
            Common.framework.showBase.loader.loadTexture(
                "../Section2SpaceflightDocking/UI/directionIndicator.png"))
        self.directionIndicator.setTransparency(True)
        self.directionIndicator.setScale(0.05)
        self.directionIndicator.hide()

        self.lockMarkerRoot = self.uiRoot.attachNewNode(
            PandaNode("lock marker root"))
        for i in range(4):
            markerRotationNP = self.lockMarkerRoot.attachNewNode(
                PandaNode("lock marker rotation"))
            marker = markerRotationNP.attachNewNode(cardMaker.generate())
            marker.setTexture(
                Common.framework.showBase.loader.loadTexture(
                    "../Section2SpaceflightDocking/UI/lockMarker.png"))
            marker.setTransparency(True)
            markerRotationNP.setScale(0.04)
            markerRotationNP.setR(i * 90)
        self.lockMarkerRoot.hide()

        self.lockBar = Common.framework.showBase.loader.loadModel(
            "../Section2SpaceflightDocking/UI/uiLockBar")
        self.lockBar.reparentTo(self.uiRoot)
        self.lockBar.setScale(0.15)
        #self.lockBar.hide()

        cardMaker.setFrame(-1, 1, 0, 1)

        self.cockpit = Common.framework.showBase.loader.loadModel(
            "../Section2SpaceflightDocking/Models/{0}".format(
                shipSpec.cockpitModelFile))
        self.cockpit.reparentTo(self.actor)

        healthBarRoot = self.cockpit.find("**/healthBar")
        if healthBarRoot is None or healthBarRoot.isEmpty():
            healthBarRoot = self.uiRoot.attachNewNode(
                PandaNode("health bar root"))
            print("No health bar root found!")

        energyBarRoot = self.cockpit.find("**/energyBar")
        if energyBarRoot is None or energyBarRoot.isEmpty():
            energyBarRoot = self.uiRoot.attachNewNode(
                PandaNode("energy bar root"))
            print("No energy bar root found!")

        missileCounterRoot = self.cockpit.find("**/missileCounter")
        if missileCounterRoot is None or missileCounterRoot.isEmpty():
            missileCounterRoot = self.uiRoot.attachNewNode(
                PandaNode("missile counter root"))
            print("No missile counter root found!")

        radarRoot = self.cockpit.find("**/radar")
        if radarRoot is None or radarRoot.isEmpty():
            radarRoot = self.uiRoot.attachNewNode(PandaNode("radar root"))
            print("No radar root found!")

        speedometerRoot = self.cockpit.find("**/speedometer")
        if speedometerRoot is None or speedometerRoot.isEmpty():
            speedometerRoot = self.uiRoot.attachNewNode(
                PandaNode("speedometer root"))
            print("No speedometer root found!")

        self.radarDrawer = MeshDrawer()
        self.radarDrawer.setBudget(4096)

        self.radarDrawerNP = self.radarDrawer.getRoot()
        self.radarDrawerNP.reparentTo(radarRoot)
        self.radarDrawerNP.setTwoSided(True)
        self.radarDrawerNP.setLightOff()
        self.radarDrawerNP.setDepthWrite(False)
        self.radarDrawerNP.setTransparency(True)

        self.healthBar = healthBarRoot.attachNewNode(cardMaker.generate())
        self.healthBar.setSx(0.05)

        self.energyBar = energyBarRoot.attachNewNode(cardMaker.generate())
        self.energyBar.setSx(0.05)

        self.healthBarScalar = 0.00175
        self.energyBarScalar = 0.00175

        self.missileCounter = DirectLabel(text="",
                                          text_mayChange=True,
                                          scale=0.09,
                                          relief=None,
                                          parent=missileCounterRoot)

        self.maxRadarRange = 700
        self.radarSize = 0.3

        self.speedometer = DirectLabel(text="",
                                       text_mayChange=True,
                                       scale=0.09,
                                       relief=None,
                                       parent=speedometerRoot)

        self.updateHealthUI()
        self.updateEnergyUI()
        self.updateMissileUI()
        self.updateRadar()
        self.updateSpeedometer()

        self.updatingEffects = []

    def update(self, keys, dt):
        GameObject.update(self, dt)

        self.updateSpeedometer()

        self.walking = False

        quat = self.root.getQuat(Common.framework.showBase.render)
        forward = quat.getForward()
        right = quat.getRight()
        up = quat.getUp()

        if keys["up"]:
            self.walking = True
            self.velocity += forward * self.acceleration * dt
        if keys["down"]:
            self.walking = True
            self.velocity -= forward * self.acceleration * dt
        if keys["left"]:
            self.walking = True
            self.velocity -= right * self.acceleration * dt
        if keys["right"]:
            self.walking = True
            self.velocity += right * self.acceleration * dt
        if self.walking:
            self.inControl = True

        mouseWatcher = base.mouseWatcherNode
        if mouseWatcher.hasMouse():
            xSize = base.win.getXSize()
            ySize = base.win.getYSize()
            xPix = float(xSize % 2) / xSize
            yPix = float(ySize % 2) / ySize
            mousePos = Vec2(base.mouseWatcherNode.getMouse())
            mousePos.addX(-xPix)
            mousePos.addY(-yPix)
            if abs(mousePos.x) < xPix:
                mousePos.x = 0
            if abs(mousePos.y) < yPix:
                mousePos.y = 0

        else:
            mousePos = self.lastMousePos

        if mousePos.length() > 0.01:
            axis = right * (mousePos.y) + up * (-mousePos.x)
            axis.normalize()
            angle = mousePos.length() * self.turnRate * dt

            rotQuat = Quat()
            rotQuat.setFromAxisAngle(angle, axis)

            self.root.setQuat(quat * rotQuat)

        if not self.weaponSets[0][0].active:
            self.alterEnergy(
                math.sin(1.071 * self.energy / self.maxEnergy + 0.5) *
                self.energyRechargeRate * dt)

        self.updateEnergyUI()
        self.updateHealthUI()
        self.updateRadar()

        #self.root.setH(self.root.getH() - mousePos.x*self.mouseSpeedHori*self.mouseSensitivity)
        #self.actor.setP(self.actor.getP() + mousePos.y*self.mouseSpeedVert*self.mouseSensitivity)

        if keys["shoot"]:
            self.startFiringSet(0)
        else:
            self.ceaseFiringSet(0)

        if keys["shootSecondary"]:
            self.startFiringSet(self.missileSetIndex + 1)
        else:
            for i in range(self.numMissileSets):
                self.ceaseFiringSet(i + 1)

        [effect.update(self, dt) for effect in self.updatingEffects]
        [
            effect.cleanup() for effect in self.updatingEffects
            if not effect.active
        ]
        self.updatingEffects = [
            effect for effect in self.updatingEffects if effect.active
        ]

        if self.targetingQueue.getNumEntries() > 0:
            self.targetingQueue.sortEntries()
            entry = self.targetingQueue.getEntry(0)
            intoNP = entry.getIntoNodePath()
            if intoNP.hasPythonTag(TAG_OWNER):
                other = intoNP.getPythonTag(TAG_OWNER)
                if other is self.prospectiveLockTarget and other is not self.lockedTarget:
                    self.lockTargetTimer += dt
                    if self.lockTargetTimer >= self.lockDuration:
                        self.lockedTarget = other
                else:
                    self.lockTargetTimer = 0
                self.prospectiveLockTarget = other
            else:
                self.lockTargetTimer = 0
        else:
            self.lockTargetTimer = 0

        perc = self.lockTargetTimer / self.lockDuration
        self.lockBar.setTexOffset(TextureStage.getDefault(), 0, -perc * 1.1)

        if self.lockedTarget is not None:
            if self.lockedTarget.health <= 0:
                self.lockedTarget = None
            else:
                relPos = self.lockedTarget.root.getPos(self.root)
                planarVec = relPos.getXz()
                relDist = relPos.length()

                if relDist == 0:
                    angle = 0
                else:
                    angle = math.acos(relPos.y / relDist)

                if relDist > 200 or angle > 1.7453:
                    self.lockedTarget = None
                else:

                    if self.lockMarkerRoot.isHidden():
                        self.lockMarkerRoot.show()

                    camPt = Point2()
                    convertedPt = Common.framework.showBase.cam.getRelativePoint(
                        Common.framework.showBase.render,
                        self.lockedTarget.root.getPos(
                            Common.framework.showBase.render))
                    if Common.framework.showBase.camLens.project(
                            convertedPt, camPt):
                        self.lockMarkerRoot.setPos(
                            Common.framework.showBase.render2d, camPt.x, 0,
                            camPt.y)
                        if self.lockMarkerRoot.isHidden():
                            self.lockMarkerRoot.show()
                        for child in self.lockMarkerRoot.getChildren():
                            child.getChild(0).setZ(
                                (1.0 - min(1, relDist / 100)) * 5 + 0.2)
                    elif not self.lockMarkerRoot.isHidden():
                        self.lockMarkerRoot.hide()

                    if relPos.y < 0 or angle > 0.6:
                        planarVec.normalize()

                        self.directionIndicator.setPos(planarVec.x * 0.4, 0,
                                                       planarVec.y * 0.4)

                        angle = math.degrees(
                            math.atan2(planarVec.x, planarVec.y))
                        self.directionIndicator.setR(angle)

                        if self.directionIndicator.isHidden():
                            self.directionIndicator.show()
                    elif not self.directionIndicator.isHidden():
                        self.directionIndicator.hide()
        else:
            if not self.directionIndicator.isHidden():
                self.directionIndicator.hide()
            if not self.lockMarkerRoot.isHidden():
                self.lockMarkerRoot.hide()

    def weaponReset(self, weapon):
        ArmedObject.weaponFired(self, weapon)

        if isinstance(weapon, RocketWeapon):
            self.ceaseFiringSet(self.missileSetIndex + 1)
            self.missileSetIndex += 1
            if self.missileSetIndex >= self.numMissileSets:
                self.missileSetIndex = 0

    def attackPerformed(self, weapon):
        ArmedObject.attackPerformed(self, weapon)

    def postTraversalUpdate(self, dt):
        ArmedObject.update(self, dt)

    def alterHealth(self,
                    dHealth,
                    incomingImpulse,
                    knockback,
                    flinchValue,
                    overcharge=False):
        GameObject.alterHealth(self, dHealth, incomingImpulse, knockback,
                               flinchValue, overcharge)

        self.updateHealthUI()

        #self.hurtSound.play()

    def alterEnergy(self, dEnergy):
        self.energy += dEnergy
        if self.energy < 0:
            self.energy = 0
        elif self.energy > self.maxEnergy:
            self.energy = self.maxEnergy

    def alterMissileCount(self, dMissiles):
        self.numMissiles += dMissiles
        if self.numMissiles < 0:
            self.numMissiles = 0
        self.updateMissileUI()

    def updateHealthUI(self):
        perc = self.health / self.maxHealth
        newVal = max(0.01, self.health * self.healthBarScalar)
        self.healthBar.setSz(newVal)
        self.healthBar.setColorScale(1.0 - (perc - 0.5) / 0.5,
                                     min(1, perc / 0.5), 0, 1)
        #self.healthCounter.setText("{0:-.0f}".format(self.health))
        #self.healthCounter.setColorScale(1.0 - (perc - 0.5)/0.5, min(1, perc/0.5), 0, 1)

    def updateEnergyUI(self):
        perc = self.energy / self.maxEnergy
        newVal = max(0.01, self.energy * self.energyBarScalar)
        self.energyBar.setSz(newVal)
        self.energyBar.setColorScale(1.0 - (perc - 0.5) / 0.5,
                                     min(1, perc / 0.5), 0, 1)

    def updateMissileUI(self):
        self.missileCounter["text"] = "Missiles:\n{0}".format(self.numMissiles)
        self.missileCounter.setText()
        self.missileCounter.resetFrameSize()

    def updateSpeedometer(self):
        self.speedometer["text"] = "Speed:\n{0:0=2.0f}m/s".format(
            self.velocity.length() * 2)
        self.speedometer.setText()
        self.speedometer.resetFrameSize()

    def updateRadar(self):
        if Common.framework.currentLevel is not None:
            self.radarDrawer.begin(Common.framework.showBase.cam,
                                   Common.framework.showBase.render)

            uvs = Vec2(0, 0)

            spotSize = 0.015

            self.radarDrawer.tri(Vec3(-spotSize, 0,
                                      -spotSize), Vec4(0, 1, 0, 1), uvs,
                                 Vec3(spotSize, 0,
                                      -spotSize), Vec4(0, 1, 0, 1), uvs,
                                 Vec3(-spotSize, 0, spotSize),
                                 Vec4(0, 1, 0, 1), uvs)
            self.radarDrawer.tri(Vec3(-spotSize, 0,
                                      spotSize), Vec4(0, 1, 0, 1), uvs,
                                 Vec3(spotSize, 0,
                                      -spotSize), Vec4(0, 1, 0, 1), uvs,
                                 Vec3(spotSize, 0, spotSize), Vec4(0, 1, 0, 1),
                                 uvs)

            selfForward = Vec3(0, 1, 0)

            for enemy in Common.framework.currentLevel.enemies:
                enemyPos = enemy.root.getPos(self.root)
                dist = enemyPos.length()
                if dist < self.maxRadarRange:
                    distPerc = dist / self.maxRadarRange
                    enemyPos.normalize()
                    anglePerc = selfForward.angleDeg(enemyPos) / 180
                    enemyPos.setY(0)
                    enemyPos.normalize()
                    enemyPos *= anglePerc * self.radarSize
                    colour = Vec4(1, 0, 0,
                                  math.sin(max(0, 1 - distPerc) * 1.571))

                    self.radarDrawer.tri(
                        Vec3(-spotSize, 0, 0) + enemyPos, colour, uvs,
                        Vec3(spotSize, 0, 0) + enemyPos, colour, uvs,
                        Vec3(0, 0, spotSize) + enemyPos, colour, uvs)
                    self.radarDrawer.tri(
                        Vec3(spotSize, 0, 0) + enemyPos, colour, uvs,
                        Vec3(-spotSize, 0, 0) + enemyPos, colour, uvs,
                        Vec3(0, 0, -spotSize) + enemyPos, colour, uvs)

            self.radarDrawer.end()

    def addUpdatingEffect(self, effect):
        self.updatingEffects.append(effect)
        effect.start(self)

    def cleanup(self):
        if self.uiRoot is not None:
            self.uiRoot.removeNode()
            self.uiRoot = None
        self.healthBar = None

        if self.lightNP is not None:
            Common.framework.showBase.render.clearLight(self.lightNP)
            self.lightNP.removeNode()
            self.lightNP = None

        for effect in self.updatingEffects:
            effect.cleanup()
        self.updatingEffects = []

        ArmedObject.cleanup(self)
        GameObject.cleanup(self)
class GameEngine( DirectObject ):
    def __init__(self):
        print 'Game Engine Started'
        self.lastBlock = 0
        self.map = []
        self.startBlock = 0
        self.endBlock = 0
        self.mapName = 'test2'
        
        self.loadEnvironment(self.mapName)
        self.loadCursorPicker()
        self.camera = RTS_Camera()
        self.loadSimpleLighting()
        
        self.waveController = WaveController(self.mapName, self.startBlock, self.map)
        self.towerController = TowerController(self.waveController)
        
        self.setupKeyListeners()
        self.EFT = taskMgr.add(self.everyFrameTask, "everyFrameTask")
        
    # The task that is run every frame
    def everyFrameTask(self, task):
        self.camera.handleMouseInput()
        self.checkCursorCollision()
        self.towerController.updateTowers()
        
        return task.cont
    
    # Loads the level from the text file. Puts each
    # row into an array then creates the rows in the
    # 1st quadrant
    def loadEnvironment(self, file):
        fileName = 'maps/' + file + '.map'
        rows = []
        self.environmentRoot = render.attachNewNode('environmentRoot')
        
        FILE = open(fileName, 'r')
        while( 1 ):
            line = FILE.readline()
            if( not line ):
                break
            print line,
            if( line[-1] == '\n' ):
                line = line[:-1]
            rows.append(line)
            
        rows.reverse()
        for i, row in enumerate(rows):
            self.createRow( i, row )
            
    # Loads the models corresponding to the
    # characters in the map file for an entire row
    def createRow(self, rowIndex, row):
        mapRow = []
        
        for colIndex, block in enumerate(row):
            block = BLOCK_CHAR_TO_MODEL[block]( self.environmentRoot, colIndex + 0.5, rowIndex + 0.5 )
            mapRow.append( block )
            block.setIndex( str(rowIndex) + ' ' + str(colIndex) )
            
            if( block.isType(StartBlock) ):
                self.startBlock = block
            elif( block.isType(EndBlock) ):
                self.endBlock = block
                
        self.map.append(mapRow)
            
    # Creates necessary collision parts to determine what object
    # the cursor is hovering
    def loadCursorPicker(self):
        self.picker = CollisionTraverser()
        self.pq     = CollisionHandlerQueue()
        self.pickerNode = CollisionNode('mouseRay')
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        self.picker.addCollider(self.pickerNP, self.pq)
        
    def checkCursorCollision(self):
        if base.mouseWatcherNode.hasMouse():
              mpos = base.mouseWatcherNode.getMouse()
              self.pickerRay.setFromLens( base.camNode, mpos.getX(), mpos.getY() )
              
        self.picker.traverse( self.environmentRoot )
        if( self.pq.getNumEntries() > 0 ):
            self.pq.sortEntries()
            (row, ignore, col) = self.pq.getEntry(0).getIntoNode().getTag('index').partition(' ')
            row = int(row)
            col = int(col)
            block = self.map[row][col]
            if( block != self.lastBlock ):
                block.highlight()
                if( self.lastBlock ):
                    self.lastBlock.unHighlight()
            self.lastBlock = block
        else:
            if( self.lastBlock ):
                self.lastBlock.unHighlight()
                self.lastBlock = 0
            
    def mouseClick(self):
        if( self.lastBlock ):
            self.towerController.addTower(self.lastBlock)
            
    def spawnEnemy(self):
        e = Enemy(self.startBlock, self.map)
        e.moveToEnd()
        
    def setTowerType(self, type):
        self.towerController.currentTowerType = type
    
    def setupKeyListeners(self):
        self.accept('mouse1', self.mouseClick)
        self.accept('q', self.waveController.start)
        
        self.accept('1', self.setTowerType, [NormalTower])
        self.accept('2', self.setTowerType, [SlowTower])
        self.accept('3', self.setTowerType, [StunTower])
            
    def loadSimpleLighting(self):
        ambientLight = AmbientLight( "ambientLight" )
        ambientLight.setColor( Vec4(.8, .8, .8, 1) )
        directionalLight = DirectionalLight( "directionalLight" )
        directionalLight.setDirection( Vec3( 0, 45, -45 ) )
        directionalLight.setColor( Vec4( 0.2, 0.2, 0.2, 0.6 ) )
        render.setLight(render.attachNewNode( directionalLight ) )
        render.setLight(render.attachNewNode( ambientLight ) )
예제 #33
0
class World(DirectObject):

    def skyBoxLoad(self):
        self.spaceSkyBox = load_model('skybox1.egg')
        self.spaceSkyBox.setScale(150)
        self.spaceSkyBox.setLightOff()
        self.spaceSkyBox.reparentTo(render)
        self.spaceSkyBox.setPos(0,0,-200)
        self.spaceSkyBox.setHpr(0,0,0)        

    def loadEnviron(self):
        self.environ = load_model("secondWorld.egg")
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)

    def loadPokemon(self):
        self.pikachu = load_model("pikachu.egg")
        self.pikachu.reparentTo(render)
        self.pikachu.setScale(1)
        # self.pikachu.setPos(0,0,1)
        # self.pikachu.place()
        self.Groudon = load_model("Groudon.egg")
        self.Groudon.reparentTo(render)
        self.Groudon.setPos(-50,0,0)        
        # self.Groudon.place()
    def loadRalph(self):
        # Create the main character, Ralph
        basePath = r"../google_drive/ball/data/models/"
        ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor(basePath+"ralph",{"run":basePath+"ralph-run",
                                  "walk":basePath+"ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos)
        self.ralph.hide()
        
    def loadMusic(self, name="palette.mp3"):
        bgmusic = load_bgmusic(name)
        bgmusic.play()                    

    def keyControl(self):
        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("w",self.setKey,["upward",1])
        self.accept("w-up",self.setKey,["upward",0])
        self.accept("s",self.setKey,["downward",1])
        self.accept("s-up",self.setKey,["downward",0])        

    def displayInformation(self):
        self.title = addTitle("My Pokemon - Roam Mode")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Arrow Keys]: Move")
        self.inst4 = addInstructions(0.85, "[w]: look up")
        self.inst4 = addInstructions(0.80, "[s]: look down")        
        
    def __init__(self):
        self.keyMap = {"left":0, "right":0, "forward":0,"backward":0,
                       "upward":0, "downward":0, "leftward":0,"rightward":0,
                       "cam-left":0, "cam-right":0}
        # base.win.setClearColor(Vec4(0,0,0,1))
        self.above = 3.0
        # load sky box
        self.skyBoxLoad()
        # load environment
        self.loadEnviron()
        # load pokemon
        self.loadPokemon()
        # load ralph
        self.loadRalph()
        # load music
        self.loadMusic()
        self.displayInformation()
        self.keyControl()
        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)
        taskMgr.add(self.move,"moveTask")
        taskMgr.add(self.setAbove,"setAbove")
        # Game state variables
        self.isMoving = False
        # Set up the camera
        base.disableMouse()
        base.camera.setPos(self.ralph.getX(),self.ralph.getY(),2)
        self.cTrav = CollisionTraverser()
        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0,0,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()
        #self.camGroundColNp.show()
       
        # Uncomment this line to show a visual representation of the 
        # collisions occuring
        #self.cTrav.showCollisions(render)
        
        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def setAbove(self,task):
        if self.keyMap["upward"] == 1:
            self.above += 0.1
        if self.keyMap["downward"] == 1:
            self.above -= 0.1
        return task.cont
    #Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

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

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

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if (self.keyMap["left"]!=0):
            self.ralph.setH(self.ralph.getH() + 113 * globalClock.getDt())
            base.camera.setX(base.camera, +20 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 113 * globalClock.getDt())
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -75 * globalClock.getDt())
        if (self.keyMap["backward"] != 0):
            pass
            #self.ralph.setY(self.ralph, 75 * globalClock.getDt())
        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):# or (self.keyMap["backward"]!=0):
            if self.isMoving is False:
                #self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                #self.ralph.stop()
                #self.ralph.pose("walk",5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec*(5-camdist))
            camdist = 5.0

        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.
        
        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.camera.setZ(self.ralph.getZ() + 2.0)
            
        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        
        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + self.above)#self.above)
        
        base.camera.lookAt(self.floater)
        return task.cont
예제 #34
0
class GameApp:

    def __init__(self):
        self.gameEventHandler = GameEventHandler(self)
        self.camLimits = ((-5, 5), (-6.5, 5), (1, 10))
        self.gameReady = False
        self.hovered = None
        self.clicked = None
        self.modelToFigure = {}
        self.modelToField = {}
        self.modelToSeaField = {}
        self.modelToBuildingField = {}
        self.modelToBuilding = {}
        # self.highlightableObjects = render.attachNewNode('highlightables')
        self.setupColisionForHighlight()
        self.songMenu = None
        self.buildMenu = None

    def setupColisionForHighlight(self):
        # Since we are using collision detection to do picking, we set it up like
        # any other collision detection system with a traverser and a handler
        self.picker = CollisionTraverser()  # Make a traverser
        self.pq = CollisionHandlerQueue()  # Make a handler
        # Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        # Attach that node to the camera since the ray will need to be positioned
        # relative to it
        self.pickerNP = self.camera.attachNewNode(self.pickerNode)
        # Everything to be picked will use bit 1. This way if we were doing other
        # collision we could seperate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  # Make our ray
        # Add it to the collision node
        self.pickerNode.addSolid(self.pickerRay)
        # Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)

    def getCameraCoords(self):
        return self.camera.getPos()

    def setCameraCoords(self, x, y, z):
        self.camera.setPos(x, y, z)

    def getMouseCoords(self):
        if self.mouseWatcherNode.hasMouse():
            return self.mouseWatcherNode.getMouse()
        return None

    def drawIsland(self, island, suppressRot=False):
        island.model.setPos(island.pos[0], island.pos[1], 0.001)
        island.model.setScale(0.05, 0.05, 0.05)
        island.model.reparentTo(self.render)
        for f in range(0, 6):
            circle = self.loader.loadModel('models/circle')
            pos = (island.fields[f].x, island.fields[f].y, 0.4)
            circle.setPos(pos)
            circle.setScale(0.4)
            circle.reparentTo(island.model)
            circle.setTag('clickable', 'true')
            cs = CollisionSphere(0, 0, 0, 1)
            cnodePath = circle.attachNewNode(CollisionNode('cnode'))
            cnodePath.node().addSolid(cs)
            island.fields[f].model = circle
            self.modelToField[circle.getKey()] = island.fields[f]

        for i in range(0, 3):
            buildingField = island.buildingFields[i]
            circle = self.loader.loadModel('models/circle')
            pos = (buildingField.x, buildingField.y, 0.1)
            circle.setPos(pos)
            circle.setScale(0.6)
            circle.reparentTo(island.model)
            circle.setTag('clickable', 'true')
            cs = CollisionSphere(0, 0, 0, 1)
            cnodePath = circle.attachNewNode(CollisionNode('cnode'))
            cnodePath.node().addSolid(cs)
            buildingField.model = circle
            self.modelToBuildingField[circle.getKey()] = buildingField

        # put the bay field
        circle = self.loader.loadModel('models/circle')
        pos = (island.bay.x, island.bay.y, 0.2)
        circle.setPos(pos)
        circle.setScale(0.6)
        circle.reparentTo(island.model)
        circle.setTag('clickable', 'true')
        cs = CollisionSphere(0, 0, 0, 1)
        cnodePath = circle.attachNewNode(CollisionNode('cnode'))
        cnodePath.node().addSolid(cs)
        island.bay.model = circle
        self.modelToSeaField[circle.getKey()] = island.bay
        degree = angle((0, 1), island.pos) * 180 / math.pi
        if island.pos[0] > 0:
            degree *= -1
        if not suppressRot:
            island.model.setHpr(degree, 0, 0)

    def drawFigures(self):
        for player in self.game.players:
            for figure in player.figures:
                if hasattr(figure, 'model'):
                    continue
                if type(figure) == Ship:
                    field = figure.field
                    figure.model = self.loader.loadModel('models/ship')
                    figure.model.reparentTo(field.model)
                    cs = CollisionSphere(1.5, 0, 1, 1.3)
                    cnodePath = figure.model.attachNewNode(
                        CollisionNode('cnode'))
                    cnodePath.node().addSolid(cs)
                    # cnodePath.show()
                    cs = CollisionSphere(0, 0, 1.4, 1.3)
                    cnodePath = figure.model.attachNewNode(
                        CollisionNode('cnode'))
                    cnodePath.node().addSolid(cs)
                    # cnodePath.show()
                    cs = CollisionSphere(-1.8, 0, 1, 1)
                    cnodePath = figure.model.attachNewNode(
                        CollisionNode('cnode'))
                    cnodePath.node().addSolid(cs)
                    # cnodePath.show()
                    figure.model.setScale(1.4)
                    figure.model.setHpr(90, 0, 0)
                    # figure.model.setTag('highlightable', 'true')
                    figure.model.setTag('clickable', 'true')
                    self.modelToFigure[figure.model.getKey()] = figure
                else:
                    field = figure.field
                    figure.model = self.loader.loadModel('models/warrior100')
                    figure.model.reparentTo(field.model)
                    cs = CollisionSphere(0, -.35, 7, 1)
                    cnodePath = figure.model.attachNewNode(
                        CollisionNode('cnode'))
                    cnodePath.node().addSolid(cs)
                    figure.model.setScale(0.35)
                    figure.model.setTag('highlightable', 'true')
                    figure.model.setTag('clickable', 'true')
                    self.modelToFigure[figure.model.getKey()] = figure

                col = 256 * int(player.color)
                # set figure title
                title = TextNode(str(figure.model.getKey()) + '_title')
                title.setText(type(figure).__name__)
                title.setCardColor(col, col, col, 1)
                title.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
                title.setCardDecal(True)
                titleNode = self.render.attachNewNode(title)
                titleNode.reparentTo(figure.model)
                titleNode.setScale(3)
                titleNode.setPos(0, 3, 10)
                if type(figure) == Ship:
                    titleNode.setScale(1.5)
                    titleNode.setPos(-1.5, 0, 3)
                titleNode.setBillboardPointEye()

    def drawSeaways(self):
        for field in self.game.board.seawayFields:
            circle = self.loader.loadModel('models/circle')
            pos = (field.x, field.y, 0)
            circle.setPos(pos)
            circle.setScale(0.04)
            circle.setHpr(-90, 0, 0)
            circle.reparentTo(self.render)
            circle.setTag('clickable', 'true')
            cs = CollisionSphere(0, 0, 0, 1)
            cnodePath = circle.attachNewNode(CollisionNode('cnode'))
            cnodePath.node().addSolid(cs)
            field.model = circle
            self.modelToSeaField[circle.getKey()] = field

    def drawBuilding(self, building, field):
        model = self.loader.loadModel('models/house')
        # model.setScale(0.05)
        model.reparentTo(field.model)
        building.model = model
        self.modelToBuilding[model.getKey()] = building
        player = self.game.currentPlayer()
        model.setTag('clickable', 'true')
        cs = CollisionSphere(0, 0, 0, 2)
        cnodePath = model.attachNewNode(CollisionNode('cnode'))
        cnodePath.node().addSolid(cs)
        # cnodePath.show()

        col = 256 * int(player.color)
        # set building title
        title = TextNode(str(building.model.getKey()) + '_title')
        title.setText(building.building)
        title.setCardColor(col, col, col, 1)
        title.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
        title.setCardDecal(True)
        titleNode = self.render.attachNewNode(title)
        titleNode.reparentTo(building.model)
        titleNode.setScale(1.5)
        titleNode.setPos(0, 0, 3)
        titleNode.setBillboardPointEye()

    def drawGame(self, game):
        if not self.gameReady:
            self.game = game
            # menu = OnscreenImage(image = 'textures/menu.png', pos = (1.53, 0, 0), scale=(0.35, 1, 1))
            # menu.setTransparency(TransparencyAttrib.MAlpha)

            # setup the background of the board
            self.environ = self.loader.loadModel('models/plane')
            sea = self.loader.loadTexture('textures/sea.png')
            self.environ.setTexture(sea)
            self.environ.setPos(0, 1, 0)
            self.environ.setScale(1.1)
            sea.setWrapU(Texture.WM_repeat)
            sea.setWrapV(Texture.WM_repeat)
            self.environ.reparentTo(self.render)

            # setup camera
            self.camera.setPos(0, 0, 10)
            self.camera.setHpr(0, -70, 0)
            self.camLens.setNear(0.85)

            # setup lighting
            plight = PointLight('plight')
            plight.setColor(VBase4(1, 1, 1, 3))
            plnp = self.render.attachNewNode(plight)
            plnp.setPos(10, 0, 10)
            self.render.setLight(plnp)
            ambientLight = AmbientLight('ambientLight')
            ambientLight.setColor(Vec4(0.25, 0.25, 0.25, .3))
            ambientLightNP = self.render.attachNewNode(ambientLight)
            self.render.setLight(ambientLightNP)

            # place islands
            first = True
            for island in game.board.islands:
                island.drawable = True
                island.model = self.loader.loadModel('models/island2_104')
                self.drawIsland(island, first)
                first = False

            self.drawFigures()
            self.drawSeaways()

            self.turn = OnscreenText(text='Black\'s turn.',
                                     pos=(0.06, -0.1),
                                     align=TextNode.ALeft,
                                     parent=base.a2dTopLeft,
                                     scale=0.06)
            self.resources = OnscreenText(text='Resources: ',
                                          pos=(0.08, -0.2),
                                          align=TextNode.ALeft,
                                          parent=base.a2dTopLeft,
                                          scale=0.06)
            self.gameReady = True

        player = 'Black'
        if game.turn == 1:
            player = 'White'
        self.turn.setText(player + '\'s turn.')
        resourcesText = 'Resources: ' + \
            str(self.game.currentPlayer().resources)
        self.resources.setText(resourcesText)
        if self.game.loosers != None:
            message = OnscreenText(text='End of the game',
                                   align=TextNode.ACenter,
                                   pos=(0, 0),
                                   scale=0.1)
            if self.game.loosers == 'black':
                message.setText('White wins!')
            elif self.game.loosers == 'white':
                message.setText('Black wins!')
            else:
                message.setText('Nobody wins!')

    def destroyGame(self):
        children = self.render.getChildren()
        for child in children:
            child.removeNode()

    def cameraSpeed(self, height, speedRange):
        # Figure out how 'wide' each range is
        leftSpan = self.camLimits[2][1] - self.camLimits[2][0]
        rightSpan = speedRange[1] - speedRange[0]

        # Convert the left range into a 0-1 range (float)
        valueScaled = float(height - self.camLimits[2][0]) / float(leftSpan)

        # Convert the 0-1 range into a value in the right range.
        return speedRange[0] + (valueScaled * rightSpan)

    def moveCamera(self):
        mousePos = self.getMouseCoords()
        if mousePos == None:
            return
        x, y = mousePos
        camX, camY, camZ = self.getCameraCoords()
        transformX, transformY = 0, 0
        speed = self.cameraSpeed(camZ, (0.01, 0.2))
        if x < -0.7 and y < -0.7:
            transformX -= speed
            transformY -= speed
        elif x > 0.7 and y < -0.7:
            transformX += speed
            transformY -= speed
        elif x < -0.7 and y > 0.7:
            transformX -= speed
            transformY += speed
        elif x > 0.7 and y > 0.7:
            transformX += speed
            transformY += speed
        else:
            if x < -0.7:
                transformX -= speed
            elif x > 0.7:
                transformX += speed
            if y < -0.7:
                transformY -= speed
            elif y > 0.7:
                transformY += speed
        newX = camX + transformX
        newY = camY + transformY
        if newX < self.camLimits[0][0] or newX > self.camLimits[0][1]:
            newX = camX
        if newY < self.camLimits[1][0] or newY > self.camLimits[1][1]:
            newY = camY
        self.setCameraCoords(newX, newY, camZ)

    def highlight(self):
        if self.mouseWatcherNode.hasMouse():
            mPos = self.mouseWatcherNode.getMouse()

            # Set the position of the ray based on the mouse position
            self.pickerRay.setFromLens(self.camNode, mPos.getX(), mPos.getY())

            self.picker.traverse(self.render)
            if self.pq.getNumEntries() > 0:
                # This is so we get the closest object.
                self.pq.sortEntries()
                pickedObj = self.pq.getEntry(0).getIntoNodePath()
                # pick the model and not the cnode
                pickedObj = pickedObj.findNetTag('clickable')
                if not pickedObj.isEmpty():
                    return pickedObj

    @staticmethod
    def boardingTransformations(figure, pos):
        figure.model.setScale(0.2)
        figure.model.setPos(1 + pos, 0, 1)

    @staticmethod
    def unboardingTransformations(figure):
        figure.model.setScale(0.35)
        figure.model.setPos(0, 0, 0)

    def drawSongsMenu(self, songs, field):
        if self.songMenu:
            return
        self.songMenu = [(OnscreenText(text='Choose song:',
                                       pos=(-0.7, -0.1),
                                       align=TextNode.ALeft,
                                       parent=base.a2dTopRight,
                                       scale=0.06), field)]
        i = 1
        for song in songs:
            item = OnscreenText(text=str(i) + ') Song of ' + song,
                                pos=(-0.7, -0.1 - i * 0.1),
                                align=TextNode.ALeft,
                                parent=base.a2dTopRight,
                                scale=0.06)
            i += 1
            self.songMenu.append((item, song))

    def destroySongMenu(self):
        if self.songMenu:
            for item in self.songMenu:
                item[0].destroy()
            self.songMenu = None

    def drawBuildMenu(self, buildings, field):
        self.buildMenu = [(OnscreenText(text='Choose building:',
                                        pos=(-0.7, -0.1),
                                        align=TextNode.ALeft,
                                        parent=base.a2dTopRight,
                                        scale=0.06), field)]
        i = 1
        for building in buildings:
            price = Building.buildingPrice(building)
            text = '{0}) {1} ({2})'.format(str(i), building, price)
            item = OnscreenText(text=text,
                                pos=(-0.7, -0.1 - i * 0.1),
                                align=TextNode.ALeft,
                                parent=base.a2dTopRight,
                                scale=0.06)
            i += 1
            self.buildMenu.append((item, building))

    def destroyBuildMenu(self):
        if self.buildMenu:
            for item in self.buildMenu:
                item[0].destroy()
            self.buildMenu = None

    def clickFigure(self, figure):
        print('figure')
        if type(figure) == Ship:
            ship = figure
            figure = self.clicked
            if isinstance(figure, Figure) and type(figure) != Ship:
                if figure.hasMoved:
                    self.clicked = ship
                    return
                if (figure.field.island == ship.field.island and
                        figure.player == ship.player and
                        None in ship.fields):
                    figure.field.put(None)
                    pos = 0
                    if ship.fields[0] == None:
                        ship.fields[0] = figure
                    else:
                        ship.fields[1] = figure
                        pos = 1
                    figure.field = ship
                    figure.model.reparentTo(ship.model)
                    self.boardingTransformations(figure, pos)
                    figure.hasMoved = True
            if ship.player == self.game.currentPlayer():
                self.clicked = ship
        else:
            if figure.player == self.game.currentPlayer():
                self.clicked = figure

    def initiateBattle(self, blackTroops, whiteTroops):
        self.blackTroops = blackTroops
        self.whiteTroops = whiteTroops
        battle = self.game.newBattle()
        self.push(battle)
        self.gameEventHandler.ignoreAll()

    def clickField(self, field):
        print(self.clicked)
        if type(self.clicked) == Ship:
            return
        if self.clicked and isinstance(self.clicked, Figure):
            figure = self.clicked
            board = self.game.board
            if figure.hasMoved:
                return
            if type(figure.field) == Ship:
                if field in board.possibleMoves(figure.field):
                    figure.field.removeFigure(figure)
                    player = self.game.currentPlayer()
                    battle = field.figure != None and field.figure.player != player
                    whiteTroops = field.figure
                    field.put(figure)
                    figure.model.reparentTo(field.model)
                    self.unboardingTransformations(figure)
                    figure.hasMoved = True
                    self.initiateBattle(figure, whiteTroops)
            if field in board.possibleMoves(self.clicked):
                initiateBattle = field.figure != None
                whiteTroops = field.figure
                figure.field.put(None)
                field.put(figure)
                figure.model.reparentTo(field.model)
                figure.hasMoved = True
                if initiateBattle:
                    self.initiateBattle(figure, whiteTroops)
        if isinstance(self.clicked, Building):
            building = self.clicked
            player = self.game.currentPlayer()
            if not field.figure or field.figure.player != player:
                if field.island != building.field.island:
                    return
                figure = None
                battle = field.figure != None and field.figure.player != player
                whiteTroops = field.figure
                if building.building == 'House':
                    figure = self.game.giveBirthToPeasant(field)
                elif building.building == 'Barracks':
                    figure = self.game.giveBirthToWarrior(field)
                if figure == None:
                    return
                if figure:
                    self.drawFigures()
                if battle:
                    self.initiateBattle(figure, whiteTroops)
                else:
                    print('Not enough resources!')

    def clickSeaField(self, field):
        if type(self.clicked) == Ship:
            figure = self.clicked
            if figure.hasMoved:
                return
            if field.figure != None:
                return
            if field in figure.field.linked:
                figure.field.put(None)
                field.put(figure)
                figure.model.reparentTo(field.model)
                figure.hasMoved = True
        if type(self.clicked) == Building:
            player = self.game.currentPlayer()
            building = self.clicked
            if building.building == 'Harbor':
                if building.field.island.bay != field:
                    return

                player = self.game.currentPlayer()
                if not field.figure or field.figure.player != player:
                    ship = self.game.buildShip(field)
                    if ship:
                        self.drawFigures()
                    else:
                        print('Not enough resources')

    def clickBuildingField(self, field):
        print("Gonna build, huh?")
        player = self.game.currentPlayer()
        print(self.game.possibleBuildings(field.island))
        self.drawSongsMenu(self.game.possibleSongs(field.island), field)

    def handle(self, event, *args):
        print(event)
        if type(self.current()) != Game:
            return
        if event == 'wheel_up':
            x, y, z = self.getCameraCoords()
            if z > self.camLimits[2][0]:
                self.setCameraCoords(x, y, z - 1)
        elif event == 'wheel_down':
            x, y, z = self.getCameraCoords()
            if z < self.camLimits[2][1]:
                self.setCameraCoords(x, y, z + 1)
        elif event == 'enter':
            if self.game.loosers != None:
                self.pop()
            self.game.changeTurn()
        elif event == 'left_click':
            obj = self.highlight()
            if obj != None:
                key = obj.getKey()
                # if it's a figure
                if key in self.modelToFigure:
                    figure = self.modelToFigure[key]
                    self.clickFigure(figure)
                # if it's a figure field
                if key in self.modelToField:
                    field = self.modelToField[key]
                    self.clickField(field)
                # if it's a building field
                if key in self.modelToBuildingField:
                    field = self.modelToBuildingField[key]
                    self.clickBuildingField(field)
                # if it's a sea field
                if key in self.modelToSeaField:
                    field = self.modelToSeaField[key]
                    self.clickSeaField(field)
                # if it's a building
                if key in self.modelToBuilding:
                    self.clicked = self.modelToBuilding[key]
            else:
                self.clicked = None
            if self.songMenu != None:
                if obj == None or obj.getKey() not in self.modelToBuildingField:
                    self.destroySongMenu()
        elif event in [str(i) for i in range(1, 10)]:
            if self.songMenu:
                if self.songMenu[0][1] != self.game.board.islands[0]:
                    song = self.songMenu[int(event)][1]
                    buildings = self.game.buildings[song]
                    self.drawBuildMenu(buildings, self.songMenu[0][1])
                else:
                    print('CHANGE OBJECTIVES!')
                self.destroySongMenu()
                return
            if self.buildMenu:
                building = self.buildMenu[int(event)][1]
                field = self.buildMenu[0][1]
                building = self.game.build(building, field)
                if building:
                    self.drawBuilding(building, field)
                else:
                    print('Not enough resources or field is taken!!>@')
                self.destroyBuildMenu()

    def hoverFigure(self, hovered):
        if self.hovered != None:
            reverseFactor = self.hovered.getScale()[0]
            reverseFactor *= REVERSE_HIGHLIGHT_SCALE
            self.hovered.setScale(reverseFactor)
        self.hovered = None
        if hovered != None:
            figure = self.modelToFigure[hovered.getKey()]
            if figure.player.color != str(self.current().turn):
                return
            self.hovered = hovered
            factor = HIGHLIGHT_SCALE * hovered.getScale()[0]
            hovered.setScale(factor)
예제 #35
0
class Main(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        global picture_names
        picture_names = [f for f in listdir('images') if isfile(join('images', f))]
        
        self.handScale = 1
        self.handV=ZERO
        self.scale = 20 / self.handScale
        self.ex = Vec3(1,0,0)
        self.ez = Vec3(0,0,-1)
        
        self.leap = Leap.Controller()
        self.title = OnscreenText(text="Wen-Jye's Panda3D Leap Motion",
                              style=1, fg=(1,1,0,1),
                              pos=(0.7,-0.95), scale = .07)
        self.score = OnscreenText(text="",
                                     pos = (-1.3, .75), fg=(1,1,0,1),
                                     align = TextNode.ALeft, scale = .1)
        self.timer = OnscreenText(text="",
                                     pos = (-1.3, .85), fg=(1,1,0,1),
                                     align = TextNode.ALeft, scale = .1)
    
        
        self.cTrav = CollisionTraverser()
        self.cHandler = CollisionHandlerQueue()
        self.handLoader()
        
        self.tracks = self.loader.loadModel("models/tracks")
        self.tracks.setScale(1,1.5,1)
        self.tracks.setPosHpr(-3, STAGE_HEIGHT, 12, 90, 90, 90)
        
        self.train = self.loader.loadModel("models/train")
        self.train.setScale(1,0.5,0.5)
        self.train.setPosHpr(16, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
        
        
        self.stage = self.loader.loadModel("models/stage")
        self.stage.setScale(0.55,0.50,0.25)
        self.stage.setPosHpr(0, STAGE_HEIGHT-0.5, 2, 90, 180, 90)
        self.mesh = self.stage.find("**/mesh_stage")
        self.floor = self.stage.find("**/floor")
        self.floor.node().setIntoCollideMask(BitMask32.bit(0))
        self.wall_B = self.stage.find("**/wall_B")
        self.wall_B.node().setIntoCollideMask(BitMask32.bit(0))
        self.wall_F = self.stage.find("**/wall_F")
        self.wall_F.node().setIntoCollideMask(BitMask32.bit(0))
        self.wall_R = self.stage.find("**/wall_R")
        self.wall_R.node().setIntoCollideMask(BitMask32.bit(0))
        self.wall_L = self.stage.find("**/wall_L")
        self.wall_L.node().setIntoCollideMask(BitMask32.bit(0))
        
        self.buttonList = [render.attachNewNode("button_%i"  % (i+1)) for i in range(3)] # @UndefinedVariable
        for i in range(len(self.buttonList)):
            self.buttonCreator(i) 
            self.buttonList[i].detachNode()
        self.setLight()        
        self.errorMsg = OnscreenText(text="", pos = (0,0), fg=(1,1,0,1), align = TextNode.ACenter, scale = .1)
        self.taskMgr.add(self.spinCameraTask, "SpinCameraTask")
        
        self.menuBG = self.loadImageAsPlane("tex/startScreen.jpg" )
        self.menuBG.setScale(12.5,9,8.5)
        self.menuBG.reparentTo(self.render)
        self.menuBG.setPosHpr(0,STAGE_HEIGHT+1.5,-2, 0, -105, 0)
        self.menuBG.setTransparency(TransparencyAttrib.MAlpha)
        self.menuBG.setAlphaScale(1)
        self.taskMgr.add(self.deviceChecker, "deviceChecker")
    def spinCameraTask(self, task):
        self.camera.setPos(0,STAGE_HEIGHT+10,30)
        self.camera.setHpr(0,255,0)
        self.camLens.setFov(65)
        return Task.cont
    def loadImageAsPlane(self, filepath, yresolution = 600):
        tex = loader.loadTexture(filepath) # @UndefinedVariable
        tex.setBorderColor(Vec4(0,0,0,0))
        tex.setWrapU(Texture.WMBorderColor)
        tex.setWrapV(Texture.WMBorderColor)
        cm = CardMaker(filepath + ' card')
        cm.setFrame(-tex.getOrigFileXSize(), tex.getOrigFileXSize(), -tex.getOrigFileYSize(), tex.getOrigFileYSize())
        card = NodePath(cm.generate())
        card.setTexture(tex)
        card.setScale(card.getScale()/ yresolution)
        card.flattenLight() # apply scale
        return card
    def handLoader(self):
        self.palm_R = self.loader.loadModel("%s/palm_R" % LOAD_HAND_FROM) # @UndefinedVariable
        self.palm_R_collider = self.palm_R.find("**/palm_R_collider")
        self.palm_R_collider.node().setIntoCollideMask(BitMask32.bit(0))
        self.fing_R = [self.loader.loadModel("%s/fing%i_R" % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.midd_R = [self.loader.loadModel("%s/m%i_R"    % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.base_R = [self.loader.loadModel("%s/b%i_R"    % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.fing_R_collider = [self.fing_R[i].find("**/fing%i_R_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        self.midd_R_collider = [self.midd_R[i].find("**/m%i_R_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        self.base_R_collider = [self.base_R[i].find("**/b%i_R_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        self.palm_L = self.loader.loadModel("%s/palm_L" % LOAD_HAND_FROM) # @UndefinedVariable
        self.palm_R_collider = self.palm_L.find("**/palm_L_collider")
        self.palm_R_collider.node().setIntoCollideMask(BitMask32.bit(0))
        self.fing_L = [self.loader.loadModel("%s/fing%i_L" % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.midd_L = [self.loader.loadModel("%s/m%i_L"    % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.base_L = [self.loader.loadModel("%s/b%i_L"    % (LOAD_HAND_FROM, i+1)) for i in range(5)] # @UndefinedVariable
        self.fing_L_collider = [self.fing_L[i].find("**/fing%i_L_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        self.midd_L_collider = [self.midd_L[i].find("**/m%i_L_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        self.base_L_collider = [self.base_L[i].find("**/b%i_L_collider" % (i+1)) for i in range(5)] # @UndefinedVariable
        
        self.palm_R.setScale(self.handScale, self.handScale, self.handScale*1.5)
        self.palm_L.setScale(self.handScale, self.handScale, self.handScale*1.5)
        for f in self.fing_R: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.midd_R: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.base_R: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.fing_L: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.midd_L: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.base_L: f.setScale(self.handScale, self.handScale*1.5, self.handScale*1.5)
        for f in self.fing_R_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
        for f in self.midd_R_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
        for f in self.base_R_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
        for f in self.fing_L_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
        for f in self.midd_L_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
        for f in self.base_L_collider: f.node().setIntoCollideMask(BitMask32.bit(0))
    def deviceChecker(self, task):
        if self.leap.is_connected: 
            if len(self.leap.frame().hands) is 0:
                self.errorMsg.setText("please place the hand above the device to start")
                return Task.cont
            else:
                base.cTrav = self.cTrav # @UndefinedVariable
                self.errorMsg.setText("")
                self.menuBG.detachNode()
                taskMgr.remove("handUpdater")  # @UndefinedVariable
                self.handLoop = taskMgr.add(self.handUpdater, "handUpdater") # @UndefinedVariable
                self.handLoop.last = 0
                self.homeInitial()
                return Task.done
        else: 
            self.errorMsg.setText("please connect device")
            return Task.cont
    def buttonCreator(self, buttonRoot):
        button = loader.loadModel("models/button") # @UndefinedVariable
        button.setScale(0.3,0.4,0.25)
        button.reparentTo(self.buttonList[buttonRoot]) # @UndefinedVariable
        buttonMesh = button.find("**/mesh_button")
        myTexture = self.loader.loadTexture('tex/start_%i.png' %(buttonRoot+1))
        buttonMesh.setTexture(myTexture,1)
        buttonCollider = button.find("**/collider_button")
        buttonCollider.node().setFromCollideMask(BitMask32.bit(0))
        self.cTrav.addCollider(buttonCollider, self.cHandler)
    def cubeCreator(self, i, cubeRoot):
        global tempCubeList
        cube = loader.loadModel("models/cube") # @UndefinedVariable
        print(i)
        cube.reparentTo(tempCubeList[i][0]) # @UndefinedVariable
        cubeMesh = cube.find("**/mesh_cube")
        myTexture = self.loader.loadTexture('cubes/tex_%i.jpg' %(cubeRoot))
        cubeMesh.setTexture(myTexture,1)
        cubeSphere = cube.find("**/collider_cube")
        cubeSphere.node().setFromCollideMask(BitMask32.bit(0))
        self.cTrav.addCollider(cubeSphere, self.cHandler)
    def clamp(self, i, mn=0, mx=1):
        return min(max(i, mn), mx)    
    def setLight(self):
        #self.ambientText = self.makeStatusLabel(0)
        self.ambientLight = self.render.attachNewNode(AmbientLight("ambientLight")) 
        # Set the color of the ambient light
        self.ambientLight.node().setColor((1, 1, 1, 1))
        self.render.setLight(self.ambientLight)
        
        self.directionalLight = self.render.attachNewNode(
            DirectionalLight("directionalLight"))
        self.directionalLight.node().setColor((.35, .35, .35, 1))
        # The direction of a directional light is set as a 3D vector
        self.directionalLight.node().setDirection(Vec3(1, 1, -2))
        # These settings are necessary for shadows to work correctly
        self.directionalLight.setY(6)
        dlens = self.directionalLight.node().getLens()
        dlens.setFilmSize(41, 21)
        dlens.setNearFar(50, 75)
        self.render.setLight(self.directionalLight)
        self.color = self.directionalLight.node().getColor()
        h, s, b = colorsys.rgb_to_hsv(self.color[0], self.color[1], self.color[2])
        brightness = self.clamp(b + 0)
        r, g, b = colorsys.hsv_to_rgb(h, s, brightness)
        self.directionalLight.node().setColor((r, g, b, 1))
        
        self.lightSourceSphere = self.loader.loadModel('models/sphere')
        self.lightSourceSphere.setColor((1, 1, 1, 1))
        self.lightSourceSphere.setPos(0,STAGE_HEIGHT+4,3)
        self.lightSourceSphere.setScale(.25)
        self.lightSource = self.lightSourceSphere.attachNewNode(PointLight("lightSource"))
        self.lightSource.node().setAttenuation(Vec3(1, 0.04, 0.1))
        self.lightSource.node().setColor((1, 1, 1, 1))
        self.lightSource.node().setSpecularColor((1, 1, 1, 1))
        self.render.setLight(self.lightSource)
        
    def homeInitial(self):
        global gameStart
        global returnHome
        global tryAgain
        gameStart = False
        tryAgain = False
        returnHome = False
        
        self.menuBG.reparentTo(self.render)
        myTexture = self.loader.loadTexture('tex/home.jpg')
        self.menuBG.setTexture(myTexture,1)
        
        self.buttonList[0].reparentTo(self.render)
        self.buttonList[0].setPosHpr(-6, STAGE_HEIGHT-1, 0, -90, 0, -105)
        
        taskMgr.remove("homeTask")  # @UndefinedVariable
        self.menu = taskMgr.add(self.homeTask, "homeTask") # @UndefinedVariable
        self.menu.last = 0
    def homeTask(self, task):
        global gameStart
        if pointable_finger is None: return Task.cont
        for i in range(len(self.buttonList)):
            buttonPressed = Vec3(1,1,1)
            for f in range(self.cHandler.getNumEntries()):
                entry = self.cHandler.getEntry(f)
                tipName = entry.getIntoNode().getName()
                name = entry.getFromNode().getName()
                if name == "collider_button" and tipName == fingerTip[pointable_finger.type]: 
                    if self.buttonPress(entry, i): buttonPressed= (Vec3(1.1,1.1,1.1))
            self.buttonList[i].setScale(buttonPressed)
        if gameStart: 
            self.stage.reparentTo(self.render)
            self.buttonList[0].detachNode()
            self.menuBG.detachNode()
            self.gameInitial(len(picture_names), True)
            taskMgr.remove("inGameTask") # @UndefinedVariable
            self.inGameTaskLoop = taskMgr.add(self.inGameTask, "inGameTask") # @UndefinedVariable
            self.inGameTaskLoop.last = 0
            gameStart = False        
            return Task.done
        else: return Task.cont
    def scoreInitial(self):
        global gameStart
        global returnHome
        global tryAgain
        global answer
        global renderedCube
        global score
        global question_list
        question_list.clear()
        gameStart = False
        tryAgain = False
        returnHome = False
        scoreCubes = []
        for i in range(len(renderedCube)): 
            taskMgr.remove("physicsTask_%i" % (i)) # @UndefinedVariable
            if len(answer)>i: self.cargos[i][0].removeNode()
            tempCubeList[i][0].removeNode()
        self.image.removeNode()
        self.cargos.clear()
        renderedCube.clear()
        tempCubeList.clear()
        answer.clear()
        self.train.setPosHpr(16, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
        self.train.detachNode()
        self.stage.detachNode()
        self.tracks.detachNode()
        self.timer.setText("")
        self.score.setText("")
        
        self.menuBG.reparentTo(self.render)
        myTexture = self.loader.loadTexture('tex/score.jpg')
        self.menuBG.setTexture(myTexture,1)
        
        for i in range(len(str(score))):        
            temp = cubeList.index(str(score)[i])
            scoreCubes.append(loader.loadModel("models/cube"))# @UndefinedVariable
            scoreCubes[i].reparentTo(self.render) # @UndefinedVariable
            scoreCubes[i].setPos(3.5+(int(i)*2.4),STAGE_HEIGHT+2.5-(i*0.1),-1)
            scoreCubes[i].setHpr(0,-2,-15)
            cubeMesh = scoreCubes[i].find("**/mesh_cube")
            myTexture = self.loader.loadTexture('cubes/tex_%i.jpg' %(temp))
            cubeMesh.setTexture(myTexture,1)
        
        self.buttonList[1].reparentTo(self.render)
        self.buttonList[1].setPosHpr(-7, STAGE_HEIGHT-5, 0, -90, 0, -105)
        
        self.buttonList[2].reparentTo(self.render)
        self.buttonList[2].setPosHpr(8.5, STAGE_HEIGHT-5, 0, -90, 0, -105)
        
        taskMgr.remove("scoreTask")  # @UndefinedVariable
        self.scoreLoop = taskMgr.add(self.scoreTask, "scoreTask", extraArgs = [scoreCubes], appendTask=True) # @UndefinedVariable
        self.scoreLoop.last = 0   
        score = 0     
    def scoreTask(self, scoreCubes, task):
        global tryAgain
        global returnHome
        for i in range(len(self.buttonList)):
            buttonPressed = Vec3(1,1,1)
            for f in range(self.cHandler.getNumEntries()):
                entry = self.cHandler.getEntry(f)
                tipName = entry.getIntoNode().getName()
                name = entry.getFromNode().getName()
                if name == "collider_button" and tipName == fingerTip[pointable_finger.type]: 
                    if self.buttonPress(entry, i): buttonPressed= (Vec3(1.1,1.1,1.1))
            self.buttonList[i].setScale(buttonPressed)
        if tryAgain: 
            self.stage.reparentTo(self.render)
            for f in scoreCubes: f.removeNode()
            scoreCubes.clear()
            self.buttonList[1].detachNode()
            self.buttonList[2].detachNode()
            self.menuBG.detachNode()
            self.gameInitial(len(picture_names),True)
            taskMgr.remove("inGameTask") # @UndefinedVariable
            self.inGameTaskLoop = taskMgr.add(self.inGameTask, "inGameTask") # @UndefinedVariable
            self.inGameTaskLoop.last = 0
            return task.done
        elif returnHome:
            for f in scoreCubes: f.removeNode()
            scoreCubes.clear()
            self.menuBG.detachNode()
            self.buttonList[1].detachNode()
            self.buttonList[2].detachNode()
            self.homeInitial()
            return task.done            
        else: return task.cont
    def gameInitial(self, question, englishGame):
        global answer
        global gameStart
        global returnHome
        global tryAgain
        global score
        global question_list
        gameStart = False
        tryAgain = False
        returnHome = False
        tempQuestion= ""
        
        self.score.setText("Score: %i" % (score))
        self.ballAccelV = GRAVITY
        self.tracks.reparentTo(self.render)
        self.trainV = Vec3(0,0,0)
        self.train.reparentTo(self.render)
        self.trainV = Vec3(-5,0,0)
        if(englishGame):
            temp = randint(0, question-1)
            while temp in question_list: temp = randint(0, question-1)
            tempQuestion = picture_names[temp][:picture_names[temp].index('.')]
            print(tempQuestion)
            question_list.append(temp)
            self.image = self.loadImageAsPlane("images/%s" % (picture_names[temp]))
            self.image.reparentTo(self.render)
            self.image.setScale(self.image.getScale()*1.2)
            self.image.setPosHpr(0,STAGE_HEIGHT+3.5,-11, 90, 270, 90)
            self.image.setTransparency(TransparencyAttrib.MAlpha)
            self.image.setAlphaScale(1)
            self.cargos = [[self.loader.loadModel("models/cargo"), -1] for i in range(len(tempQuestion))] # @UndefinedVariable
            for i in range(len(self.cargos)):
                self.cargos[i][0].reparentTo(self.render)
                self.cargos[i][0].setScale(1,0.3,0.3)
                self.cargos[i][0].setScale(1,0.32,0.32)
                if i == 0:self.cargos[i][0].setPosHpr(self.train.getX()+2.5, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
                else: self.cargos[i][0].setPosHpr(self.cargos[i-1][0].getX()+2, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
    
            taskMgr.remove("trainMovingTask") # @UndefinedVariable
            self.trainEnter = taskMgr.add(self.trainMovingTask, "trainMovingTask", extraArgs = [True], appendTask=True ) # @UndefinedVariable
            self.trainEnter.last = 0
            
            usedPos = random.sample(range(0, 10), 10)
            for i in range(10):
                if i<len(tempQuestion):
                    temp = cubeList.index(tempQuestion[i])
                    answer.append(temp)
                    self.assignCube(temp, i, usedPos)
                else: 
                    temp = randint(10,35)
                    while temp in answer: temp = randint(10,35)
                    self.assignCube(temp, i, usedPos)
        else:
            temp = randint(0, question-1)
            while temp in question_list: temp = randint(0, question-1)
            tempQuestion = picture_names[temp][:picture_names[temp].index('.')]
            question_list.append(temp)
            self.image = self.loadImageAsPlane("images/%s" % (picture_names[temp]))
            self.image.reparentTo(self.render)
            self.image.setScale(self.image.getScale()*1.2)
            self.image.setPosHpr(0,STAGE_HEIGHT+3.5,-11, 90, 270, 90)
            self.image.setTransparency(TransparencyAttrib.MAlpha)
            self.image.setAlphaScale(1)
            self.cargos = [[self.loader.loadModel("models/cargo"), -1] for i in range(len(tempQuestion))] # @UndefinedVariable
            for i in range(len(self.cargos)):
                self.cargos[i][0].reparentTo(self.render)
                self.cargos[i][0].setScale(1,0.3,0.3)
                self.cargos[i][0].setScale(1,0.32,0.32)
                if i == 0:self.cargos[i][0].setPosHpr(self.train.getX()+2.5, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
                else: self.cargos[i][0].setPosHpr(self.cargos[i-1][0].getX()+2, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
    
            taskMgr.remove("trainMovingTask") # @UndefinedVariable
            self.trainEnter = taskMgr.add(self.trainMovingTask, "trainMovingTask", extraArgs = [True], appendTask=True ) # @UndefinedVariable
            self.trainEnter.last = 0
            
            usedPos = random.sample(range(0, 10), 10)
            for i in range(10):
                if i<len(tempQuestion):
                    temp = cubeList.index(tempQuestion[i])
                    answer.append(temp)
                    self.assignCube(temp, i, usedPos)
                else: 
                    temp = randint(10,35)
                    while temp in answer: temp = randint(10,35)
                    self.assignCube(temp, i, usedPos)
    def assignCube(self, temp, i, usedPos):
        global renderedCube   
        global tempCubeList
        pos = len(tempCubeList)
        renderedCube.append(temp) 
        tempCubeList.append([render.attachNewNode("cubeRoot_%i"  % (temp)), Vec3(randint(-3, 3),7,randint(-3, 3))]) # @UndefinedVariable
        self.cubeCreator(pos,temp) 
            
        tempCubeList[pos][0].reparentTo(self.render)
        tempCubeList[pos][0].setPos(cubesPosList[usedPos[i]])
        tempCubeList[pos][0].setHpr(0,0,0)
        taskMgr.remove("physicsTask_%i" % (i)) # @UndefinedVariable
        self.physicsTaskLoop = taskMgr.add(self.physicsTask, "physicsTask_%i" % (i),extraArgs = [pos], appendTask=True) # @UndefinedVariable
        self.physicsTaskLoop.last = 0 
    
    def inGameTask(self, task):
        global gameSuccess
        global score
        global gameInter
        global timer
        secs = timer - int(task.time)
        mins = int(secs/60)
        self.timer.setText('{:02d}:{:02d}'.format(mins, secs%60))
            
        if secs <= -1:
            #score= score+22
            gameInter= False
            self.errorMsg.setText("")
            taskMgr.remove("trainMovingTask")  # @UndefinedVariable
            self.scoreInitial()
            return Task.done
        if gameInter: return Task.cont
        fail = True
        gameSuccess = True
        for i in range(len(answer)):
            if self.cargos[i][1] == -1: fail = False
            if answer[i] != renderedCube[self.cargos[i][1]]:
                gameSuccess = False
        if gameSuccess: 
            self.errorMsg.setText("Success")
            score = score +1
            self.score.setText("Score: %i" % (score))
            gameInter = True
            taskMgr.remove("trainMovingTask") # @UndefinedVariable
            self.trainLeaving = taskMgr.add(self.trainMovingTask, "trainMovingTask", extraArgs = [False], appendTask=True ) # @UndefinedVariable
            self.trainLeaving.last = 0
            
        elif fail: self.errorMsg.setText("FAIL")
        else: self.errorMsg.setText("")
        return Task.cont
    def buttonPress(self, colEntry, button):
        global gameStart
        global returnHome
        global tryAgain
        if colEntry.getFromNodePath().getPos(self.buttonList[button]).length() == 0:
            norm = colEntry.getSurfaceNormal(render) * -1 # The normal of the hand # @UndefinedVariable
            handCurSpeed = self.handV.length()                # The current hand speed
            hitDir = colEntry.getSurfacePoint(render) - self.buttonList[button].getPos() # @UndefinedVariable
            hitDir.normalize()                            
            hitAngle = self.dotProduct(norm, hitDir)
            if hitAngle > 0 and handCurSpeed>100 and self.handV[2]<-1: 
                if button == 0: gameStart = True
                elif button == 1: returnHome = True
                elif button == 2: tryAgain = True
            return True
        else: return False
    def trainMovingTask(self, arriving, task):
        global tempCubeList
        global answer
        global renderedCube
        global gameInter
        dt = task.time - task.last
        task.last = task.time
        if dt > .1: return Task.cont 
        if arriving:
            if self.train.getX()<0:  self.trainV += Vec3(1,0,0)* dt * trainAccel[len(answer)]
            self.train.setPos(self.train.getPos() + (self.trainV * dt))
            for f in self.cargos: f[0].setPos(f[0].getPos() + (self.trainV * dt))
            if self.trainV[0]>0:
                self.trainV = Vec3(0,0,0)
                return Task.done
        else: 
            self.trainV += Vec3(-1,0,0)* dt * trainAccel[len(answer)]
            self.train.setPos(self.train.getPos() + (self.trainV * dt))
            for i in range(len(answer)): 
                newPos = self.cargos[i][0].getPos() + (self.trainV * dt)
                self.cargos[i][0].setPos(newPos)
                tempCubeList[self.cargos[i][1]][0].setPos(newPos+Vec3(0,1.4,0))
            if self.cargos[len(answer)-1][0].getX()<-16:
                for i in range(len(renderedCube)): 
                    if len(answer)>i: self.cargos[i][0].remove_node()
                    tempCubeList[i][0].removeNode()
                self.image.removeNode()
                tempCubeList.clear()
                renderedCube.clear()
                self.cargos.clear()
                answer.clear()
                gameInter = False
                self.train.setPosHpr(16, STAGE_HEIGHT+0.3, 12, 90, 180, 90)
                self.gameInitial(len(picture_names),True)
                return task.done
        return Task.cont            
    def physicsTask(self, cube, task):
        global trigger_pinch
        global trigger_pinch_threshold
        global lastPinchFrame
        global pinch_cube
        if gameInter: return task.done
        isLoaded = False
        dt = task.time - task.last
        task.last = task.time
        if dt > .1: return Task.cont 
        df = 0
        if trigger_pinch and cube == pinch_cube: 
            lastPinchFrame = task.time
            trigger_pinch_threshold = True
        else: df = task.time - lastPinchFrame
        
        if cube == pinch_cube:
            if df < 0.1  and trigger_pinch_threshold is True and trigger_pinch is False: 
                cubeP = tempCubeList[pinch_cube][0].getPos()
                for f in self.cargos:
                    cargoP = f[0].getPos()
                    if cubeP[0]>cargoP[0]-1 and cubeP[0]<cargoP[0]+1 and cubeP[1] > cargoP[1] and cubeP[1] < cargoP[1]+4 and cubeP[2]>cargoP[2]-3 and cubeP[2]<cargoP[2]+3:
                        tempCubeList[pinch_cube][0].setPos(cargoP+Vec3(0,1.4,0))
                        lastPinchFrame = 0
                        trigger_pinch_threshold = False
                        f[1] = pinch_cube
                        pinch_cube = -1
                
                if trigger_pinch_threshold:
                    currentPos = self.thowingTask(False)
                    if currentPos.length() >0:
                        tempCubeList[cube][0].setPos(currentPos)
                    else: 
                        lastPinchFrame = 0
                        trigger_pinch_threshold = False
            
            elif df >= 0.1  and trigger_pinch_threshold is True: 
                lastPinchFrame = 0
                trigger_pinch_threshold = False
                pinch_cube = -1
                tempCubeList[cube][1] = self.thowingTask(True)
        for f in self.cargos:
            if f[1] == cube: 
                isLoaded=True
                
        if isLoaded : return Task.cont
        elif cube == pinch_cube and trigger_pinch_threshold: return Task.cont
        
        #if trigger_pinch_threshold is False:
        for i in range(self.cHandler.getNumEntries()):
            entry = self.cHandler.getEntry(i)
            name = entry.getIntoNode().getName()
            if name == "palm_L_collider": self.handCollideHandler(entry, cube)
            elif name == "palm_R_collider": self.handCollideHandler(entry, cube)
            elif name == "floor": self.wallCollideHandler(entry, cube)
            elif name == "wall_B": self.wallCollideHandler(entry, cube)
            elif name == "wall_F": self.wallCollideHandler(entry, cube)
            elif name == "wall_R": self.wallCollideHandler(entry, cube)
            elif name == "wall_L": self.wallCollideHandler(entry, cube)
            elif name == "collider_cube": self.cubeCollideHandler(entry, cube)
            elif trigger_pinch_threshold is False: self.handCollideHandler(entry, cube)
        
        tempCubeList[cube][1] += self.ballAccelV * dt * ACCEL
        if tempCubeList[cube][1].lengthSquared() > MAX_SPEED_SQ:
            tempCubeList[cube][1].normalize()
            tempCubeList[cube][1] *= MAX_SPEED
        tempCubeList[cube][0].setPos(tempCubeList[cube][0].getPos() + (tempCubeList[cube][1] * dt))
        return Task.cont
    def thowingTask(self, thowing):
        global pinch_position
        global pinch_finger
        self.frame = self.leap.frame()
        temp = self.frame.hands[pinch_finger[0]].palm_velocity
        releaseHandV = Vec3((temp[0], temp[1], temp[2]))/self.scale
        thumb_tip = self.frame.hands[pinch_finger[0]].fingers[0].bone(3).next_joint
        joint_position = self.frame.hands[pinch_finger[0]].fingers[pinch_finger[1]].bone(3).next_joint
        distance = thumb_tip - joint_position
        release_position = joint_position + Vector(distance[0]/2, distance[1]/2, distance[2]/2)
        release_position = Vec3((release_position[0], release_position[1], release_position[2]))/self.scale
        if thowing is True: 
            thowingV = release_position-pinch_position
            pinch_finger = [-1,-1]
            return releaseHandV
        else: 
            return release_position
    def dotProduct(self, pos1, pos2):
        v1 = (round(pos1[0], 8),round(pos1[1], 8),round(pos1[2], 8))
        v2 = (round(pos2[0], 8),round(pos2[1], 8),round(pos2[2], 8))
        v1_u = v1 / numpy.linalg.norm(v1)
        v2_u = v2 / numpy.linalg.norm(v2)
        return numpy.dot(v1_u, v2_u)
    def cubeCollideHandler(self, colEntry, cube):
        if colEntry.getFromNodePath().getPos(tempCubeList[cube][0]).length() == 0:
            ballV=Vec3(0,0,0)
            tempCubeList[cube][1] = ballV
            disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) # @UndefinedVariable
            newPos = tempCubeList[cube][0].getPos() + disp
            tempCubeList[cube][0].setPos(newPos)        
    def handCollideHandler(self, colEntry, cube):
        if colEntry.getFromNodePath().getPos(tempCubeList[cube][0]).length() == 0:
            norm = colEntry.getSurfaceNormal(render) * -1               # The normal of the hand # @UndefinedVariable
            curSpeed = tempCubeList[cube][1].length()                 # The current ball speed
            inVec = tempCubeList[cube][1] / curSpeed                  # The direction of ball travel
            velAngle = self.dotProduct(norm, inVec)     
            totalV = Vec3(tempCubeList[cube][1][0]+self.handV[0],tempCubeList[cube][1][1]+self.handV[1],tempCubeList[cube][1][2]+self.handV[2])
            ballV=Vec3(totalV[0]/10,totalV[1]/10,totalV[2]/10)
            if velAngle > 0:
                tempCubeList[cube][1] = ballV
                disp = (colEntry.getSurfacePoint(render) - colEntry.getInteriorPoint(render)) # @UndefinedVariable
                newPos = tempCubeList[cube][0].getPos() + disp
                tempCubeList[cube][0].setPos(newPos)        
    def wallCollideHandler(self, colEntry, cube):
        if colEntry.getFromNodePath().getPos(tempCubeList[cube][0]).length() == 0:
            ballV=Vec3(-tempCubeList[cube][1][0],tempCubeList[cube][1][1],tempCubeList[cube][1][2])
            if colEntry.getIntoNode().getName() == "wall_F" or colEntry.getIntoNode().getName() == "wall_B":
                ballV=Vec3(tempCubeList[cube][1][0],tempCubeList[cube][1][1],-tempCubeList[cube][1][2])
            elif colEntry.getIntoNode().getName() == "floor": 
                ballV=Vec3(tempCubeList[cube][1][0]/2,-tempCubeList[cube][1][1]/2,tempCubeList[cube][1][2]/2)
                if ballV[2]<0.01: ballV[2] =0
            tempCubeList[cube][1] = ballV
            disp = (colEntry.getSurfacePoint(render)- colEntry.getInteriorPoint(render)) # @UndefinedVariable
            newPos = tempCubeList[cube][0].getPos() + disp
            tempCubeList[cube][0].setPos(newPos)
    def handUpdater(self, task):
        self.frame = self.leap.frame()
        global trigger_pinch
        pointables = self.frame.pointables
        trigger_pinch = False
        rightHand=None
        if len(self.frame.hands)>0:  
            front_pointable = pointables.frontmost
            for hand in self.frame.hands:
                if(hand.is_left and rightHand==None):
                    self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, self.frame.hands[0], 0, front_pointable)
                    rightHand=False
                elif(hand.is_right and rightHand==None):
                    self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, self.frame.hands[0], 0, front_pointable)
                    rightHand=True
                if(len(self.frame.hands)>1):
                    if(rightHand):
                        self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, self.frame.hands[1], 0, front_pointable)
                    else:
                        self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, self.frame.hands[1], 0, front_pointable)
                else:
                    if(rightHand):
                        self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, None, None, front_pointable)
                    else:
                        self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, None, None, front_pointable)
        else:
            self.plotHand(self.palm_L, self.fing_L, self.midd_L, self.base_L, None, None, None)
            self.plotHand(self.palm_R, self.fing_R, self.midd_R, self.base_R, None, None, None)
            rightHand=None
        return Task.cont
    def plotHand(self, palm, fingerTips, fingerMiddles, fingerbases, leapHand, pinchHand, front_pointable):
        global pinch_finger
        global pointable_position
        global pointable_finger
        usedFingers = 0
        palmValid = False
        if(leapHand and leapHand.is_valid):
            palmValid = True
            palm_position, palm_quat = self.calcTrafo(leapHand.palm_position, -leapHand.palm_normal, self.ez, self.scale)
            palm.setPos(palm_position)
            #print(palm_position[2])
            palm.setQuat(palm_quat)
            thumb_tip = leapHand.fingers[0].bone(3).next_joint
            self.handV=Vec3(leapHand.palm_velocity[0], leapHand.palm_velocity[1], leapHand.palm_velocity[2])
            for i in range(len(leapHand.fingers)):
                lf = leapHand.fingers[i]                
                if lf.is_valid:
                    if i>0 and len(answer) >0: self.updatePinch(leapHand, thumb_tip, lf)
                    if trigger_pinch is True: 
                        pinch_finger[0] = pinchHand
                        pinch_finger[1] = i
                    bf = fingerTips[usedFingers]
                    bm = fingerMiddles[usedFingers]
                    bb = fingerbases [usedFingers]
                    usedFingers += 1
                    
                    bf.reparentTo(self.render)
                    tip_position, tip_quat = self.calcTrafo(lf.bone(3).next_joint, -lf.bone(3).direction, self.ex, self.scale)
                    bf.setPos(tip_position)
                    bf.setQuat(tip_quat)
                    
                    if str(front_pointable) == str(lf):
                        pointable_position = tip_position
                        pointable_finger = lf
                    
                    bm.reparentTo(self.render)
                    m1 = lf.bone(3).next_joint+lf.bone(3).direction*30
                    m2 = lf.bone(2).next_joint-m1
                    mid_position, mid_quat = self.calcTrafo(m1, lf.bone(2).direction, self.ex, self.scale)
                    #mid_position, mid_quat = self.calcTrafo(m1, m2, self.ex, self.scale)
                    bm.setPos(mid_position)
                    bm.setQuat(mid_quat)
                    
                    
                    bb.reparentTo(self.render)
                    b1 = lf.bone(2).next_joint+lf.bone(2).direction*30
                    b2 = leapHand.palm_position-b1
                    #base_position, base_quat = self.calcTrafo(b1, lf.bone(1).direction, self.ex, self.scale)
                    base_position, base_quat = self.calcTrafo(b1, b2, self.ex, self.scale)
                    bb.setPos(base_position)
                    bb.setQuat(base_quat)
                    
        if palmValid: palm.reparentTo(self.render)
        else: palm.detachNode()
        for i in range(usedFingers,5):
            fingerTips[i].detachNode()
            fingerMiddles[i].detachNode()
            fingerbases[i].detachNode()            
    def updatePinch(self, hand, tip, finger):
        global tempCubeList
        global trigger_pinch
        global pinch_position
        global pinch_cube
        joint_position = finger.bone(3).next_joint
        distance = tip - joint_position
        if distance.magnitude < 35:
            trigger_pinch = True
            pinch_position = joint_position + Vector(distance[0]/2, distance[1]/2, distance[2]/2)
            pinch_position = Vec3((pinch_position[0], pinch_position[1], pinch_position[2]))/self.scale
            
        if trigger_pinch is True:
            temp = 1.5
            for i in range(len(tempCubeList)):
                distance = pinch_position - tempCubeList[i][0].getPos()
                distance = Vector(distance[0], distance[1], distance[2])
                if distance.magnitude<temp: 
                    temp = distance.magnitude
                    self.unLoadedCube(i) 
                    pinch_cube = i
            if temp < 1.5: 
                tempCubeList[pinch_cube][0].setPos(pinch_position)
                trigger_pinch = True
            else: trigger_pinch = False
    def unLoadedCube(self, cube):
        for f in self.cargos:
            if f[1] == cube: 
                f[1]=-1
    def calcTrafo(self, leapPosition, leapDirection, e_i, scale):
        position = Vec3((leapPosition[0], leapPosition[1], leapPosition[2]))/scale
        direction = Vec3((leapDirection[0], leapDirection[1], leapDirection[2])).normalized()
        ang  = e_i.angleDeg(direction)
        axis = e_i.cross(direction).normalized()
        return position, LRotationf(axis, ang)
예제 #36
0
class Player(GameObject):
    def __init__(self,
                 modelName,
                 model_anims,
                 max_health,
                 speed,
                 collider_name,
                 base,
                 pos,
                 hpr=Vec3(0, 0, 0),
                 scale=1.0):
        GameObject.__init__(self, modelName, model_anims, max_health, speed,
                            collider_name, base, pos, hpr, scale)
        self.player_init()

    def player_init(self):
        self.base.pusher.addCollider(self.collider, self.actor)
        self.base.cTrav.addCollider(self.collider, self.base.pusher)
        self.collider.setPythonTag("player", self)

        self.score = 0
        self.score_string = str(self.score)

        # self.base.camLens.setFov(150) #----------------------------------------------
        # self.base.camLens.setFov(5)

        self.textObject = OnscreenText(text='Score:' + self.score_string,
                                       pos=(-1.15, -0.95),
                                       scale=0.1)

        self.ray = CollisionRay(0, 0, 0, 0, -1, 0)

        rayNode = CollisionNode("playerRay")
        rayNode.addSolid(self.ray)

        self.rayNodePath = self.actor.attachNewNode(rayNode)
        self.rayQueue = CollisionHandlerQueue()

        self.base.cTrav.addCollider(self.rayNodePath, self.rayQueue)

        # self.damagePerSecond = -5.0
        self.beamModel = self.base.loader.loadModel("models/frowney")
        self.beamModel.reparentTo(self.actor)
        self.beamModel.setZ(10)

        self.beamModel.setLightOff()
        self.beamModel.hide()

    def move(self, movement_vector):
        anim_controller = self.actor.getAnimControl("walk")
        if not anim_controller.isPlaying():
            self.actor.play("walk")
        self.actor.setPos(self.actor, movement_vector * self.speed)

    def stop(self):
        anim_controller = self.actor.getAnimControl("walk")
        anim_controller.stop()

    def change_health(self, dHealth):
        GameObject.change_health(self, dHealth)
        if self.health == 0:
            #     imageOnject = OnscreenImage(image = "game_over.png")
            self.cleanup()
            sys.exit()

    def update_score(self):
        self.score_string = str(self.score)
        self.textObject.destroy()
        self.textObject = OnscreenText(text='Score:' + self.score_string,
                                       pos=(-1.15, -0.95),
                                       scale=0.1)

    def shoot(self):
        dt = globalClock.getDt()
        # print(self.rayQueue.getNumEntries())
        # print(self.rayQueue)
        if self.rayQueue.getNumEntries() > 0:
            self.rayQueue.sortEntries()
            rayHit = self.rayQueue.getEntry(1)
            hitPos = rayHit.getSurfacePoint(self.base.render)
            # print(hitPos, "hitpos")
            # print(rayHit, "rayhit")
            # beamLength = (hitPos - self.actor.getPos()).length()
            # print("length: ", beamLength)

            hitNodePath = rayHit.getIntoNodePath()
            # print(hitNodePath)
            # print(hitNodePath.getPythonTag)
            # print(hitPos)
            # print(hitNodePath.getTag)
            # print(hitNodePath.hasPythonTag("enemy"))
            # print(rayHit.getFrom())
            if hitNodePath.hasPythonTag("enemy"):
                # print("here")
                hitObject = hitNodePath.getPythonTag("enemy")
                hitObject.change_health(-1)

                # Find out how long the beam is, and scale the
                # beam-model accordingly.
                # print(self.actor.getPos())
                beamLength = (hitPos - (self.actor.getPos())).length()
                self.beamModel.setSy(-beamLength)
                self.score += 1
                self.update_score()
                self.beamModel.show()
            else:
                # If we're not shooting, don't show the beam-model.
                self.beamModel.hide()
예제 #37
0
class DistributedLevel(DistributedObject):
    """ An instance of these is created and placed in the middle of
    the zone.  It serves to illustrate the creation of AI-side objects
    to populate the world, and a general mechanism for making them
    react to the avatars. """
    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        #self.model = loader.loadModel('environment')
        #self.model.setZ(0)
        #self.builder = Builder(self, "map.txt", "development")

        plane = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0)))
        cnode = CollisionNode('cnode')
        cnode.setIntoCollideMask(BitMask32.bit(1))
        cnode.setFromCollideMask(BitMask32.bit(1))
        cnode.addSolid(plane)
        self.planeNP = self.model.attachNewNode(cnode)
        self.planeNP.show()

        # Setup a traverser for the picking collisions
        self.picker = CollisionTraverser()
        # Setup mouse ray
        self.pq = CollisionHandlerQueue()
        # Create a collision Node
        pickerNode = CollisionNode('MouseRay')
        # set the nodes collision bitmask
        pickerNode.setFromCollideMask(BitMask32.bit(1))
        # create a collision ray
        self.pickerRay = CollisionRay()
        # add the ray as a solid to the picker node
        pickerNode.addSolid(self.pickerRay)
        # create a nodepath with the camera to the picker node
        self.pickerNP = base.camera.attachNewNode(pickerNode)
        # add the nodepath to the base traverser
        self.picker.addCollider(self.pickerNP, self.pq)

        print "model loaded"
        #TODO: check how to load multiple levels and set players in specific levels!
        self.accept("mouse1", self.mouseClick)

    def announceGenerate(self):
        """ This method is called after generate(), after all of the
        required fields have been filled in.  At the time of this call,
        the distributed object is ready for use. """
        DistributedObject.announceGenerate(self)

        # Now that the object has been fully manifested, we can parent
        # it into the scene.
        print "render the model"
        self.model.reparentTo(render)

    def disable(self):
        # Take it out of the scene graph.
        self.detachNode()

        DistributedObject.disable(self)

    def checkMousePos(self, mpos, camPos, camHpr):
        lens = LenseNode.copyLens(base.camNode)
        lens.setPos(camPos)
        lens.setHpr(camHpr)
        help(mpos)
        mpos = Point2(mpos.x, mpos.y)
        pos = self.getClickPosition(mpos, lens)
        print "mouse clicked at:", pos

    def mouseClick(self):
        """Send an event to the server that will check where the mouse
        will hit and what action needs to be done"""
        hitPos = (0, 0, 0)
        # check if we have a mouse on the window
        if base.mouseWatcherNode.hasMouse():
            # get the mouse position on the screen
            mpos = base.mouseWatcherNode.getMouse()
            print mpos
            # set the ray's position
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            # Now call the traverse function to let the traverser check for collisions
            # with the added colliders and the levelNP
            self.picker.traverse(self.planeNP)
            # check if we have a collision
            if self.pq.getNumEntries() > 0:
                # sort the entries to get the closest first
                self.pq.sortEntries()
                # This is the point at where the mouse ray and the level plane intersect
                hitPos = self.pq.getEntry(0).getSurfacePoint(render)
        base.messenger.send("clickPosition", [hitPos])
예제 #38
0
class World(ShowBase):

    def __init__(self):

        # Load the default configuration.prc. This is recommended, as it
        # contains some important panda options
        loadPrcFile("../../Config/configuration.prc")

        ShowBase.__init__(self)

        # Create a new pipeline instance
        self.renderPipeline = RenderingPipeline(self)

        # Set the base path for the pipeline. This is required as we are in
        # a subdirectory
        self.renderPipeline.getMountManager().setBasePath("../../")

        # Also set the write path
        self.renderPipeline.getMountManager().setWritePath("../../Temp/")

        # Load the default settings
        self.renderPipeline.loadSettings("../../Config/pipeline.ini")

        # Now create the pipeline
        self.renderPipeline.create()

        # Add a directional light
        dPos = Vec3(40, 40, 15)
        dirLight = DirectionalLight()
        dirLight.setPos(dPos * 1000000.0)
        dirLight.setShadowMapResolution(1024)
        dirLight.setCastsShadows(True)
        dirLight.setColor(Vec3(8))
        self.renderPipeline.addLight(dirLight)
        self.renderPipeline.setScatteringSource(dirLight)
        self.dirLight = dirLight



        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0}
        base.win.setClearColor(Vec4(0, 0, 0, 1))

        # Post the instructions

        self.title = addTitle(
            "Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward")
        self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left")
        self.inst7 = addInstructions(0.65, "[S]: Rotate Camera Right")

        # Set up the environment
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)
        self.environ.setPos(0, 0, 0)

        self.environ.find("**/wall").removeNode()

        # Create the main character, Ralph
        ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor("models/ralph",
                           {"run": "models/ralph-run",
                            "walk": "models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos)

        self.renderPipeline.setEffect(self.ralph, "Effects/Default/Default.effect", {
                "dynamic": True
            })

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("arrow_up", self.setKey, ["forward", 1])
        self.accept("a", self.setKey, ["cam-left", 1])
        self.accept("s", self.setKey, ["cam-right", 1])
        self.accept("arrow_left-up", self.setKey, ["left", 0])
        self.accept("arrow_right-up", self.setKey, ["right", 0])
        self.accept("arrow_up-up", self.setKey, ["forward", 0])
        self.accept("a-up", self.setKey, ["cam-left", 0])
        self.accept("s-up", self.setKey, ["cam-right", 0])

        # NOTICE: It is important that your update tasks have a lower priority
        # than -10000
        taskMgr.add(self.move, "moveTask", priority=-20000)

        self.accept("r", self.reloadShader)

        # Game state variables
        self.isMoving = False

        # Set up the camera

        base.disableMouse()
        base.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 1.2)

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

        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 1000)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 1000)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

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

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        # self.cTrav.showCollisions(render)


        # Create some ocean
        self.water = ProjectedWaterGrid(self.renderPipeline)
        self.water.setWaterLevel(-4.0)

        # Create the skybox
        self.skybox = self.renderPipeline.getDefaultSkybox()
        self.skybox.reparentTo(render)

        self.prepareSRGB(render)
        self.reloadShader()
        self.renderPipeline.onSceneInitialized()

        # Add demo slider to move the sun position
        if self.renderPipeline.settings.displayOnscreenDebugger:
            self.renderPipeline.guiManager.demoSlider.node[
                "command"] = self.setSunPos
            self.renderPipeline.guiManager.demoSlider.node[
                "value"] = 50

    def setSunPos(self):
        rawValue = self.renderPipeline.guiManager.demoSlider.node["value"]
        dPos = Vec3(100, 100, rawValue - 20)
        self.dirLight.setPos(dPos * 100000000.0)

        
    def reloadShader(self):
        self.renderPipeline.reloadShaders()

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

    def prepareSRGB(self, np):
        """ Sets the correct texture format for all textures found in <np> """
        for tex in np.findAllTextures():

            baseFormat = tex.getFormat()

            if baseFormat == Texture.FRgb:
                tex.setFormat(Texture.FSrgb)
            elif baseFormat == Texture.FRgba:
                tex.setFormat(Texture.FSrgbAlpha)
            else:
                print "Unkown texture format:", baseFormat
                print "\tTexture:", tex

            # tex.setMinfilter(Texture.FTLinearMipmapLinear)
            # tex.setMagfilter(Texture.FTLinear)
            tex.setAnisotropicDegree(16)

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

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        base.camera.lookAt(self.ralph)
        if (self.keyMap["cam-left"] != 0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["cam-right"] != 0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())

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

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if (self.keyMap["left"] != 0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"] != 0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"] != 0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0) or (self.keyMap["right"] != 0):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 7.0):
            base.camera.setPos(base.camera.getPos() + camvec * (camdist - 7))
            camdist = 7.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec * (5 - camdist))
            camdist = 5.0

        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(),
                                      x.getSurfacePoint(render).getZ()))
        if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.

        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(),
                                      x.getSurfacePoint(render).getZ()))
        if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.5):
            base.camera.setZ(self.ralph.getZ() + 2.5)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.

        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        return task.cont
예제 #39
0
class Weapon(DirectObject):
    def __init__(self, _main, _name, _fireRate, _dmg=20,_mountSlot=0, weaponType="Pistol"):
        self.main = _main
        self.name = _name
        self.fireRate = _fireRate
        self.dmg = _dmg
        self.weaponType = weaponType
        self.mountSlot = _mountSlot

        self.muzzleFlash = loader.loadModel("muzzleflash")
        if weaponType == "Pistol":
            self.style = "OneHand"
            self.model = loader.loadModel("Pistol")
            self.muzzleFlash.setZ(0.65)
            self.muzzleFlash.setX(-0.04)
            self.muzzleFlash.setScale(0.25)
            self.muzzleFlash.find('**/+SequenceNode').node().setFrameRate(20)
        else:
            self.style = "TwoHand"
            self.model = loader.loadModel("MG")
            self.muzzleFlash.setZ(0.65)
            self.muzzleFlash.setX(0.08)
            self.muzzleFlash.setScale(0.3)
            self.muzzleFlash.find('**/+SequenceNode').node().setFrameRate(20)
        self.model.setY(2)
        self.muzzleFlash.reparentTo(self.model)
        self.muzzleFlash.find('**/+SequenceNode').node().stop()
        self.muzzleFlash.hide()

        # Load bullet model
        self.bullet = loader.loadModel("Bullet")
        self.bullet.setP(-90)
        self.bullet.setH(180)
        #self.bullet.setPos(0, 0.5, 0)

        # Control
        self.isFiring = False

        # Collision Stuff
        self.wepRay = None
        # Make weapon ray
        self.setupRay()
        self.model.show()

    def setAmmo(self):
        pass

    def setupRay(self):
        self.shootTraverser = CollisionTraverser()
        self.shootingQH = CollisionHandlerQueue()
        #self.shootingEH = CollisionHandlerEvent()
        #self.shootingEH.addInPattern('into-%in')
        # Create a collision Node
        shootNode = CollisionNode('WeaponRay')
        # set the nodes collision bitmask
        shootNode.setFromCollideMask(BitMask32.bit(1))
        # create a collision segment (ray like)
        self.shootRay = CollisionSegment()
        shootNode.addSolid(self.shootRay)
        #self.pickerNP = self.main.player.model.attachNewNode(pickerNode)
        self.shootNP = render.attachNewNode(shootNode)
        #self.shootTraverser.addCollider(self.shootNP, self.shootingEH)
        self.shootTraverser.addCollider(self.shootNP, self.shootingQH)
        #self.shootNP.show()

    def doFire(self, _toPos=(0, 0, 0)):
        self.isFiring = True

        if self.weaponType == "Pistol":
            self.muzzleFlash.find('**/+SequenceNode').node().play(0, 1)
        else:
            self.muzzleFlash.find('**/+SequenceNode').node().loop(True)
        self.muzzleFlash.show()

        # For some reason the mouse ray end up at posZ -1 (which causes a problem when we make the enemy spheres smaller in radius)
        # so here for now.. ill make a quick fix.
        adjustedZ = (_toPos[0], _toPos[1], 0)

        self.shootRay.setPointA(self.main.player.model.getPos())
        self.shootRay.setPointB(adjustedZ)

        fromPos = self.main.player.model.getPos() #self.model.getPos()
        #self.setProjectile(fromPos, adjustedZ)#_toPos)

        self.shootTraverser.traverse(self.main.enemyParent)
        if self.shootingQH.getNumEntries() > 0:
            self.shootingQH.sortEntries()
            enemyCol = self.shootingQH.getEntry(0).getIntoNodePath().node().getName()
            base.messenger.send("into-" + enemyCol, [self.dmg])

    def stopFire(self):
        if self.weaponType == "Pistol" and \
               self.muzzleFlash.find('**/+SequenceNode').node().isPlaying():
            taskMgr.add(self.waitForFrame, "waitForFrame")
            return
        self.muzzleFlash.find('**/+SequenceNode').node().stop()
        self.muzzleFlash.hide()

    def waitForFrame(self, task):
        if self.muzzleFlash.find('**/+SequenceNode').node().isPlaying():
            return task.cont
        self.muzzleFlash.find('**/+SequenceNode').node().stop()
        self.muzzleFlash.hide()

    def reload(self):
        pass

    def setProjectile(self, _from, _to):
        self.bullet.reparentTo(render)#self.model)
        # setup the projectile interval
        #self.bulletProjectile = ProjectileInterval(self.bullet,
        #                                startPos = Point3(_from),
        #                                duration = 1,
        #                                endPos = Point3(_to))
        #self.bulletProjectile = self.bullet.posInterval(1.0, Point3(_to), startPos=Point3(_from))
        #self.bulletProjectile = LerpPosInterval(self.bullet, 2.0, _to, _from)
        print "POSITIONS:"
        print _to
        print _from
        frm = render.getPos(self.main.player.model)
        print frm

        self.bulletProjectile = LerpPosInterval(self.bullet, 1.0, _to, _from)
        self.bulletProjectile.start()
예제 #40
0
class Fighter():
    def __init__(self,characterPath , callOnDeath , side , name = None):
        #side indicates if the player is on the left or right side.
        #TODO: add collision tests against ring-out geometry in the arena, 
        

        self.fsm = FighterFsm(self,characterPath)    
        self.inputHandler = InputHandler(self.fsm,side)
        
        self.side = side
        
        self.wins = 0 #counting won rounds, a double-ko/draw counts as win for both.
        self.faceOpp = True  #looking at opponent
        self.callOnDeath = callOnDeath
        
        self.statusBitMask = BitMask32()
        self.defenseBitMask = BitMask32()    #active defense parts get a 1
        #the attack bitmask is generated by the fsm and passed to the attack method directly
    
        if not name:
            name = "player"+str(1+bool(side))
        
        self.healthBar = PlayerHud(side, name )
          
        self.fighterNP = render.attachNewNode(name)
        self.collTrav = CollisionTraverser(name)
        fromObject = self.fighterNP.attachNewNode(CollisionNode('colNode'+name))
        fromObject.node().addSolid(CollisionRay(0, 0, 2,0,0, -1))
        fromObject.node().setFromCollideMask(BitMask32.bit(1))
        fromObject.node().setIntoCollideMask(BitMask32.allOff())
        self.queue = CollisionHandlerQueue()
        self.collTrav.addCollider(fromObject, self.queue)
        
        self.fsm.getNP().reparentTo(self.fighterNP)
        #fromObject.show() #more debug collision visuals
        #self.collTrav.showCollisions(render) #debug visuals for collision     
        self.prepareFighter()
   
   
    def updateState(self,newState = None):
        if newState:
            if "enter" + state in dir(self.fsm):
                self.fsm.forceTransition(newState)
        else:
            self.inputHandler.pollEvents()          
        
    def prepareFighter(self):
        taskMgr.remove("player"+str(self.side))
        self.speed = (0,0)
        self.fsm.forceTransition("Idle")
        self.health= 100
        self.healthBar.setHealth(self.health)
        self.healthBar.setRoundIndicator('V'*self.wins)
        
        if self.side:
            self.fighterNP.setX(5)
        else:
            self.fighterNP.setX(-5)
        self.fighterNP.setY(0)
        taskMgr.add(self._playertask, "player"+str(self.side))
    
    def setStatusBitMask(self,bitmask):
        self.statusBitMask = bitmask
        
    def setDefenseBitMask(self,bitmask):
        self.defenseBitMask = bitmask 
   
    #getters and setters are a bit stupid here. properties from python 3 would be nice
    def fighterWin(self):
        #request a win-anim from the fsm if there are any
        self.wins += 1
        self.healthBar.setRoundIndicator('V'*self.wins)
    
    def getWins(self):
        return self.wins   
    
    def getHealth(self):
        return self.health
        
    def getNP(self):
        return self.fighterNP

    def setOpponent(self,opponent):
        self.opponent = opponent
        self.fighterNP.lookAt(self.opponent.getNP())
   
    def attack(self,attackBitMask,attackrange,damageHit,damageDodge=0,angle=30): #those variables will be supplied by the fsm states later on. 
                                                             #function is pretty redundant... for structure only, and for early days
        attackstatus = self.opponent.getAttacked(attackBitMask,attackrange,damageHit,damageDodge,angle)
        return attackstatus
    
    def _testHit(self,node1,node2,threshold=30, dist = 1):  #node1 which looks for a target , node2 is the target , threshold is the max-attack-angle, dist the dist
          dirVec = node1.getRelativePoint(node2,Vec3(0,0,0))
          dirVec = Vec3(dirVec[0],dirVec[1],dirVec[2])
          
          dirVec.normalize()
          angle = dirVec.angleDeg(Vec3(0,1,0))
          if angle < threshold and dist > node1.getDistance(node2):
            #print "hit at "+str(angle)+" degree!"
            return True
          else:
            #print angle,node1.getDistance(node2)
            return False
        
    def getAttacked(self,attackBitMask,attackrange,damageHit,damageDodge=0,angle = 30):
        """
        returns 0 if not hit, 1 if hit was blocked, 2 if hit, 3 for hit+KO 
        """
        if self.health <=0:
            return 4 #player is ko already
            

        if  not self._testHit(self.opponent.getNP(),self.fighterNP  ,angle,attackrange )  : #instead of 0, a sligtly positive values makes thinks look better.
            #attack misses due to out of range.
            return 0 

        if (self.statusBitMask & attackBitMask).getWord() == 0: # attak misses cause the player avoided it. went low or so.
            return 0
  
        if (self.defenseBitMask & attackBitMask).getWord():
            self.health -= damageDodge
            self.healthBar.setHealth(self.health)
            return 1 #hit,... but blocked so no combos 
            
        else:
            self.health -= damageHit
            self.healthBar.setHealth(self.health)
            if self.health <= 0 : #if KO
                taskMgr.remove("player"+str(self.side))
                self.fsm.forceTransition("Ko")
                #actually make the match.py allow the other player to KO (in case of doubleKO,befor calling round end.
                taskMgr.doMethodLater(0.5,self.callOnDeath,"RoundEnd") 
                return 3
            #TODO: requesting the same state as you are in doesnt work well.sorta need to re-enter the hit state
            if "Crouch" in self.fsm.state:
                self.fsm.forceTransition("CrouchHit")
            elif self.fsm.state:
                self.fsm.forceTransition("Hit")
            return 2 #regular hit
    
    def setSpeed(self,x,y):
        self.speed = (x,y)
    
    def faceOpponent(self,facing):
        self.faceOpp = facing #true if yuo look at the other player (usualy true unless attacking), so you can dodge an attack by evading.
    
    def _playertask(self,task):
        
        oldpos = self.fighterNP.getPos()
        
        dist = self.fighterNP.getY(self.opponent.getNP()) 

        if dist > 3 or self.speed[0]<0: #prevert players from walking throug each other , too troublesome atm
            self.fighterNP.setX(self.fighterNP,self.speed[1]*globalClock.getDt())
            self.fighterNP.setY(self.fighterNP,self.speed[0]*globalClock.getDt())
        else :
            self.speed = ( min(2,self.speed[0] ), self.speed[1])
            #also push back other player
            self.opponent.getNP().setY(self.opponent.getNP(),-self.speed[0]*globalClock.getDt() )
            
        self.collTrav.traverse(render)
        self.queue.sortEntries()
        for i in range(self.queue.getNumEntries()):
            entry = self.queue.getEntry(i)
            if "ground" in entry.getIntoNodePath().getName() :
                break
            if "out" in entry.getIntoNodePath().getName() :
                pass #ring out
                self.fighterNP.setPos(oldpos) #for now reset him as we have no ring-out anim yet #TODO: add ring out anim!
                break
            
        if self.queue.getNumEntries() == 0:
            #if there is no ground and no ring out, propably a wall or no thin like that. just reset the pos     
            self.fighterNP.setPos(oldpos)
            print "resetting fighter"
            
        if self.faceOpp:
            self.fighterNP.lookAt(self.opponent.getNP())      
                
        return task.cont
class SmartCamera:
    UPDATE_TASK_NAME = 'update_smartcamera'
    notify = directNotify.newCategory('SmartCamera')

    def __init__(self):
        self.cTrav = CollisionTraverser('cam_traverser')
        base.pushCTrav(self.cTrav)
        self.cTrav.setRespectPrevTransform(1)
        self.default_pos = None
        self.parent = None
        self.initialized = False
        self.started = False
        self.camFloorRayNode = None
        self.ccRay2 = None
        self.ccRay2Node = None
        self.ccRay2NodePath = None
        self.ccRay2BitMask = None
        self.ccRay2MoveNodePath = None
        self.camFloorCollisionBroadcaster = None
        self.notify.debug('SmartCamera initialized!')
        return

    def lerpCameraFov(self, fov, time):
        taskMgr.remove('cam-fov-lerp-play')
        oldFov = base.camLens.getHfov()
        if abs(fov - oldFov) > 0.1:

            def setCamFov(fov):
                base.camLens.setMinFov(fov / (4.0 / 3.0))

            self.camLerpInterval = LerpFunctionInterval(setCamFov, fromData=oldFov, toData=fov, duration=time, name='cam-fov-lerp')
            self.camLerpInterval.start()

    def setCameraFov(self, fov):
        self.fov = fov
        if not (self.isPageDown or self.isPageUp):
            base.camLens.setMinFov(self.fov / (4.0 / 3.0))

    def initCameraPositions(self):
        camHeight = max(base.localAvatar.getHeight(), 3.0)
        nrCamHeight = base.localAvatar.getHeight()
        heightScaleFactor = camHeight * 0.3333333333
        defLookAt = Point3(0.0, 1.5, camHeight)
        self.firstPersonCamPos = Point3(0.0, 0.7, nrCamHeight * 5.0)
        scXoffset = 3.0
        scPosition = (Point3(scXoffset - 1, -10.0, camHeight + 5.0), Point3(scXoffset, 2.0, camHeight))
        self.cameraPositions = [
         (Point3(0.0, -9.0 * heightScaleFactor, camHeight),
          defLookAt,
          Point3(0.0, camHeight, camHeight * 4.0),
          Point3(0.0, camHeight, camHeight * -1.0),
          0),
         (
          Point3(0.0, 0.7, camHeight),
          defLookAt,
          Point3(0.0, camHeight, camHeight * 1.33),
          Point3(0.0, camHeight, camHeight * 0.66),
          1),
         (
          Point3(5.7 * heightScaleFactor, 7.65 * heightScaleFactor, camHeight + 2.0),
          Point3(0.0, 1.0, camHeight),
          Point3(0.0, 1.0, camHeight * 4.0),
          Point3(0.0, 1.0, camHeight * -1.0),
          0),
         (
          Point3(0.0, 8.65 * heightScaleFactor, camHeight),
          Point3(0.0, 1.0, camHeight),
          Point3(0.0, 1.0, camHeight * 4.0),
          Point3(0.0, 1.0, camHeight * -1.0),
          0),
         (
          Point3(0.0, -24.0 * heightScaleFactor, camHeight + 4.0),
          defLookAt,
          Point3(0.0, 1.5, camHeight * 4.0),
          Point3(0.0, 1.5, camHeight * -1.0),
          0),
         (
          Point3(0.0, -12.0 * heightScaleFactor, camHeight + 4.0),
          defLookAt,
          Point3(0.0, 1.5, camHeight * 4.0),
          Point3(0.0, 1.5, camHeight * -1.0),
          0)]

    def pageUp(self):
        if not base.localAvatar.avatarMovementEnabled:
            return
        if not self.isPageUp:
            self.isPageDown = 0
            self.isPageUp = 1
            self.lerpCameraFov(70, 0.6)
            self.setCameraPositionByIndex(self.cameraIndex)
        else:
            self.clearPageUpDown()

    def pageDown(self):
        if not base.localAvatar.avatarMovementEnabled:
            return
        if not self.isPageDown:
            self.isPageUp = 0
            self.isPageDown = 1
            self.lerpCameraFov(70, 0.6)
            self.setCameraPositionByIndex(self.cameraIndex)
        else:
            self.clearPageUpDown()

    def clearPageUpDown(self):
        if self.isPageDown or self.isPageUp:
            self.lerpCameraFov(self.fov, 0.6)
            self.isPageDown = 0
            self.isPageUp = 0
            self.setCameraPositionByIndex(self.cameraIndex)

    def nextCameraPos(self, forward):
        if not base.localAvatar.avatarMovementEnabled:
            return
        self.__cameraHasBeenMoved = 1
        if forward:
            self.cameraIndex += 1
            if self.cameraIndex > len(self.cameraPositions) - 1:
                self.cameraIndex = 0
        else:
            self.cameraIndex -= 1
            if self.cameraIndex < 0:
                self.cameraIndex = len(self.cameraPositions) - 1
        self.setCameraPositionByIndex(self.cameraIndex)

    def setCameraPositionByIndex(self, index):
        self.notify.debug('switching to camera position %s' % index)
        self.setCameraSettings(self.cameraPositions[index])

    def setCameraSettings(self, camSettings):
        self.setIdealCameraPos(camSettings[0])
        if self.isPageUp and self.isPageDown or not self.isPageUp and not self.isPageDown:
            self.__cameraHasBeenMoved = 1
            self.setLookAtPoint(camSettings[1])
        else:
            if self.isPageUp:
                self.__cameraHasBeenMoved = 1
                self.setLookAtPoint(camSettings[2])
            else:
                if self.isPageDown:
                    self.__cameraHasBeenMoved = 1
                    self.setLookAtPoint(camSettings[3])
                else:
                    self.notify.error('This case should be impossible.')
        self.__disableSmartCam = camSettings[4]
        if self.__disableSmartCam:
            self.putCameraFloorRayOnAvatar()
            self.cameraZOffset = 0.0

    def set_default_pos(self, pos):
        self.default_pos = pos

    def get_default_pos(self):
        return self.default_pos

    def set_parent(self, parent):
        self.parent = parent

    def get_parent(self):
        return self.parent

    def getVisibilityPoint(self):
        return Point3(0.0, 0.0, base.localAvatar.getHeight())

    def setLookAtPoint(self, la):
        self.__curLookAt = Point3(la)

    def getLookAtPoint(self):
        return Point3(self.__curLookAt)

    def setIdealCameraPos(self, pos):
        self.__idealCameraPos = Point3(pos)
        self.updateSmartCameraCollisionLineSegment()

    def getIdealCameraPos(self):
        return Point3(self.__idealCameraPos)

    def getCompromiseCameraPos(self):
        if self.__idealCameraObstructed == 0:
            compromisePos = self.getIdealCameraPos()
        else:
            visPnt = self.getVisibilityPoint()
            idealPos = self.getIdealCameraPos()
            distance = Vec3(idealPos - visPnt).length()
            ratio = self.closestObstructionDistance / distance
            compromisePos = idealPos * ratio + visPnt * (1 - ratio)
            liftMult = 1.0 - ratio * ratio
            compromisePos = Point3(compromisePos[0], compromisePos[1], compromisePos[2] + base.localAvatar.getHeight() * 0.4 * liftMult)
        compromisePos.setZ(compromisePos[2] + self.cameraZOffset)
        return compromisePos

    def updateSmartCameraCollisionLineSegment(self):
        pointB = self.getIdealCameraPos()
        pointA = self.getVisibilityPoint()
        vectorAB = Vec3(pointB - pointA)
        lengthAB = vectorAB.length()
        if lengthAB > 0.001:
            self.ccLine.setPointA(pointA)
            self.ccLine.setPointB(pointB)

    def initializeSmartCamera(self):
        self.__idealCameraObstructed = 0
        self.closestObstructionDistance = 0.0
        self.cameraIndex = 0
        self.cameraPositions = []
        self.auxCameraPositions = []
        self.cameraZOffset = 0.0
        self.setGeom(render)
        self.__onLevelGround = 0
        self.__camCollCanMove = 0
        self.__disableSmartCam = 0
        self.initializeSmartCameraCollisions()
        self._smartCamEnabled = False
        self.isPageUp = 0
        self.isPageDown = 0
        self.fov = CIGlobals.DefaultCameraFov

    def enterFirstPerson(self):
        self.stop_smartcamera()
        if hasattr(self.get_parent(), 'toon_head'):
            head = self.get_parent().toon_head
            camera.reparentTo(head)
        camera.setPos(0, -0.35, 0)
        camera.setHpr(0, 0, 0)

    def exitFirstPerson(self):
        self.initialize_smartcamera()
        self.initialize_smartcamera_collisions()
        self.start_smartcamera()

    def putCameraFloorRayOnAvatar(self):
        self.camFloorRayNode.setPos(base.localAvatar, 0, 0, 5)

    def putCameraFloorRayOnCamera(self):
        self.camFloorRayNode.setPos(self.ccSphereNodePath, 0, 0, 0)

    def recalcCameraSphere(self):
        nearPlaneDist = base.camLens.getNear()
        hFov = base.camLens.getHfov()
        vFov = base.camLens.getVfov()
        hOff = nearPlaneDist * math.tan(deg2Rad(hFov / 2.0))
        vOff = nearPlaneDist * math.tan(deg2Rad(vFov / 2.0))
        camPnts = [Point3(hOff, nearPlaneDist, vOff),
         Point3(-hOff, nearPlaneDist, vOff),
         Point3(hOff, nearPlaneDist, -vOff),
         Point3(-hOff, nearPlaneDist, -vOff),
         Point3(0.0, 0.0, 0.0)]
        avgPnt = Point3(0.0, 0.0, 0.0)
        for camPnt in camPnts:
            avgPnt = avgPnt + camPnt

        avgPnt = avgPnt / len(camPnts)
        sphereRadius = 0.0
        for camPnt in camPnts:
            dist = Vec3(camPnt - avgPnt).length()
            if dist > sphereRadius:
                sphereRadius = dist

        avgPnt = Point3(avgPnt)
        self.ccSphereNodePath.setPos(avgPnt)
        self.ccSphereNodePath2.setPos(avgPnt)
        self.ccSphere.setRadius(sphereRadius)

    def setGeom(self, geom):
        self.__geom = geom

    def initializeSmartCameraCollisions(self):
        if self.initialized:
            return
        self.ccTrav = CollisionTraverser('LocalAvatar.ccTrav')
        self.ccLine = CollisionSegment(0.0, 0.0, 0.0, 1.0, 0.0, 0.0)
        self.ccLineNode = CollisionNode('ccLineNode')
        self.ccLineNode.addSolid(self.ccLine)
        self.ccLineNodePath = base.localAvatar.attachNewNode(self.ccLineNode)
        self.ccLineBitMask = CIGlobals.CameraBitmask
        self.ccLineNode.setFromCollideMask(self.ccLineBitMask)
        self.ccLineNode.setIntoCollideMask(BitMask32.allOff())
        self.camCollisionQueue = CollisionHandlerQueue()
        self.ccTrav.addCollider(self.ccLineNodePath, self.camCollisionQueue)
        self.ccSphere = CollisionSphere(0, 0, 0, 1)
        self.ccSphereNode = CollisionNode('ccSphereNode')
        self.ccSphereNode.addSolid(self.ccSphere)
        self.ccSphereNodePath = base.camera.attachNewNode(self.ccSphereNode)
        self.ccSphereNode.setFromCollideMask(CIGlobals.CameraBitmask)
        self.ccSphereNode.setIntoCollideMask(BitMask32.allOff())
        self.camPusher = CollisionHandlerPusher()
        self.camPusher.addCollider(self.ccSphereNodePath, base.camera)
        self.camPusher.setCenter(base.localAvatar)
        self.ccPusherTrav = CollisionTraverser('LocalAvatar.ccPusherTrav')
        self.ccSphere2 = self.ccSphere
        self.ccSphereNode2 = CollisionNode('ccSphereNode2')
        self.ccSphereNode2.addSolid(self.ccSphere2)
        self.ccSphereNodePath2 = base.camera.attachNewNode(self.ccSphereNode2)
        self.ccSphereNode2.setFromCollideMask(CIGlobals.CameraBitmask)
        self.ccSphereNode2.setIntoCollideMask(BitMask32.allOff())
        self.camPusher2 = CollisionHandlerPusher()
        self.ccPusherTrav.addCollider(self.ccSphereNodePath2, self.camPusher2)
        self.camPusher2.addCollider(self.ccSphereNodePath2, base.camera)
        self.camPusher2.setCenter(base.localAvatar)
        self.camFloorRayNode = base.localAvatar.attachNewNode('camFloorRayNode')
        self.ccRay = CollisionRay(0.0, 0.0, 0.0, 0.0, 0.0, -1.0)
        self.ccRayNode = CollisionNode('ccRayNode')
        self.ccRayNode.addSolid(self.ccRay)
        self.ccRayNodePath = self.camFloorRayNode.attachNewNode(self.ccRayNode)
        self.ccRayBitMask = CIGlobals.FloorBitmask
        self.ccRayNode.setFromCollideMask(self.ccRayBitMask)
        self.ccRayNode.setIntoCollideMask(BitMask32.allOff())
        self.ccTravFloor = CollisionTraverser('LocalAvatar.ccTravFloor')
        self.camFloorCollisionQueue = CollisionHandlerQueue()
        self.ccTravFloor.addCollider(self.ccRayNodePath, self.camFloorCollisionQueue)
        self.ccTravOnFloor = CollisionTraverser('LocalAvatar.ccTravOnFloor')
        self.ccRay2 = CollisionRay(0.0, 0.0, 0.0, 0.0, 0.0, -1.0)
        self.ccRay2Node = CollisionNode('ccRay2Node')
        self.ccRay2Node.addSolid(self.ccRay2)
        self.ccRay2NodePath = self.camFloorRayNode.attachNewNode(self.ccRay2Node)
        self.ccRay2BitMask = CIGlobals.FloorBitmask
        self.ccRay2Node.setFromCollideMask(self.ccRay2BitMask)
        self.ccRay2Node.setIntoCollideMask(BitMask32.allOff())
        self.ccRay2MoveNodePath = hidden.attachNewNode('ccRay2MoveNode')
        self.camFloorCollisionBroadcaster = CollisionHandlerFloor()
        self.camFloorCollisionBroadcaster.setInPattern('on-floor')
        self.camFloorCollisionBroadcaster.setOutPattern('off-floor')
        self.camFloorCollisionBroadcaster.addCollider(self.ccRay2NodePath, self.ccRay2MoveNodePath)
        self.cTrav.addCollider(self.ccRay2NodePath, self.camFloorCollisionBroadcaster)
        self.initialized = True

    def deleteSmartCameraCollisions(self):
        del self.ccTrav
        del self.ccLine
        del self.ccLineNode
        self.ccLineNodePath.removeNode()
        del self.ccLineNodePath
        del self.camCollisionQueue
        del self.ccRay
        del self.ccRayNode
        self.ccRayNodePath.removeNode()
        del self.ccRayNodePath
        del self.ccRay2
        del self.ccRay2Node
        self.ccRay2NodePath.removeNode()
        del self.ccRay2NodePath
        self.ccRay2MoveNodePath.removeNode()
        del self.ccRay2MoveNodePath
        del self.ccTravOnFloor
        del self.ccTravFloor
        del self.camFloorCollisionQueue
        del self.camFloorCollisionBroadcaster
        del self.ccSphere
        del self.ccSphereNode
        self.ccSphereNodePath.removeNode()
        del self.ccSphereNodePath
        del self.camPusher
        del self.ccPusherTrav
        del self.ccSphere2
        del self.ccSphereNode2
        self.ccSphereNodePath2.removeNode()
        del self.ccSphereNodePath2
        del self.camPusher2
        self.initialized = False

    def startUpdateSmartCamera(self):
        if self.started:
            return
        self.__floorDetected = 0
        self.__cameraHasBeenMoved = 1
        self.recalcCameraSphere()
        self.__instantaneousCamPos = camera.getPos()
        self.cTrav.addCollider(self.ccSphereNodePath, self.camPusher)
        self.ccTravOnFloor.addCollider(self.ccRay2NodePath, self.camFloorCollisionBroadcaster)
        self.__disableSmartCam = 0
        self.__lastPosWrtRender = camera.getPos(render) + 1
        self.__lastHprWrtRender = camera.getHpr(render) + 1
        taskName = base.localAvatar.taskName('updateSmartCamera')
        taskMgr.remove(taskName)
        taskMgr.add(self.updateSmartCamera, taskName, priority=47)
        self.started = True

    def stopUpdateSmartCamera(self):
        self.cTrav.removeCollider(self.ccSphereNodePath)
        self.ccTravOnFloor.removeCollider(self.ccRay2NodePath)
        taskName = base.localAvatar.taskName('updateSmartCamera')
        taskMgr.remove(taskName)
        camera.setPos(self.getIdealCameraPos())
        self.started = False

    def updateSmartCamera(self, task):
        if not self.__camCollCanMove and not self.__cameraHasBeenMoved:
            if self.__lastPosWrtRender == camera.getPos(render):
                if self.__lastHprWrtRender == camera.getHpr(render):
                    return Task.cont
        self.__cameraHasBeenMoved = 0
        self.__lastPosWrtRender = camera.getPos(render)
        self.__lastHprWrtRender = camera.getHpr(render)
        self.__idealCameraObstructed = 0
        if not self.__disableSmartCam:
            self.ccTrav.traverse(self.__geom)
            if self.camCollisionQueue.getNumEntries() > 0:
                try:
                    self.camCollisionQueue.sortEntries()
                    self.handleCameraObstruction(self.camCollisionQueue.getEntry(0))
                except AssertionError:
                    pass

            if not self.__onLevelGround:
                self.handleCameraFloorInteraction()
        if not self.__idealCameraObstructed:
            self.nudgeCamera()
        if not self.__disableSmartCam:
            self.ccPusherTrav.traverse(self.__geom)
            self.putCameraFloorRayOnCamera()
        self.ccTravOnFloor.traverse(self.__geom)
        return Task.cont

    def positionCameraWithPusher(self, pos, lookAt):
        camera.setPos(pos)
        self.ccPusherTrav.traverse(self.__geom)
        camera.lookAt(lookAt)

    def nudgeCamera(self):
        CLOSE_ENOUGH = 0.1
        curCamPos = self.__instantaneousCamPos
        curCamHpr = camera.getHpr()
        targetCamPos = self.getCompromiseCameraPos()
        targetCamLookAt = self.getLookAtPoint()
        posDone = 0
        if Vec3(curCamPos - targetCamPos).length() <= CLOSE_ENOUGH:
            camera.setPos(targetCamPos)
            posDone = 1
        camera.setPos(targetCamPos)
        camera.lookAt(targetCamLookAt)
        targetCamHpr = camera.getHpr()
        hprDone = 0
        if Vec3(curCamHpr - targetCamHpr).length() <= CLOSE_ENOUGH:
            hprDone = 1
        if posDone and hprDone:
            return
        lerpRatio = 0.15
        lerpRatio = 1 - pow(1 - lerpRatio, globalClock.getDt() * 30.0)
        self.__instantaneousCamPos = targetCamPos * lerpRatio + curCamPos * (1 - lerpRatio)
        if self.__disableSmartCam or not self.__idealCameraObstructed:
            newHpr = targetCamHpr * lerpRatio + curCamHpr * (1 - lerpRatio)
        else:
            newHpr = targetCamHpr
        camera.setPos(self.__instantaneousCamPos)
        camera.setHpr(newHpr)

    def popCameraToDest(self):
        newCamPos = self.getCompromiseCameraPos()
        newCamLookAt = self.getLookAtPoint()
        self.positionCameraWithPusher(newCamPos, newCamLookAt)
        self.__instantaneousCamPos = camera.getPos()

    def handleCameraObstruction(self, camObstrCollisionEntry):
        collisionPoint = camObstrCollisionEntry.getSurfacePoint(self.ccLineNodePath)
        collisionVec = Vec3(collisionPoint - self.ccLine.getPointA())
        distance = collisionVec.length()
        self.__idealCameraObstructed = 1
        self.closestObstructionDistance = distance
        self.popCameraToDest()

    def handleCameraFloorInteraction(self):
        self.putCameraFloorRayOnCamera()
        self.ccTravFloor.traverse(self.__geom)
        if self.__onLevelGround:
            return
        if self.camFloorCollisionQueue.getNumEntries() == 0:
            return
        self.camFloorCollisionQueue.sortEntries()
        camObstrCollisionEntry = self.camFloorCollisionQueue.getEntry(0)
        camHeightFromFloor = camObstrCollisionEntry.getSurfacePoint(self.ccRayNodePath)[2]
        self.cameraZOffset = camera.getPos()[2] + camHeightFromFloor
        if self.cameraZOffset < 0:
            self.cameraZOffset = 0
        if self.__floorDetected == 0:
            self.__floorDetected = 1
            self.popCameraToDest()
예제 #42
0
class Labryn(DirectObject):

    def setCamera(self, spin):
        self.spin = spin
    
    def spinCamera(self, task):
        if self.spin == 1: # spin counter-clockwise
            self.cameraSpinCount += 1
            angleDegrees = self.cameraSpinCount
            angleRadians =  angleDegrees * (pi/ 180)
            self.CAM_RAD = angleRadians
            camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R) 
            camera.setHpr(angleDegrees,-65,0)
        elif self.spin == 2: # spin clockwise
            self.cameraSpinCount  -= 1
            angleDegrees = self.cameraSpinCount
            angleRadians =  angleDegrees * (pi/ 180)
            self.CAM_RAD = angleRadians
            camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
            camera.setHpr(angleDegrees,-65,0)
        elif self.spin == 3: # ZOOM IN not spin
            self.cameraZoomCount += 1
            deltaR = self.cameraZoomCount * 0.1
            new_R = 12-deltaR
            self.CAM_R = new_R
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*new_R)
        elif self.spin == 4: # ZOOM OUT
            self.cameraZoomCount -= 1
            deltaR = self.cameraZoomCount * 0.1
            new_R = 12-deltaR
            self.CAM_R = new_R
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
                          
        return Task.cont

    def checkMouse(self, task):
        if base.mouseWatcherNode.hasMouse():
            self.mouseX=base.mouseWatcherNode.getMouseX()
            self.mouseY=base.mouseWatcherNode.getMouseY()
        return Task.cont

    def dropRock(self):
        if self.pokeMoveChoice == 1: # selected Geodude
            result = MAZE.canDropRock(self.rockX, self.rockY)
            if result != False: # can place rock here
                MAZE.dropRock(result[0],result[1])
                self.rock.setPos(self.rockX, self.rockY, 1)
                self.rockOnMaze = True
                self.pokeMoveChoice = None
                self.myPokeName.hide()
                self.myPokeName = None
                self.updateTwoD()
                self.playerCandyCount -= 1

    def useFlame(self):
        self.onFire = True # on fire
        self.playerCandyCount -= 1
        self.pokeStatus = 1
        self.flame = ParticleEffect()
        self.flame.loadConfig("fireish.ptf")
        self.flame.setPos(self.pikachu.getPos())
        self.flame.start(parent=render, renderParent=render)
        self.updateTwoD()

    def useStringShot(self):
        self.pokeStatus = 2
        self.updateTwoD()

    def placeRock(self, task):
        if self.pokeMoveChoice == 1: # selected Geodude
            dX,dY = ((self.mouseX-self.rockRefX),
                     (self.mouseY-self.rockRefY))
            self.rockX, self.rockY = MAZE.translateRockPosition(self.rockRefX,
                                                      self.rockRefY,
                                                      dX, dY)
            self.rock.show()
            self.rock.setPos(self.rockX, self.rockY, 1)
        self.updateTwoD()
        return Task.cont
    
    def placeRareCandy(self, task):
        if int(task.time) % 4 == 9 and self.candyOnBoard:
            self.candy.hide()
            self.candyOnBoard = False
        if int(task.time) % 10 ==  0 and (self.candyOnBoard == False):
            # every 10 seconds
            self.candy.setPos(MAZE.generateCandyPos())
            self.candy.show()
            self.candyOnBoard = True
        return Task.cont

    def updateTwoD(self):
        # update player candy count
        self.playerCandyStatus.destroy()
        self.playerCandyStatus = candyStatus(0, self.playerCandyCount)
        # update pikachu candy count
        # TODO
        # update my pokes color     
        if self.playerCandyCount == 0 :
            groupHide(self.myPokesBright)
            groupShow(self.myPokesDark)
            # update name
            if self.myPokeName != None:
                self.myPokeName.destroy()

    def clearRock(self):
        self.rock.hide()
        self.rockOnMaze = False
        MAZE.clearRock() # clear it in 2D

    def clearFlame(self):
        self.onFire = False
        self.flame.cleanup()
        self.pokeStatus = 0
        self.pokeMoveChoice = None
        try:
            self.myPokeName.destroy()
        except:
            pass
        self.myPokeName = None

    def clearString(self):
        self.pokeStatus = 0
        self.pokeMoveChoice = None
        try:
            self.myPokeName.destroy()
        except:
            pass
        self.myPokeName = None

        
    def timer(self, task): # deals with moves' lasting effects
        ##############################################################
        if self.rockOnMaze: # rock on maze
            self.rockCounter += 1
        elif self.rockCounter != 1: # rock not on maze, counter not cleared
            self.rockCounter = 0

        if self.onFire:
            self.fireCounter += 1
        elif self.fireCounter != 1:
            self.fireCounter = 0

        if self.pokeStatus == 2: # string shot
            self.stringCounter += 1
        elif self.stringCounter != 1:
            self.stringCounter = 0

        ##################################################################
        if self.rockCounter == 500:
            self.clearRock()

        if self.fireCounter == 80:
            self.clearFlame()

        if self.stringCounter == 120:
            self.clearString()
            
        return Task.cont
    
    def usePokeMove(self, number):
        if self.playerCandyCount > 0: # have more than one candy
            if number == 1 and self.rockOnMaze == False:
                if self.pokeMoveChoice != 1: # NONE or other
                    # set to center position
                    centerx =  base.win.getProperties().getXSize()/2
                    centery =  base.win.getProperties().getYSize()/2
                    base.win.movePointer(0,centerx,centery)
                    self.pokeMoveChoice = 1 # placeRock called here
                    self.rockRefX, self.rockRefY = 0,0
                    self.rock.show()
                    self.rock.setPos(0,0,1)
                else: # already 1
                    self.pokeMoveChoice = None
                    self.clearRock() # clear rock
            elif number == 2:
                if self.pokeMoveChoice != 2:
                    self.pokeMoveChoice = 2
                    self.useFlame()
                else:
                    self.pokeMoveChoice = None
            elif number == 3:
                if self.pokeMoveChoice != 3:
                    self.pokeMoveChoice = 3
                    self.useStringShot()
                else:
                    self.pokeMoveChoice = None
            if self.pokeMoveChoice == None: # no choice
                if self.myPokeName != None: # there is a name on board
                    self.myPokeName.destroy() # kill it
                else: # no name
                    pass
            else: # there is a choice
                if self.myPokeName != None:
                    self.myPokeName.destroy()
                self.myPokeName = Two_D.writePokeName(self.pokeMoveChoice)
  
    def loadRareCandy(self):
        self.candy = Model_Load.loadRareCandy()
        self.candy.reparentTo(render)
        self.candy.setScale(0.1)
        self.candy.hide()
        
    def eatRareCandy(self, task):
        if self.candyOnBoard: # candy on board
            if checkEat(self.ballRoot.getX(), self.ballRoot.getY(),
                        self.candy.getX(), self.candy.getY()): # ball eats
                self.candy.hide() # eaten
                self.candyOnBoard = False
                self.playerCandyCount += 1
                # self.playerCandyStatus.destroy()
                # self.playerCandyStatus = candyStatus(0,
                                       # self.playerCandyCount) # update
                print "BALL EATS CANDY"
                groupShow(self.myPokesBright)

            elif checkEat(self.pikachu.getX(), self.pikachu.getY(),
                          self.candy.getX(), self.candy.getY()):
                self.candy.hide()
                self.candyOnBoard = False
                self.pokemonCandyCount += 1
        return Task.cont

    def setFocus(self, changing):
        self.changingFocus = changing
        if changing == True: # Just Pressed
            self.referenceX, self.referenceY = self.mouseX, self.mouseY
        else: # cursor moves up
            self.referenceX, self.referenceY = None, None

    def resetView(self):
        self.CAM_R, self.CAM_RAD = 12, 0
        self.cameraSpinCount, self.cameraZoomCount = 0, 0
        # _FOCUS = [0,0,0] does not work WHY???
        _FOCUS[0], _FOCUS[1], _FOCUS[2] = 0,0,0
        self.changingFocus = False
        self.referenceX, self.referenceY = None, None
        camera.setPos(_FOCUS[0], _FOCUS[1]-self.CAM_R, 25)
        camera.setHpr(0, -65, 0)
        
    def changeFocus(self, task):
        if (self.changingFocus == True and self.mouseX != None and
            self.mouseY != None ):
            dX, dY = ((self.mouseX - self.referenceX)*0.1,
                      (self.mouseY - self.referenceY)*0.1)
            _FOCUS[0] += dX
            _FOCUS[1] += dY
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
        return Task.cont

    def initialize(self):
        #bgmusic = load_bgmusic("palette.mp3")
        #bgmusic.play()

        self.background = Two_D.loadBackground()
        base.cam2dp.node().getDisplayRegion(0).setSort(-20)
        self.candyOnBoard = False
        self.playerCandyCount, self.pokemonCandyCount = 2, 0
        ######################Rare Candy###############################
        pokes=['caterpie', 'charmander', 'geodude']
        self.myPokesDark = Two_D.loadMyPokemon_Dark(pokes) # my pokemons
        self.myPokesBright = Two_D.loadMyPokemon_Bright()
        groupHide(self.myPokesBright)
        self.loadRareCandy() # load rare candy
        ######################Camera Initialization####################
        self.CAM_R, self.CAM_RAD = 12, 0
        camera.setPos(_FOCUS[0],_FOCUS[1]-12,_FOCUS[2]+25)
        camera.setHpr(0, -65, 0)
        self.cameraSpinCount, self.cameraZoomCount = 0, 0
        self.changingFocus = False
        self.spin = 0
        #######################ICONS###################################
        self.myIcon = Two_D.loadMyIcon()
        self.pokeIcon = Two_D.loadPokeIcon()
        self.playerCandyStatus = candyStatus(0, self.playerCandyCount)
        #######################FLAMES##################################
        base.enableParticles()
        self.fireCounter = 0
        self.onFire = False
        #######################STRINGSHOT#############################
        self.stringCounter = 0
        #######################GLOBALS#################################
        self.i = 0
        self.myDirection = ['zx', 'zy']
        self.rockCounter  = 0
        self.rockX, self.rockY = None, None
        self.rockOnMaze = False
        self.pokeMoveChoice = None
        self.myPokeName = None
        self.arrowKeyPressed = False
        self.pokemonDirection = 'd'
        self.mouseX, self.mouseY = None, None
        # direction the ball is going
        self.jerkDirection = None
        base.disableMouse()
        self.jerk = (0,0,0)
        self.MAZE = Model_Load.loadLabyrinth()
        Control.keyControl(self)
        self.loadPokemonLevel1()
        self.light()
        self.loadBall()
        self.pokeStatus = 0 # 0 is normal, 1 is burned, 2 is slow-speed
        ########################################ROCK###################
        self.rock = Model_Load.loadRock()
        self.rock.reparentTo(render)
        self.rock.hide() # Do not show, but load beforehand for performance
        
    def loadPokemonLevel1(self):
        self.pikachu = load_model("pikachu.egg")
        self.pikachu.reparentTo(render)
        self.pikachu.setScale(0.3)
        endPos = self.MAZE.find("**/end").getPos()
        self.pikachu.setPos(endPos) 
        
    def light(self):
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def loadBall(self):
        self.ballRoot = render.attachNewNode("ballRoot")
        self.ball = load_model("ball")
        self.ball.reparentTo(self.ballRoot)
        self.ball_tex = load_tex("pokeball.png")
        self.ball.setTexture(self.ball_tex,1)
        self.ball.setScale(0.8)
        # Find the collision sphere for the ball in egg.
        self.ballSphere = self.ball.find("**/ball")
        self.ballSphere.node().setFromCollideMask(BitMask32.bit(0))
        self.ballSphere.node().setIntoCollideMask(BitMask32.allOff())
        #self.ballSphere.show()
        # Now we create a ray to cast down at the ball.
        self.ballGroundRay = CollisionRay()
        self.ballGroundRay.setOrigin(0,0,10)
        self.ballGroundRay.setDirection(0,0,-1)

        # Collision solids go in CollisionNode
        self.ballGroundCol =  CollisionNode('groundRay')
        self.ballGroundCol.addSolid(self.ballGroundRay)
        self.ballGroundCol.setFromCollideMask(BitMask32.bit(1))
        self.ballGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol)
        
        # light
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.55, .55, .55, 1))
        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))
        self.ballRoot.setLight(render.attachNewNode(ambientLight))
        self.ballRoot.setLight(render.attachNewNode(directionalLight))
        # material to the ball
        m = Material()
        m.setSpecular(Vec4(1,1,1,1))
        m.setShininess(96)
        self.ball.setMaterial(m,1)

    def __init__(self):
        self.initialize()
        self.WALLS = self.MAZE.find("**/Wall.004")
        self.WALLS.node().setIntoCollideMask(BitMask32.bit(0))
        # collision with the ground. different bit mask
        #self.mazeGround = self.maze.find("**/ground_collide")
        #self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1))
        self.MAZEGROUND = self.MAZE.find("**/Cube.004")
        self.MAZEGROUND.node().setIntoCollideMask(BitMask32.bit(1))
        # add collision to the rock
        cs = CollisionSphere(0, 0, 0, 0.5)
        self.cnodePath = self.rock.attachNewNode(CollisionNode('cnode'))
        self.cnodePath.node().addSolid(cs)
        self.cnodePath.show()
        self.cnodePath.node().setIntoCollideMask(BitMask32.bit(0))
        # load the ball and attach it to the scene.
        # it is on a dummy node so that we can rotate the ball
        # without rotating the ray that will be attached to it

        # CollisionTraversers calculate collisions
        self.cTrav = CollisionTraverser()
        #self.cTrav.showCollisions(render)
        #self.cTrav.showCollisions(render)
        # A list collision handler queue
        self.cHandler = CollisionHandlerQueue()
        # add collision nodes to the traverse.
        # maximum nodes per traverser: 32
        self.cTrav.addCollider(self.ballSphere,self.cHandler)
        self.cTrav.addCollider(self.ballGroundColNp,self.cHandler)
        self.cTrav.addCollider(self.cnodePath, self.cHandler)
        # collision traversers have a built-in tool to visualize collisons
        #self.cTrav.showCollisions(render)
        self.start()

    def pokemonTurn(self, pokemon, direction):
        if direction  == 'l' and self.pokemonDirection != 'l':
            self.pokemonDirection = 'l'
            pokemon.setH(-90)
        if direction  == 'r' and self.pokemonDirection != 'r':
            self.pokemonDirection = 'r'
            pokemon.setH(90)
        if direction  == 'd' and self.pokemonDirection != 'd':
            self.pokemonDirection = 'd'
            pokemon.setH(0)
        if direction  == 'u' and self.pokemonDirection != 'u':
            self.pokemonDirection = 'u'
            pokemon.setH(180)
                        
    def pokemonMove(self, pokemon, direction):
        self.pokemonTurn(pokemon, direction)
        if self.pokeStatus == 0: speed = _SPEED
        elif self.pokeStatus == 1: speed = 0
        else: # self.pokeStatus == 2
            speed = _SPEED/2.0
        if direction == 'l':
            newX = pokemon.getX() - speed
            pokemon.setX(newX)
        elif direction == 'r':
            newX = pokemon.getX() + speed
            pokemon.setX(newX)
        elif direction == 'u':
            newY = pokemon.getY() + speed
            pokemon.setY(newY)
        elif direction == 'd':
            newY = pokemon.getY() - speed
            pokemon.setY(newY)
        elif direction == "s": # stop
            pass
        
    def whereToGo(self, task):
        # this returns the direction pokemon should go
        # tell MAZE pokemon and ball's board position
        print self.myDirection
        MAZE.setPokeCoord(self.pikachu.getX(), self.pikachu.getY(),
                          self.pokemonDirection)
        MAZE.setBallCoord(self.ballRoot.getX(), self.ballRoot.getY())
        # find out which direction to go
        direction = MAZE.getDecision()
        self.pokemonMove(self.pikachu,direction)
        return Task.cont

    def getInformation(self, task):
        # get information on the board
        # TODO
        self.i += 1 # sample every other call to avoid 
        if self.i % 2 == 0:
            dX = self.ballRoot.getX() - self.oldPos[0]
            dY = self.ballRoot.getY() - self.oldPos[1]
            if dX < 0 :
                # print "going left"
                self.myDirection[0] = 'l'
            elif abs(dX) < _EPSILON:
                # print "not moving horiz"
                self.myDirection[0] = 'zx'
            else:
                # print "going right"
                self.myDirection[0] = 'r'

            if dY < 0 :
                # print "going down"
                self.myDirection[1] = 'd'
            elif abs(dY) < _EPSILON:
                # print "not moving verti"
                self.myDirection[1] = 'zy'
            else:
                # print "going up"
                self.myDirection[1] = 'u'
            self.oldPos = self.ballRoot.getPos()
        return Task.cont
    
    def start(self):
        # maze model has a locator in it
        # self.ballRoot.show()
        self.startPos = self.MAZE.find("**/start").getPos()
        self.oldPos = self.MAZE.find("**/start").getPos()
        self.ballRoot.setPos(self.startPos) # set the ball in the pos
        self.ballV = Vec3(0,0,0) # initial velocity
        self.accelV = Vec3(0,0,0) # initial acceleration

        # for a traverser to work, need to call traverser.traverse()
        # base has a task that does this once a frame
        base.cTrav = self.cTrav

        # create the movement task, make sure its not already running
        taskMgr.remove("rollTask")
        taskMgr.add(self.placeRock, "placeRock")
        taskMgr.add(self.timer, "timer")
        taskMgr.add(self.getInformation, "getInformation")
        taskMgr.add(self.eatRareCandy, "eatRareCandy")
        taskMgr.add(self.placeRareCandy, "placeRareCandy")
        taskMgr.add(self.checkMouse, "checkMouse")
        taskMgr.add(self.spinCamera, "spinCamera")
        taskMgr.add(self.changeFocus, "changeFocus")
        taskMgr.add(self.whereToGo, "whereToGo")
        # taskMgr.add(lambda task: self.moveBall(task, self.jerkDirection),
                    # "moveBall")
        taskMgr.add(self.moveBall, "moveBall")
        self.mainLoop = taskMgr.add(self.rollTask, "rollTask")
        self.mainLoop.last = 0

    def moveBallWrapper(self, direction):
        if direction == False:
            self.arrowKeyPressed = False
        else:
            self.arrowKeyPressed = True
            self.jerkDirection = direction
    
    def moveBall(self, task):
        direction = self.jerkDirection
        if self.arrowKeyPressed == True:
            if direction == "u":
                self.jerk = Vec3(0,_JERK,0)
            elif direction == "d":
                self.jerk = Vec3(0,-_JERK,0)
            elif direction == "l":
                self.jerk = Vec3(-_JERK,0,0)
            elif direction == "r":
                self.jerk = Vec3(_JERK,0,0)
        return Task.cont        
    """      
    def moveBall(self, task, direction):
        if self.arrowKeyPressed == True:
            if direction == "u":
                self.jerk = Vec3(0,_JERK,0)
            elif direction == "d":
                self.jerk = Vec3(0,-_JERK,0)
            elif direction == "l":
                self.jerk = Vec3(-_JERK,0,0)
            elif direction == "r":
                self.jerk = Vec3(_JERK,0,0)
        return Task.cont
    """       
    # collision between ray and ground
    # info about the interaction is passed in colEntry
    
    def groundCollideHandler(self,colEntry):
        # set the ball to the appropriate Z for it to be on the ground
        newZ = colEntry.getSurfacePoint(render).getZ()
        self.ballRoot.setZ(newZ+.4)

        # up vector X normal vector
        norm = colEntry.getSurfaceNormal(render)
        accelSide = norm.cross(UP)
        self.accelV = norm.cross(accelSide)

    # collision between the ball and a wall
    def wallCollideHandler(self,colEntry):
        # some vectors needed to do the calculation
        norm = colEntry.getSurfaceNormal(render) * -1
        norm.normalize()
        curSpeed = self.ballV.length()
        inVec = self.ballV/curSpeed
        velAngle = norm.dot(inVec) # angle of incidance
        hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos()
        hitDir.normalize()
        hitAngle = norm.dot(hitDir)
    # deal with collision cases

        if velAngle > 0 and hitAngle >.995:
            # standard reflection equation
            reflectVec = (norm * norm.dot(inVec*-1)*2) + inVec

            # makes velocity half of hitting dead-on
            self.ballV = reflectVec * (curSpeed * (((1-velAngle)*.5)+.5))

            # a collision means the ball is already a little bit buried in
            # move it so exactly touching the wall
            disp = (colEntry.getSurfacePoint(render) -
                    colEntry.getInteriorPoint(render))
            newPos = self.ballRoot.getPos() + disp
            self.ballRoot.setPos(newPos)
            
    def rollTask(self,task):
        # standard technique for finding the amount of time
        # since the last frame
        dt = task.time - task.last
        task.last = task.time

        # If dt is large, then there is a HICCUP
        # ignore the frame
        if dt > .2: return Task.cont

        # dispatch which function to handle the collision based on name
        for i in range(self.cHandler.getNumEntries()):
            entry = self.cHandler.getEntry(i)
            name = entry.getIntoNode().getName()
       
            if name == "Wall.004":
                self.wallCollideHandler(entry)
            elif name=="Cube.004":
                self.groundCollideHandler(entry)
            else: 
                if self.rockOnMaze == True:
                    self.wallCollideHandler(entry)
        self.accelV += self.jerk
        # move the ball, update the velocity based on accel
        self.ballV += self.accelV * dt * ACCELERATION
        # clamp the velocity to the max speed
        if self.ballV.lengthSquared() > MAX_SPEED_SQ:
            self.ballV.normalize()
            self.ballV *= MAX_SPEED
        # update the position
        self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV*dt))

        # uses quaternion to rotate the ball
        prevRot = LRotationf(self.ball.getQuat())
        axis = UP.cross(self.ballV)
        newRot = LRotationf(axis, 45.5 * dt * self.ballV.length())
        self.ball.setQuat(prevRot * newRot)
        return Task.cont # continue the task
예제 #43
0
class CollisionAvatar():
    """Collision for avatar
    """
    def __init__(self, game):
        self.game = game
        self.enable = False
        self.camera = self.game.gui.camera
        self.debug = False

        self.sphere_node = CollisionNode('Sphere')
        self.sphere_nodepath = self.game.world.avatar.attachNewNode(self.sphere_node)
        self.sphere_node.setFromCollideMask(BitMask32.bit(2))
        self.sphere_node.setIntoCollideMask(BitMask32.bit(4))
        self.sphere = CollisionSphere(0, 0, 0.5, 0.5)
        self.sphere_node.addSolid(self.sphere)
        self.sphere_handler = CollisionHandlerQueue()

        self.ray_node = CollisionNode('downRay')
        self.ray_nodepath = self.game.world.avatar.attachNewNode(self.ray_node)
        self.ray_node.setFromCollideMask(BitMask32.bit(1))
        self.ray_node.setIntoCollideMask(BitMask32.bit(3))
        self.ray = CollisionRay()
        self.ray.setOrigin(0, 0, 5)
        self.ray.setDirection(0, 0, -1)
        self.ray_node.addSolid(self.ray)
        self.ray_handler = CollisionHandlerQueue()

    def set_debug(self, value):
        """docstring for debug
        """
        self.debug = value
        if self.debug:
            self.ray_nodepath.show()
            self.sphere_nodepath.show()
        else:
            self.ray_nodepath.hide()
            self.sphere_nodepath.hide()

    def set_enable(self, value, Fly = True):
        self.enable = value
        self.fly = Fly
        if self.enable:
            self.game.gui.cTrav.addCollider(self.ray_nodepath, self.ray_handler)
            self.game.gui.cTrav.addCollider(self.sphere_nodepath, self.sphere_handler)
        else:
            self.game.gui.cTrav.removeCollider(self.ray_nodepath)
            self.game.gui.cTrav.removeCollider(self.sphere_nodepath)

    def detector(self):
        if not self.enable:
            return

        self.game.gui.cTrav.traverse(self.game.world.root_node)

        if self.sphere_handler.getNumEntries() > 0:
            #self.sphere_handler.sortEntries()
            self.game.world.avatar.setPos(self.game.world.root_node, self.lastpos)

        if self.ray_handler.getNumEntries() > 0:
            self.ray_handler.sortEntries()
            pickedObj = self.ray_handler.getEntry(0).getIntoNodePath()
            pickedObj = pickedObj.findNetTag('Chunk')
            if not pickedObj.isEmpty():
                Z = self.ray_handler.getEntry(0).\
                                            getSurfacePoint(self.game.world.root_node).getZ()
                if self.fly:
                    if Z > self.game.world.avatar.getZ(self.game.world.root_node):
                        self.game.world.avatar.setZ(self.game.world.root_node, Z)
                else:
                    self.game.world.avatar.setZ(self.game.world.root_node, Z)
예제 #44
0
class p3dApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self);
        
        # setup the environment or model
        self.model = \
            self.loader.loadModel("/Developer/Panda3D/models/box.egg.pz");
        self.model.reparentTo(self.render);
        self.model.setTag('Model', '1');
        self.model.setScale(1.5, 1.5, 1.5);
        
        # setup camera
        self.camera.setPos(5,5,5)
        self.camera.lookAt(0,0,0)
        
        # Disable mouse control
        self.disableMouse();
        
        # Handle mouse events.
        self.accept('mouse1', self.mouse_down);
        
        # convert image from opencv to panda3d texture
#         self.taskMgr.add(self.read_image_cv, "cvImageTask");
        
        # Setup collision handler
        self.handler = CollisionHandlerQueue()
        self.traverser = CollisionTraverser('ColTraverser')
        self.traverser.traverse(self.model)
        self.ray = CollisionRay()
        pickerNode = CollisionNode('MouseRay')
        pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
        pickerNP = self.camera.attachNewNode(pickerNode)
        pickerNode.addSolid(self.ray)
        self.traverser.addCollider(pickerNP, self.handler)
        
        self.load_shader();
        
        self.first_frame_loaded = False;

    def read_image_cv(self):
        """
        Pulls the next frame from the opencv part, and converts to a panda3d
        texture and display it on the screen.
        """
        cvim = self.cvapp.pull_frame()
        w = cvim.shape[1];
        h = cvim.shape[0];
        
        cvim = cv2.flip(cvim, 0);
        self.im = Texture("cvIm");
        self.im.setCompression(Texture.CMOff);
        self.im.setup2dTexture(w, h, Texture.TUnsignedByte, Texture.FLuminance);
        self.im.setRamImage(cvim);
         
        self.screen_im = OnscreenImage(parent=self.render2d, image=self.im, scale=(1, 1, 1), pos=(0, 0, 0));
        self.cam2d.node().getDisplayRegion(0).setSort(-20);
    
    def load_shader(self):
        """
        The function loads the vertex and fragment shader.
        It provides an example of sending the model-view-projection matrix
        to the shader program when it's calculated.
        """
        self.shader = Shader.load(Shader.SL_GLSL, "vertex.glsl", "fragment.glsl");
        self.model.set_shader(self.shader)
        self.model.set_shader_input("my_ModelViewProjectionMatrix", LMatrix4f())

    def mouse_down(self):
        """
        This function is called as a result of a mouse click.
        It gets the vertex that was clicked by the mouse.
        It sends the mouse position and the vertex position to the cv app.
        """
        if (self.first_frame_loaded == False):
            self.first_frame_loaded = True
            self.read_image_cv()
            return;
        
        xPos = self.mouseWatcherNode.getMouseX()
        yPos = self.mouseWatcherNode.getMouseY()
        self.ray.setFromLens(self.camNode, xPos, yPos)
        self.traverser.traverse(self.model)
        self.handler.sortEntries()
        if (self.handler.getNumEntries() > 0):
            entry = self.handler.getEntry(0) # CollisionEntry
            vpos = entry.getSurfacePoint(self.model)
            res = self.cvapp.mouse_clicked(LPoint3f(xPos, yPos), vpos)
            if (res == 1):
                self.read_image_cv()
        
    def set_cv_app(self, cvapp):
        self.cvapp = cvapp;
예제 #45
0
class Labryn(ShowBase):
    def setCamera(self, spin):
        # set camera spin state
        self.spin = spin

    def displayInformation(self):
        self.title = addTitle("Single Player")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[wasd]: Move")
        self.inst3 = addInstructions(0.85, "[q/e]: spin camera")
        self.inst4 = addInstructions(0.80, "[z/c]: zoom in/out")
        self.inst5 = addInstructions(0.75, "[shift]: hold and pan")
        self.inst6 = addInstructions(0.70, "[1/2/3]: use moves")
        self.inst7 = addInstructions(0.65, "[h]: hide instructions")
        self.insts = [self.title, self.inst1, self.inst2, self.inst3,
                      self.inst4, self.inst5, self.inst6, self.inst7]

    def hideInstructions(self):
        if self.instStatus == "show":
            self.instStatus = "hide"
            groupHide(self.insts)
        else: # instructions are hidden
            self.instStatus = "show"
            groupShow(self.insts)        
        
    def loadNextMusic(self, task):
        # random load background music
        if (self.music.status()!=self.music.PLAYING):
            # not playing
            self.musicCounter += 1
            index = self.musicCounter % len(_BGMUSIC)
            self.music = load_bgmusic(_BGMUSIC[index])
            self.music.play()
        return task.cont
        
    def spinCamera(self, task):
        # deal with spinning the camera
        # _FOCUS: focus point, changed by panning the camera
        # CAM_R: radius, changed by zooming
        # cameraSpinCount: amount of spinning, changed by spinning
        if self.spin == 1: # spin counter-clockwise
            self.cameraSpinCount += 1
            angleDegrees = self.cameraSpinCount
            angleRadians =  angleDegrees * (pi/ 180)
            self.CAM_RAD = angleRadians
            camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R) 
            camera.setHpr(angleDegrees,-65,0)
        elif self.spin == 2: # spin clockwise
            self.cameraSpinCount  -= 1
            angleDegrees = self.cameraSpinCount
            angleRadians =  angleDegrees * (pi/ 180)
            self.CAM_RAD = angleRadians
            camera.setPos(_FOCUS[0]+self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1]+self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
            camera.setHpr(angleDegrees,-65,0)
        elif self.spin == 3: # ZOOM IN not spin
            self.cameraZoomCount += 1
            deltaR = self.cameraZoomCount * 0.1
            new_R = 12-deltaR
            self.CAM_R = new_R
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*new_R)
        elif self.spin == 4: # ZOOM OUT
            self.cameraZoomCount -= 1
            deltaR = self.cameraZoomCount * 0.1
            new_R = 12-deltaR
            self.CAM_R = new_R
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
        return Task.cont

    def takeRecord(self):
        def myCMP(aString, bString):
            a = float(aString.split(',')[0])
            b = float(bString.split(',')[0])
            return int(10*(a - b))
        
        msg = "%.2f,%s\n" %(self.clock/100.0, time.ctime())
        with open('record.txt') as f:
            data = f.readlines()
        # if has no previous data
        if len(data) == 0:
            data.append(msg)
            with open('record.txt','w') as f:
                f.writelines(data)
        else:
            data.append(msg)
            processedData = sorted(data, myCMP)
            with open('record.txt', 'w') as f:
                f.writelines(processedData)

    def printResults(self):
        addEndMessage(self.clock)
        with open('record.txt') as f:
            data = f.readlines()
        for i in xrange(0, len(data)):
            if i < 5: # only print the top 5
                string = data[i]
                printRank(i, string)
        
    def checkForWin(self, task):
        if (checkWin(self.pikachu.getX(), self.pikachu.getY(),
                    self.ballRoot.getX(), self.ballRoot.getY()) and
            self.gameOver == False):
            self.takeRecord()
            self.printResults()
            self.gameOver = True
            # if top 10, if top 1,
            print "WIN"
            # print previous best 10 results
        return Task.cont
    
    def pikachuBark(self, task):
        if self.distance < 3:
            if random.randint(1,200) == 1:
            # randomly bark dangerous sound
                if self.dangerous.status() != self.dangerous.PLAYING:
                    self.dangerous.play()
        elif self.distance > 10:
            if random.randint(1,430) == 1:
                if self.safe.status() != self.safe.PLAYING:
                    self.safe.play()
        return Task.cont
            
    def checkMouse(self, task):
        # get mouse position 
        if base.mouseWatcherNode.hasMouse():
            self.mouseX=base.mouseWatcherNode.getMouseX()
            self.mouseY=base.mouseWatcherNode.getMouseY()
        return Task.cont

    def dropRock(self):
        # when the user clicks, rock is dropped
        if self.pokeMoveChoice == 1: # selected Geodude
            result = MAZE.canDropRock(self.rockX, self.rockY)
            if result != False: # can place rock here
                MAZE.dropRock(result[0],result[1])
                self.rock.setPos(self.rockX, self.rockY, 1)
                self.rockOnMaze = True
                self.pokeMoveChoice = None
                self.myPokeName.hide()
                self.myPokeName = None
                self.updateTwoD()
                self.playerCandyCount -= 1

    def restart(self):
        sys.exit()
                
    def useFlame(self):
        # use flame to Pikachu -> cannot move
        self.onFire = True # on fire
        self.playerCandyCount -= 1
        self.pokeStatus = 1
        self.flame = ParticleEffect()
        self.flame.loadConfig("fireish.ptf")
        self.flame.setPos(self.pikachu.getPos())
        self.flame.start(parent=render, renderParent=render)
        self.updateTwoD()

    def useStringShot(self):
        # use string shot -> speed goes down
        self.pokeStatus = 2
        self.updateTwoD()

    def useThunder(self):
        self.onThunder = True
        self.pokeCandyCount -= 1
        self.thunder = ParticleEffect()
        self.thunder.loadConfig("thunder.ptf")
        self.thunder.start(parent=render, renderParent=render)
        self.use.play()
                
    def placeRock(self, task):
        # rock moves with mouse cursor
        if self.pokeMoveChoice == 1: # selected Geodude
            dX,dY = ((self.mouseX-self.rockRefX),
                     (self.mouseY-self.rockRefY))
            self.rockX, self.rockY = MAZE.translateRockPosition(self.rockRefX,
                                                      self.rockRefY,
                                                      dX, dY)
            self.rock.show()
            self.rock.setPos(self.rockX, self.rockY, 1)
        self.updateTwoD()
        return Task.cont
    
    def placeRareCandy(self, task):
        # place rare candy with interval
        # needs to be improved
        if int(task.time) % 4 == 9 and self.candyOnBoard:
            self.candy.hide()
            self.candyOnBoard = False
            MAZE.clearCandy()
        if int(task.time) % 10 ==  0 and (self.candyOnBoard == False):
            # every 10 seconds
            self.candy.setPos(MAZE.generateCandyPos())
            self.candy.show()
            self.candyOnBoard = True
        return Task.cont

    def updateTwoD(self):
        # update player candy count
        self.playerCandyStatus.destroy()
        self.playerCandyStatus = candyStatus(0, self.playerCandyCount)
        self.pokeCandyStatus.destroy()
        self.pokeCandyStatus = candyStatus(1, self.pokeCandyCount)
        # update my pokes color     
        if self.playerCandyCount == 0 :
            groupHide(self.myPokesBright)
            groupShow(self.myPokesDark)
            # update name
            if self.myPokeName != None:
                self.myPokeName.destroy()

    def clearRock(self):
        # clear rock 
        self.rock.hide()
        self.rockOnMaze = False
        MAZE.clearRock() # clear it in 2D

    def clearFlame(self):
        # clear flame
        self.onFire = False
        self.flame.cleanup()
        self.pokeStatus = 0
        self.pokeMoveChoice = None
        try:
            self.myPokeName.destroy()
        except:
            pass
        self.myPokeName = None

    def clearString(self):
        # clear string shot
        self.pokeStatus = 0
        self.pokeMoveChoice = None
        try:
            self.myPokeName.destroy()
        except:
            pass
        self.myPokeName = None

    def clearThunder(self):
        self.onThunder = False
        try:
            self.thunder.cleanup()
        except:
            pass
        
    def timer(self, task): # deals with moves' lasting effects
        ##############################################################
        self.clock += 1
        if self.rockOnMaze: # rock on maze
            self.rockCounter += 1
        elif self.rockCounter != 1: # rock not on maze, counter not cleared
            self.rockCounter = 0

        if self.onFire:
            self.fireCounter += 1
        elif self.fireCounter != 1:
            self.fireCounter = 0

        if self.pokeStatus == 2: # string shot
            self.stringCounter += 1
        elif self.stringCounter != 1:
            self.stringCounter = 0

        if self.onThunder: # thunderbolt
            self.thunderCounter += 1
        elif self.thunderCounter != 1:
            self.thunderCounter = 0

        if self.gameOver == True: # game is over
            self.gameOverCounter += 1

        ##################################################################
        if self.rockCounter >= 100:
            self.clearRock()

        if self.fireCounter >= 80:
            self.clearFlame()

        if self.thunderCounter >= 150:
            self.clearThunder()
            
        if self.stringCounter >= 120:
            self.clearString()

        if self.gameOverCounter >= 800: # quit the game
            sys.exit()
            
        return Task.cont
    
    def usePokeMove(self, number):
        # use pokemon move
        if self.playerCandyCount > 0: # have more than one candy
            if number == 1 and self.rockOnMaze == False:
                if self.pokeMoveChoice == None: # no choice
                    # set to center position
                    centerx =  base.win.getProperties().getXSize()/2
                    centery =  base.win.getProperties().getYSize()/2
                    base.win.movePointer(0,centerx,centery)
                    self.pokeMoveChoice = 1 # placeRock called here
                    self.rockRefX, self.rockRefY = 0,0
                    self.rock.show()
                    self.rock.setPos(0,0,1)
                elif self.pokeMoveChoice != 1:
                    pass

                else: # self.pokeMoveChoice is already 1, cancel the choice
                    self.pokeMoveChoice = None
                    self.clearRock() # clear rock
            elif number == 2:
                if self.pokeMoveChoice == None:
                    self.pokeMoveChoice = 2
                    self.useFlame()
                elif self.pokeMoveChoice != 2:
                    pass
                else:
                    self.pokeMoveChoice = None

            elif number == 3:
                if self.pokeMoveChoice == None:
                    self.pokeMoveChoice = 3
                    self.useStringShot()
                elif self.pokeMoveChoice != 3:
                    pass
                else: # already 3
                    self.pokeMoveChoice = None

            if self.pokeMoveChoice == None: # no choice
                if self.myPokeName != None: # there is a name on board
                    self.myPokeName.destroy() # kill it
                else: # no name
                    pass
            else: # there is a choice
                if self.myPokeName != None:
                    self.myPokeName.destroy()
                self.myPokeName = writePokeName(self.pokeMoveChoice)
  
    def loadRareCandy(self):
        # load rare candy (a box)
        # needs to be improved
        self.candy = Model_Load.loadRareCandy()
        self.candy.reparentTo(render)
        self.candy.setScale(0.1)
        self.candy.hide()
        
    def eatRareCandy(self, task):
        # check who eats candy
        if self.candyOnBoard: # candy on board
            if checkEat(self.ballRoot.getX(), self.ballRoot.getY(),
                        self.candy.getX(), self.candy.getY()): # ball eats
                self.candy.hide() # eaten
                self.candyOnBoard = False
                if self.playerCandyCount < 3:
                    self.playerCandyCount += 1
                groupShow(self.myPokesBright)
                MAZE.clearCandy()
            elif checkEatPika(self.pikachu.getX(), self.pikachu.getY(),
                          self.candy.getX(), self.candy.getY()):
                self.candy.hide()
                self.candyOnBoard = False
                if self.pokeCandyCount < 3:
                    self.pokeCandyCount += 1
                MAZE.clearCandy()                
        return Task.cont

    def setFocus(self, changing):
        # set focus of the camera while panning
        self.changingFocus = changing
        if changing == True: # Just Pressed
            self.referenceX, self.referenceY = self.mouseX, self.mouseY
        else: # cursor moves up
            self.referenceX, self.referenceY = None, None

    def resetView(self):
        # reset the view to default
        self.CAM_R, self.CAM_RAD = 12, 0
        self.cameraSpinCount, self.cameraZoomCount = 0, 0
        # _FOCUS = [0,0,0] does not work WHY???
        _FOCUS[0], _FOCUS[1], _FOCUS[2] = 0,0,0
        self.changingFocus = False
        self.referenceX, self.referenceY = None, None
        camera.setPos(_FOCUS[0], _FOCUS[1]-self.CAM_R, 25)
        camera.setHpr(0, -65, 0)
        
    def changeFocus(self, task):
        # change focus with displacement of mouse cursor
        if (self.changingFocus == True and self.mouseX != None and
            self.mouseY != None ):
            dX, dY = ((self.mouseX - self.referenceX)*0.1,
                      (self.mouseY - self.referenceY)*0.1)
            _FOCUS[0] += dX
            _FOCUS[1] += dY
            camera.setPos(_FOCUS[0] + self.CAM_R*cos(-pi/2+self.CAM_RAD),
                          _FOCUS[1] + self.CAM_R*sin(-pi/2+self.CAM_RAD),
                          (25.0/12)*self.CAM_R)
        return Task.cont

    def thunderbolt(self, task):
        if self.onThunder == True:
            self.thunder.setPos(self.ballRoot.getPos())
        return Task.cont

    def displayClock(self, task):
        msg = "Time: %.2f" %(self.clock/100.0)
        if self.clockMSG == None:
            self.clockMSG = OnscreenText(text=msg, style=1, fg=(1,1,1,1),
                                         pos=(1.3, .95), align=TextNode.ALeft,
                                         scale = .05)
        else:
            self.clockMSG.destroy()
            self.clockMSG = OnscreenText(text=msg, style=1, fg=(1,1,1,1),
                                         pos=(1.3, .95), align=TextNode.ALeft,
                                         scale = .05)
        return task.cont
    
    def initialize(self):
        taskMgr.stop()
        self.musicCounter, self.clock = 0, 0
        self.gameOverCounter = 0
        self.clockMSG = None
        self.music = load_bgmusic(_BGMUSIC[0])
        self.background = loadBackground()
        base.cam2dp.node().getDisplayRegion(0).setSort(-20)
        self.candyOnBoard = False
        self.playerCandyCount, self.pokeCandyCount = 0, 0
        self.gameOver = False
        self.displayInformation()
        self.instStatus = "show"
        ######################Rare Candy###############################
        pokes=['caterpie', 'charmander', 'geodude']
        self.myPokesDark = loadMyPokemon_Dark(pokes) # my pokemons
        self.myPokesBright = loadMyPokemon_Bright()
        groupHide(self.myPokesBright)
        self.loadRareCandy() # load rare candy
        ######################Camera Initialization####################
        self.CAM_R, self.CAM_RAD = 12, 0
        camera.setPos(_FOCUS[0],_FOCUS[1]-12,_FOCUS[2]+25)
        camera.setHpr(0, -65, 0)
        self.cameraSpinCount, self.cameraZoomCount = 0, 0
        self.changingFocus = False
        self.spin = 0
        #######################ICONS###################################
        self.myIcon = loadMyIcon()
        self.pokeIcon = loadPokeIcon()
        self.playerCandyStatus = candyStatus(0, self.playerCandyCount)
        self.pokeCandyStatus = candyStatus(1, self.pokeCandyCount)
        self.rareCandyImage = loadRareCandyImage()
        self.pokeRareCandyImage = loadRareCandyImage(pos=(-.3,0,-.75))
        #######################FLAMES##################################
        base.enableParticles()
        self.fireCounter = 0
        self.onFire = False
        #######################STRINGSHOT#############################
        self.stringCounter = 0
        #######################THUNDER################################
        self.thunderCounter = 0
        #######################SOUND##################################
        self.dangerous = load_sound("pikachu_d.wav")
        self.safe = load_sound("pikachu_s1.wav")
        self.use = load_sound("pikachu_u.wav")
        #######################"GLOBALS"##############################
        self.speedCounter = 0
        self.onThunder = False
        self.direction = 's'
        self.myDirection = ['zx', 'zy']
        self.rockCounter  = 0
        self.rockX, self.rockY = None, None
        self.rockOnMaze = False
        self.pokeMoveChoice = None
        self.myPokeName = None
        self.arrowKeyPressed = False
        self.pokemonDirection = 'd'
        self.mouseX, self.mouseY = None, None
        # direction the ball is going
        self.jerkDirection = None
        base.disableMouse()
        self.jerk = Vec3(0,0,0)
        self.MAZE = Model_Load.loadLabyrinth()
        Control.keyControl(self)
        self.loadPokemonLevel1()
        self.light()
        self.loadBall()
        self.pokeStatus = 0 # 0 is normal, 1 is burned, 2 is slow-speed
        ########################################ROCK###################
        self.rock = Model_Load.loadRock()
        self.rock.reparentTo(render)
        self.rock.hide() # Do not show, but load beforehand for performance
        
    def loadPokemonLevel1(self):
        self.pikachu = load_model("pikachu.egg")
        self.pikachu.reparentTo(render)
        self.pikachu.setScale(0.3)
        endPos = self.MAZE.find("**/end").getPos()
        self.pikachu.setPos(endPos)
        
    def light(self):
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def loadBall(self):
        self.ballRoot = render.attachNewNode("ballRoot")
        self.ball = load_model("ball")
        self.ball.reparentTo(self.ballRoot)
        self.ball_tex = load_tex("pokeball.png")
        self.ball.setTexture(self.ball_tex,1)
        self.ball.setScale(0.8)
        # Find the collision sphere for the ball in egg.
        self.ballSphere = self.ball.find("**/ball")
        self.ballSphere.node().setFromCollideMask(BitMask32.bit(0))
        self.ballSphere.node().setIntoCollideMask(BitMask32.allOff())
        #self.ballSphere.show()
        # Now we create a ray to cast down at the ball.
        self.ballGroundRay = CollisionRay()
        self.ballGroundRay.setOrigin(0,0,10)
        self.ballGroundRay.setDirection(0,0,-1)

        # Collision solids go in CollisionNode
        self.ballGroundCol =  CollisionNode('groundRay')
        self.ballGroundCol.addSolid(self.ballGroundRay)
        self.ballGroundCol.setFromCollideMask(BitMask32.bit(1))
        self.ballGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ballGroundColNp = self.ballRoot.attachNewNode(self.ballGroundCol)
        
        # light
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.55, .55, .55, 1))
        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))
        self.ballRoot.setLight(render.attachNewNode(ambientLight))
        self.ballRoot.setLight(render.attachNewNode(directionalLight))
        # material to the ball
        m = Material()
        m.setSpecular(Vec4(1,1,1,1))
        m.setShininess(96)
        self.ball.setMaterial(m,1)
        
    def __init__(self):

        self.initialize()
        self.WALLS = self.MAZE.find("**/Wall.004")
        self.WALLS.node().setIntoCollideMask(BitMask32.bit(0))
        # collision with the ground. different bit mask
        #self.mazeGround = self.maze.find("**/ground_collide")
        #self.mazeGround.node().setIntoCollideMask(BitMask32.bit(1))
        self.MAZEGROUND = self.MAZE.find("**/Cube.004")
        self.MAZEGROUND.node().setIntoCollideMask(BitMask32.bit(1))

        # add collision to the rock
        cs = CollisionSphere(0, 0, 0, 0.5)
        self.cnodePath = self.rock.attachNewNode(CollisionNode('cnode'))
        self.cnodePath.node().addSolid(cs)
        self.cnodePath.node().setIntoCollideMask(BitMask32.bit(0))
        
        # CollisionTraversers calculate collisions
        self.cTrav = CollisionTraverser()
        #self.cTrav.showCollisions(render)
        #self.cTrav.showCollisions(render)
        # A list collision handler queue
        self.cHandler = CollisionHandlerQueue()
        # add collision nodes to the traverse.
        # maximum nodes per traverser: 32
        self.cTrav.addCollider(self.ballSphere,self.cHandler)
        self.cTrav.addCollider(self.ballGroundColNp,self.cHandler)
        self.cTrav.addCollider(self.cnodePath, self.cHandler)
        # collision traversers have a built-in tool to visualize collisons
        #self.cTrav.showCollisions(render)
        self.start()

    def pokemonTurn(self, pokemon, direction):
        if direction  == 'l' and self.pokemonDirection != 'l':
            self.pokemonDirection = 'l'
            pokemon.setH(-90)
        if direction  == 'r' and self.pokemonDirection != 'r':
            self.pokemonDirection = 'r'
            pokemon.setH(90)
        if direction  == 'd' and self.pokemonDirection != 'd':
            self.pokemonDirection = 'd'
            pokemon.setH(0)
        if direction  == 'u' and self.pokemonDirection != 'u':
            self.pokemonDirection = 'u'
            pokemon.setH(180)
                        
    def pokemonMove(self, pokemon, direction):
        self.pokemonTurn(pokemon, direction)
        if self.pokeStatus == 0: speed = _SPEED
        elif self.pokeStatus == 1: speed = 0
        else: # self.pokeStatus == 2
            speed = _SPEED/2.0
        if direction == 'l':
            newX = pokemon.getX() - speed
            pokemon.setX(newX)
        elif direction == 'r':
            newX = pokemon.getX() + speed
            pokemon.setX(newX)
        elif direction == 'u':
            newY = pokemon.getY() + speed
            pokemon.setY(newY)
        elif direction == 'd':
            newY = pokemon.getY() - speed
            pokemon.setY(newY)
        elif direction == "s": # stop
            pass
        
    def whereToGo(self, task):
        # this returns the direction pokemon should go
        # tell MAZE pokemon and ball's board position
        self.pokemonMove(self.pikachu, self.direction)
        MAZE.setPokeCoord(self.pikachu.getX(), self.pikachu.getY(),
                          self.pokemonDirection)
        MAZE.setBallCoord(self.ballRoot.getX(), self.ballRoot.getY())
        MAZE.sendInformation(self.myDirection, self.rockOnMaze,
                             self.onThunder, self.playerCandyCount,
                             self.pokeCandyCount, self.distance)
        # find out which direction to go
        self.direction = MAZE.getDecision()
        self.pokemonMove(self.pikachu,self.direction)
        return Task.cont

    def whatToDo(self, task):
        # determines when to use thunder
        if self.pokeCandyCount > 0: # Pikachu has candies
            decision = MAZE.useThunderDecision()
            if decision == True:
                self.useThunder()
        return Task.cont
    
    def getInformation(self, task):
        # get information on the board
        self.speedCounter += 1 # sample every other call to avoid 
        if self.speedCounter % 2 == 0:
            dX = self.ballRoot.getX() - self.oldPos[0]
            dY = self.ballRoot.getY() - self.oldPos[1]
            if dX < 0 :
                # print "going left"
                self.myDirection[0] = 'l'
            elif abs(dX) < _EPSILON:
                # print "not moving horiz"
                self.myDirection[0] = 'zx'
            else:
                # print "going right"
                self.myDirection[0] = 'r'
            if dY < 0 :
                # print "going down"
                self.myDirection[1] = 'd'
            elif abs(dY) < _EPSILON:
                # print "not moving verti"
                self.myDirection[1] = 'zy'
            else:
                # print "going up"
                self.myDirection[1] = 'u'
            self.oldPos = self.ballRoot.getPos()
        # calculate distance
        self.distance = MAZE.getDistance()
        return Task.cont
    
    def start(self):
        # maze model has a locator in it
        # self.ballRoot.show()
        self.startPos = self.MAZE.find("**/start").getPos()
        self.oldPos = self.MAZE.find("**/start").getPos()
        self.ballRoot.setPos(self.startPos) # set the ball in the pos
        self.ballV = Vec3(0,0,0) # initial velocity
        self.accelV = Vec3(0,0,0) # initial acceleration

        # for a traverser to work, need to call traverser.traverse()
        # base has a task that does this once a frame
        base.cTrav = self.cTrav

        # create the movement task, make sure its not already running
        taskMgr.remove("rollTask")
        taskMgr.add(self.placeRock, "placeRock")
        taskMgr.add(self.displayClock, "displayClock")
        taskMgr.add(self.timer, "timer")
        taskMgr.add(self.loadNextMusic, "loadNextMusic")
        taskMgr.add(self.getInformation, "getInformation")
        taskMgr.add(self.eatRareCandy, "eatRareCandy")
        taskMgr.add(self.placeRareCandy, "placeRareCandy")
        taskMgr.add(self.checkMouse, "checkMouse")
        taskMgr.add(self.spinCamera, "spinCamera")
        taskMgr.add(self.changeFocus, "changeFocus")
        taskMgr.add(self.whereToGo, "whereToGo")
        taskMgr.add(self.whatToDo, "whatToDo")
        taskMgr.add(self.moveBall, "moveBall")
        taskMgr.add(self.thunderbolt, "thunderbolt")
        taskMgr.add(self.checkForWin, "checkForWin")
        taskMgr.add(self.pikachuBark, "pikachuBark")
        self.mainLoop = taskMgr.add(self.rollTask, "rollTask")
        self.mainLoop.last = 0

    def moveBallWrapper(self, direction):
        # wrapper for moving the ball
        # needs to be improved
        if direction == False:
            self.arrowKeyPressed = False
        else:
            self.arrowKeyPressed = True
            self.jerkDirection = direction
    
    def moveBall(self, task):
        # move the ball
        # a key press changes the jerk
        direction = self.jerkDirection
        if self.arrowKeyPressed == True and self.onThunder == False:
            if direction == "u":
                self.jerk = Vec3(0,_JERK,0)
            elif direction == "d":
                self.jerk = Vec3(0,-_JERK,0)
            elif direction == "l":
                self.jerk = Vec3(-_JERK,0,0)
            elif direction == "r":
                self.jerk = Vec3(_JERK,0,0)
        elif self.onThunder == True:
            self.jerk = self.jerk
        return Task.cont        

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

        # up vector X normal vector
        norm = colEntry.getSurfaceNormal(render)
        accelSide = norm.cross(UP)
        self.accelV = norm.cross(accelSide)

    # collision between the ball and a wall
    def wallCollideHandler(self,colEntry):
        # some vectors needed to do the calculation
        norm = colEntry.getSurfaceNormal(render) * -1
        norm.normalize()
        curSpeed = self.ballV.length()
        inVec = self.ballV/curSpeed
        velAngle = norm.dot(inVec) # angle of incidance
        hitDir = colEntry.getSurfacePoint(render) - self.ballRoot.getPos()
        hitDir.normalize()
        hitAngle = norm.dot(hitDir)
    # deal with collision cases
        if velAngle > 0 and hitAngle >.995:
            # standard reflection equation
            reflectVec = (norm * norm.dot(inVec*-1)*2) + inVec
            # makes velocity half of hitting dead-on
            self.ballV = reflectVec * (curSpeed * (((1-velAngle)*.5)+.5))
            # a collision means the ball is already a little bit buried in
            # move it so exactly touching the wall
            disp = (colEntry.getSurfacePoint(render) -
                    colEntry.getInteriorPoint(render))
            newPos = self.ballRoot.getPos() + disp
            self.ballRoot.setPos(newPos)
            
    def rollTask(self,task):
        # standard technique for finding the amount of time
        # since the last frame
        dt = task.time - task.last
        task.last = task.time
        # If dt is large, then there is a HICCUP
        # ignore the frame
        if dt > .2: return Task.cont
        # dispatch which function to handle the collision based on name
        for i in range(self.cHandler.getNumEntries()):
            entry = self.cHandler.getEntry(i)
            name = entry.getIntoNode().getName()
            if name == "Wall.004":
                self.wallCollideHandler(entry)
            elif name=="Cube.004":
                self.groundCollideHandler(entry)
            else:
                if self.rockOnMaze == True:
                    self.wallCollideHandler(entry)
                    
        self.accelV += self.jerk
        # move the ball, update the velocity based on accel
        self.ballV += self.accelV * dt * ACCELERATION
        # clamp the velocity to the max speed
        if self.ballV.lengthSquared() > MAX_SPEED_SQ:
            self.ballV.normalize()
            self.ballV *= MAX_SPEED
        # update the position
        self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV*dt))

        # uses quaternion to rotate the ball
        prevRot = LRotationf(self.ball.getQuat())
        axis = UP.cross(self.ballV)
        newRot = LRotationf(axis, 45.5 * dt * self.ballV.length())
        self.ball.setQuat(prevRot * newRot)
        return Task.cont # continue the task     
예제 #46
0
class World(DirectObject):
    def __init__(self):
        # This code puts the standard title and instruction text on screen
        self.title = OnscreenText(text="Ball in Maze",
                                  style=1,
                                  fg=(1, 1, 1, 1),
                                  pos=(0.7, -0.95),
                                  scale=.07)
        self.instructions = OnscreenText(text="Press Esc to exit.",
                                         pos=(-1.3, .95),
                                         fg=(1, 1, 1, 1),
                                         align=TextNode.ALeft,
                                         scale=.05)

        base.setBackgroundColor(0, 0, 0)

        self.central_msg = OnscreenText(text="",
                                        pos=(0, 0),
                                        fg=(1, 1, 0, 1),
                                        scale=.1)
        self.central_msg.hide()

        self.accept("escape", sys.exit)  # Escape quits
        base.disableMouse()  # Disable mouse-based camera control
        camera.setPosHpr(0, 0, 25, 0, -90, 0)  # Place the camera

        # Load the maze and place it in the scene
        self.maze = loader.loadModel("models/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 visable polygons,
        # set a from collide mask to include bit 20
        #
        # For this example, we will make everything we want the ball to collide with
        # include bit 0
        self.walls.node().setIntoCollideMask(BitMask32.bit(0))
        # CollisionNodes are usually invisible but can be shown. Uncomment the next
        # line to see the collision walls
        # self.walls.show()

        # We will now find the triggers for the holes and set their masks to 0 as
        # well. We also set their names to make them easier to identify during
        # collisions
        self.loseTriggers = []
        for i in range(6):
            trigger = self.maze.find("**/hole_collide" + str(i))
            trigger.node().setIntoCollideMask(BitMask32.bit(0))
            trigger.node().setName("loseTrigger")
            self.loseTriggers.append(trigger)
            # Uncomment this line to see the triggers
            # trigger.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.
        # self.cTrav.showCollisions(render)

        # This section deals with lighting for the ball. Only the ball was lit
        # because the maze has static lighting pregenerated by the modeler
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.55, .55, .55, 1))
        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))
        self.ballRoot.setLight(render.attachNewNode(ambientLight))
        self.ballRoot.setLight(render.attachNewNode(directionalLight))

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

        # Create the movement task, but first make sure it is not already running
        taskMgr.remove("rollTask")
        self.mainLoop = taskMgr.add(self.rollTask, "rollTask")
        self.mainLoop.last = 0

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

    # This is the task that deals with making everything interactive
    def rollTask(self, task):
        # Standard technique for finding the amount of time since the last frame
        dt = task.time - task.last
        task.last = task.time

        # If dt is large, then there has been a # hiccup that could cause the ball
        # to leave the field if this functions runs, so ignore the frame
        if dt > .2: return Task.cont

        # The collision handler collects the collisions. We dispatch which function
        # to handle the collision based on the name of what was collided into
        for i in range(self.cHandler.getNumEntries()):
            entry = self.cHandler.getEntry(i)
            name = entry.getIntoNode().getName()
            if name == "wall_collide": self.wallCollideHandler(entry)
            elif name == "ground_collide": self.groundCollideHandler(entry)
            elif name == "loseTrigger": self.loseGame(entry)

        # Read the mouse position and tilt the maze accordingly
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()  # get the mouse position
            self.maze.setP(mpos.getY() * -10)
            self.maze.setR(mpos.getX() * 10)

        # Finally, we move the ball
        # Update the velocity based on acceleration
        self.ballV += self.accelV * dt * ACCEL
        # Clamp the velocity to the maximum speed
        if self.ballV.lengthSquared() > MAX_SPEED_SQ:
            self.ballV.normalize()
            self.ballV *= MAX_SPEED
        # Update the position based on the velocity
        self.ballRoot.setPos(self.ballRoot.getPos() + (self.ballV * dt))

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

        return Task.cont  # Continue the task indefinitely

    def show_message(self, message=''):
        if message:
            self.central_msg.setText(message)
            self.central_msg.show()
        else:
            self.central_msg.hide()

    # If the ball hits a hole trigger, then it should fall in the hole.
    # This is faked rather than dealing with the actual physics of it.
    def loseGame(self, entry):
        # The triggers are set up so that the center of the ball should move to the
        # collision point to be in the hole

        toPos = entry.getInteriorPoint(render)
        taskMgr.remove('rollTask')  # Stop the maze task

        # Move the ball into the hole over a short sequence of time. Then wait a
        # second and call start to reset the game
        Sequence(
            Parallel(
                LerpFunc(self.ballRoot.setX,
                         fromData=self.ballRoot.getX(),
                         toData=toPos.getX(),
                         duration=.1),
                LerpFunc(self.ballRoot.setY,
                         fromData=self.ballRoot.getY(),
                         toData=toPos.getY(),
                         duration=.1),
                LerpFunc(self.ballRoot.setZ,
                         fromData=self.ballRoot.getZ(),
                         toData=self.ballRoot.getZ() - .9,
                         duration=.2)), Func(self.show_message, "Try Again!"),
            Wait(1), Func(self.show_message, ""), Func(self.start)).start()
예제 #47
0
class RoamingRalphDemo(ShowBase):
    def __init__(self):
        # Setup window size, title and so on
        load_prc_file_data(
            "", """
            win-size 1600 900
            window-title Render Pipeline - Roaming Ralph Demo
        """)

        if alt:
            ShowBase.__init__(self)
            self.render_pipeline = render_pipeline
            self.render_pipeline.create(self)
        else:
            # ------ Begin of render pipeline code (else case) ------

            # Insert the pipeline path to the system path, this is required to be
            # able to import the pipeline classes
            #pipeline_path = "../../"

            # Just a special case for my development setup, so I don't accidentally
            # commit a wrong path. You can remove this in your own programs.
            #if not os.path.isfile(os.path.join(pipeline_path, "setup.py")):
            pipeline_path = "../tobsprRenderPipeline"

            sys.path.insert(0, pipeline_path)

            from rpcore import RenderPipeline, SpotLight
            self.render_pipeline = RenderPipeline()
            self.render_pipeline.create(self)

            # ------ End of render pipeline code, thats it! ------

        # Set time of day
        self.render_pipeline.daytime_mgr.time = "7:40"

        # Use a special effect for rendering the scene, this is because the
        # roaming ralph model has no normals or valid materials
        self.render_pipeline.set_effect(
            render, "roaming_ralph_pipeline_scene-effect.yaml", {}, sort=250)

        self.keyMap = {
            "left": 0,
            "right": 0,
            "forward": 0,
            "backward": 0,
            "cam-left": 0,
            "cam-right": 0
        }
        self.speed = 1.0
        base.win.setClearColor(Vec4(0, 0, 0, 1))

        # Post the instructions

        self.inst1 = addInstructions(0.95, "[ESC]  Quit")
        self.inst4 = addInstructions(0.90, "[W]  Run Ralph Forward")
        self.inst4 = addInstructions(0.85, "[S]  Run Ralph Backward")
        self.inst2 = addInstructions(0.80, "[A]  Rotate Ralph Left")
        self.inst3 = addInstructions(0.75, "[D]  Rotate Ralph Right")
        self.inst6 = addInstructions(0.70, "[Left Arrow]  Rotate Camera Left")
        self.inst7 = addInstructions(0.65,
                                     "[Right Arrow]  Rotate Camera Right")

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel(
            "roaming_ralph_pipeline_resources/world")
        self.environ.reparentTo(render)
        self.environ.setPos(0, 0, 0)

        # Remove wall nodes
        self.environ.find("**/wall").remove_node()

        # Create the main character, Ralph
        self.ralph = Actor(
            "roaming_ralph_pipeline_resources/ralph", {
                "run": "roaming_ralph_pipeline_resources/ralph-run",
                "walk": "roaming_ralph_pipeline_resources/ralph-walk"
            })
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(Vec3(-110.9, 29.4, 1.8))

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("a", self.setKey, ["left", 1])
        self.accept("d", self.setKey, ["right", 1])
        self.accept("w", self.setKey, ["forward", 1])
        self.accept("s", self.setKey, ["backward", 1])
        self.accept("arrow_left", self.setKey, ["cam-left", 1])
        self.accept("arrow_right", self.setKey, ["cam-right", 1])
        self.accept("a-up", self.setKey, ["left", 0])
        self.accept("d-up", self.setKey, ["right", 0])
        self.accept("w-up", self.setKey, ["forward", 0])
        self.accept("s-up", self.setKey, ["backward", 0])
        self.accept("arrow_left-up", self.setKey, ["cam-left", 0])
        self.accept("arrow_right-up", self.setKey, ["cam-right", 0])
        self.accept("=", self.adjustSpeed, [0.25])
        self.accept("+", self.adjustSpeed, [0.25])
        self.accept("-", self.adjustSpeed, [-0.25])

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera

        base.disableMouse()
        base.camera.setPos(self.ralph.getX() + 10, self.ralph.getY() + 10, 2)
        base.camLens.setFov(80)

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

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 1000)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 1000)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

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

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

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

    # Adjust movement speed
    def adjustSpeed(self, delta):
        newSpeed = self.speed + delta
        if 0 <= newSpeed <= 3:
            self.speed = newSpeed

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

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        base.camera.lookAt(self.ralph)
        if (self.keyMap["cam-left"] != 0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())
        if (self.keyMap["cam-right"] != 0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())

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

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if (self.keyMap["left"] != 0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        elif (self.keyMap["right"] != 0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"] != 0):
            self.ralph.setY(self.ralph, -25 * self.speed * globalClock.getDt())
        elif (self.keyMap["backward"] != 0):
            self.ralph.setY(self.ralph, 25 * self.speed * globalClock.getDt())

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"]!=0) or (self.keyMap["backward"]!=0) or \
           (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec * (5 - camdist))
            camdist = 5.0

        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        if (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                   == "terrain"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.

        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        if (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                   == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.camera.setZ(self.ralph.getZ() + 2.0)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.

        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        return task.cont
예제 #48
0
class World(DirectObject):
    def __init__(self):
        #This code puts the standard title and instruction text on screen
        self.title = OnscreenText(text="Panda3D: Tutorial - Mouse Picking",
                                  style=1,
                                  fg=(1, 1, 1, 1),
                                  pos=(0.8, -0.95),
                                  scale=.07)
        self.escapeEvent = OnscreenText(text="ESC: Quit",
                                        style=1,
                                        fg=(1, 1, 1, 1),
                                        pos=(-1.3, 0.95),
                                        align=TextNode.ALeft,
                                        scale=.05)
        self.mouse1Event = OnscreenText(
            text="Left-click and drag: Pick up and drag piece",
            style=1,
            fg=(1, 1, 1, 1),
            pos=(-1.3, 0.90),
            align=TextNode.ALeft,
            scale=.05)

        self.accept('escape', sys.exit)  #Escape quits
        base.disableMouse()  #Disble mouse camera control
        camera.setPosHpr(0, -13.75, 6, 0, -25, 0)  #Set the camera
        self.setupLights()  #Setup default lighting

        #Since we are using collision detection to do picking, we set it up like
        #any other collision detection system with a traverser and a handler
        self.picker = CollisionTraverser()  #Make a traverser
        self.pq = CollisionHandlerQueue()  #Make a handler
        #Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        #Attach that node to the camera since the ray will need to be positioned
        #relative to it
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        #Everything to be picked will use bit 1. This way if we were doing other
        #collision we could seperate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  #Make our ray
        self.pickerNode.addSolid(self.pickerRay)  #Add it to the collision node
        #Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)
        #self.picker.showCollisions(render)

        #Now we create the chess board and its pieces

        #We will attach all of the squares to their own root. This way we can do the
        #collision pass just on the sqaures and save the time of checking the rest
        #of the scene
        self.squareRoot = render.attachNewNode("squareRoot")

        #For each square
        self.squares = [None for i in range(64)]
        self.pieces = [None for i in range(64)]
        for i in range(64):
            #Load, parent, color, and position the model (a single square polygon)
            self.squares[i] = loader.loadModel("models/square")
            self.squares[i].reparentTo(self.squareRoot)
            self.squares[i].setPos(SquarePos(i))
            self.squares[i].setColor(SquareColor(i))
            #Set the model itself to be collideable with the ray. If this model was
            #any more complex than a single polygon, you should set up a collision
            #sphere around it instead. But for single polygons this works fine.
            self.squares[i].find("**/polygon").node().setIntoCollideMask(
                BitMask32.bit(1))
            #Set a tag on the square's node so we can look up what square this is
            #later during the collision pass
            self.squares[i].find("**/polygon").node().setTag('square', str(i))

            #We will use this variable as a pointer to whatever piece is currently
            #in this square

        #The order of pieces on a chessboard from white's perspective. This list
        #contains the constructor functions for the piece classes defined below
        pieceOrder = (Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook)

        for i in range(8, 16):
            #Load the white pawns
            self.pieces[i] = Pawn(i, WHITE)
        for i in range(48, 56):
            #load the black pawns
            self.pieces[i] = Pawn(i, PIECEBLACK)
        for i in range(8):
            #Load the special pieces for the front row and color them white
            self.pieces[i] = pieceOrder[i](i, WHITE)
            #Load the special pieces for the back row and color them black
            self.pieces[i + 56] = pieceOrder[i](i + 56, PIECEBLACK)

        #This will represent the index of the currently highlited square
        self.hiSq = False
        #This wil represent the index of the square where currently dragged piece
        #was grabbed from
        self.dragging = False

        #Start the task that handles the picking
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
        self.accept("mouse1", self.grabPiece)  #left-click grabs a piece
        self.accept("mouse1-up", self.releasePiece)  #releasing places it

    #This function swaps the positions of two pieces
    def swapPieces(self, fr, to):
        temp = self.pieces[fr]
        self.pieces[fr] = self.pieces[to]
        self.pieces[to] = temp
        if self.pieces[fr]:
            self.pieces[fr].square = fr
            self.pieces[fr].obj.setPos(SquarePos(fr))
        if self.pieces[to]:
            self.pieces[to].square = to
            self.pieces[to].obj.setPos(SquarePos(to))

    def mouseTask(self, task):
        #This task deals with the highlighting and dragging based on the mouse

        #First, clear the current highlight
        if self.hiSq is not False:
            self.squares[self.hiSq].setColor(SquareColor(self.hiSq))
            self.hiSq = False

        #Check to see if we can access the mouse. We need it to do anything else
        if base.mouseWatcherNode.hasMouse():
            #get the mouse position
            mpos = base.mouseWatcherNode.getMouse()

            #Set the position of the ray based on the mouse position
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())

            #If we are dragging something, set the position of the object
            #to be at the appropriate point over the plane of the board
            if self.dragging is not False:
                #Gets the point described by pickerRay.getOrigin(), which is relative to
                #camera, relative instead to render
                nearPoint = render.getRelativePoint(camera,
                                                    self.pickerRay.getOrigin())
                #Same thing with the direction of the ray
                nearVec = render.getRelativeVector(
                    camera, self.pickerRay.getDirection())
                self.pieces[self.dragging].obj.setPos(
                    PointAtZ(.5, nearPoint, nearVec))

            #Do the actual collision pass (Do it only on the squares for
            #efficiency purposes)
            self.picker.traverse(self.squareRoot)
            if self.pq.getNumEntries() > 0:
                #if we have hit something, sort the hits so that the closest
                #is first, and highlight that node
                self.pq.sortEntries()
                i = int(self.pq.getEntry(0).getIntoNode().getTag('square'))
                #Set the highlight on the picked square
                self.squares[i].setColor(HIGHLIGHT)
                self.hiSq = i

        return Task.cont

    def grabPiece(self):
        #If a square is highlighted and it has a piece, set it to dragging mode
        if (self.hiSq is not False and self.pieces[self.hiSq]):
            self.dragging = self.hiSq
            self.hiSq = False

    def releasePiece(self):
        #Letting go of a piece. If we are not on a square, return it to its original
        #position. Otherwise, swap it with the piece in the new square
        if self.dragging is not False:  #Make sure we really are dragging something
            #We have let go of the piece, but we are not on a square
            if self.hiSq is False:
                self.pieces[self.dragging].obj.setPos(SquarePos(self.dragging))
            else:
                #Otherwise, swap the pieces
                self.swapPieces(self.dragging, self.hiSq)

        #We are no longer dragging anything
        self.dragging = False

    def setupLights(self):  #This function sets up some default lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.8, .8, .8, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0, 45, -45))
        directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(ambientLight))
예제 #49
0
class Usuario(object):
    """
    Usuario
    """

    def __init__(self, dadosUsuario, principal=False):
        self.key = dadosUsuario["key"]
        self.nick = dadosUsuario["nick"]
        self.vida_real = float(dadosUsuario["vida_real"])
        self.vida_total = float(dadosUsuario["vida_total"])
        self.mana_real = float(dadosUsuario["mana_real"])
        self.mana_total = float(dadosUsuario["mana_total"])
        self.forca = float(dadosUsuario["forca"])
        self.velocidade = float(dadosUsuario["velocidade"])
        self.velocidade_atack = float(dadosUsuario["velocidade_atack"])

        self.estaMovendo = False
        self.estaRodando = False

        self.__task_name = "Task Usuario - " + self.key

        self.keyMap = {TECLA_esquerda: EVENT_up, TECLA_direita: EVENT_up, TECLA_frente: EVENT_up, TECLA_traz: EVENT_up}

        pandaFileModelo = get_path_modelo("ralph")
        pandaFileAnimacaoRun = get_path_animacao("ralph-run")
        pandaFileAnimacaoWalk = get_path_animacao("ralph-walk")

        self.modelo = Actor(pandaFileModelo, {"run": pandaFileAnimacaoRun, "walk": pandaFileAnimacaoWalk})
        self.modelo.reparentTo(render)
        self.modelo.setScale(SCALE_MODELOS)

        self.set_pos((float(dadosUsuario["x"]), float(dadosUsuario["y"]), float(dadosUsuario["z"])))
        self.set_h(float(dadosUsuario["h"]))

        if not principal:
            self.text = Text(
                parent=self.modelo, pos=(0, 0, 5.5), scale=0.5, align="center", cor=COR_VERDE, text=self.nick
            )

            self.text.billboardEffect()

        self.__setup_collision()

        taskMgr.add(self.__task_movimentacao, self.__task_name, sort=1)

    def get_x(self):
        return self.modelo.getX()

    def get_y(self):
        return self.modelo.getY()

    def get_z(self):
        return self.modelo.getZ()

    def get_h(self):
        return self.modelo.getH()

    def get_pos(self):
        return self.modelo.getPos()

    def set_x(self, x):
        self.modelo.setX(x)

    def set_y(self, y):
        self.modelo.setY(y)

    def set_z(self, z):
        self.modelo.setZ(z)

    def set_h(self, h):
        self.modelo.setH(h)

    def set_pos(self, pos):
        self.modelo.setPos(pos)

    def delete(self):
        taskMgr.remove(self.__task_name)

        self.modelo.delete()

    def __setup_collision(self):
        # Colisao
        self.cTrav = CollisionTraverser("usuarioTraverser")

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 5)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode("ralphRay")
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.modelo.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()

        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        # self.ralphGroundColNp.show()
        # self.cTrav.showCollisions(render)
        # Colisao

    def __task_movimentacao(self, task):
        dt = globalClock.getDt()
        startpos = self.modelo.getPos()

        # movimentos usuario modelo
        if self.keyMap[TECLA_esquerda] == EVENT_down and self.keyMap[TECLA_direita] == EVENT_up:
            self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt))

            if not self.estaRodando:
                self.estaRodando = True

        elif self.keyMap[TECLA_direita] == EVENT_down and self.keyMap[TECLA_esquerda] == EVENT_up:
            self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt) * -1)

            if not self.estaRodando:
                self.estaRodando = True

        elif self.estaRodando:
            self.estaRodando = False

        if self.keyMap[TECLA_frente] == EVENT_down and self.keyMap[TECLA_traz] == EVENT_up:
            self.modelo.setY(self.modelo, ((self.velocidade * 2) * dt) * -1)

            if self.estaMovendo is False:
                self.modelo.loop("run")
                self.estaMovendo = True

        elif self.keyMap[TECLA_traz] == EVENT_down and self.keyMap[TECLA_frente] == EVENT_up:
            self.modelo.setY(self.modelo, (self.velocidade * dt))

            if self.estaMovendo is False:
                self.modelo.loop("walk")
                self.estaMovendo = True

        elif self.estaMovendo:
            self.modelo.stop()
            self.modelo.pose("walk", 5)
            self.estaMovendo = False
        # movimentos usuario modelo

        if self.estaMovendo:

            self.cTrav.traverse(render)

            if self.ralphGroundHandler.getNumEntries() == 1:
                entry = self.ralphGroundHandler.getEntry(0)
                if entry.getIntoNode().getName() == "terrain":
                    self.modelo.setZ(entry.getSurfacePoint(render).getZ())
            else:
                self.modelo.setPos(startpos)

        return task.cont
예제 #50
0
class World(ShowBase):
    def skyBoxLoad(self):
        self.spaceSkyBox = load_model('skybox1.egg')
        self.spaceSkyBox.setScale(150)
        self.spaceSkyBox.setLightOff()
        self.spaceSkyBox.reparentTo(render)
        self.spaceSkyBox.setPos(0,0,-200)
        self.spaceSkyBox.setHpr(0,0,0)        

    def loadEnviron(self):
        self.environ = load_model("secondWorld.egg")
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)

    def Hooh(self):
        """ hooh """
        self.hoohActor = Actor("anim2hooh.egg",
                           {"wing":"anim-Anim0.egg"})
        self.hoohActor.reparentTo(render)
        self.hoohActor.loop("wing")
        self.hoohActor.setPos(self.ralphStartPos[0],
                              self.ralphStartPos[1]+100,
                              self.ralphStartPos[2]+100)
        self.hoohActor.setPlayRate(4.0,"wing")
        self.hoohActor.setHpr(180,90,0)

        start = Point3(self.ralphStartPos[0], self.ralphStartPos[1]+95,
                       self.ralphStartPos[2]+100)
        end = Point3(self.ralphStartPos[0], self.ralphStartPos[1]-100,
                     self.ralphStartPos[2]+100)
        turnHpr1 = Point3(180,90,0)
        turnHpr2 = Point3(0,90,0) 
        hoohPosInt1 = self.hoohActor.posInterval(5.0, start, startPos = end)
        hoohPosInt2 = self.hoohActor.posInterval(5.0, end, startPos = start)
        hoohHprInt1 = self.hoohActor.hprInterval(1.0, turnHpr2,
                                                 startHpr=turnHpr1)
        hoohHprInt2 = self.hoohActor.hprInterval(1.0, turnHpr1,
                                                 startHpr=turnHpr2)        
        self.hoohFly = Sequence(hoohPosInt1,
                                hoohHprInt1,
                                hoohPosInt2,
                                hoohHprInt2,
                                name="hoohFly")
        self.hoohFly.loop()        

    def gold(self, task):
        _GOLD_PARTICLES.setPos(self.hoohActor.getPos())
        return task.cont
        
    def loadPokemon(self):
        """ Pikachu """
        self.pikachu = load_model("pikachu.egg")
        self.pikachu.reparentTo(render)
        self.pikachu.setPos(_PIKACHU_POS)
        self.pikachu.setHpr(_PIKACHU_HPR)

        """ Groudon """
        self.Groudon = load_model("Groudon.egg")
        self.Groudon.reparentTo(render)
        self.Groudon.setPos(_GROUDON_POS)
        self.Groudon.setHpr(_GROUDON_HPR)

        """ Bulbasaur """
        self.bulbasaur = load_model("bulbasaur.egg")
        self.bulbasaur.reparentTo(render)
        self.bulbasaur.setPos(_BULBASAUR_POS)
        self.bulbasaur.setHpr(_BULBASAUR_HPR)

        """ hooh """
        self.Hooh()

        """ Pichu """
        self.pichu = load_model("pichu.egg")
        self.pichu.reparentTo(render)
        self.pichu.setPos(_PICHU_POS)
        self.pichu.setHpr(_PICHU_HPR)

        """ Charmander """
        self.charmander = load_model("char.egg")
        self.charmander.reparentTo(render)
        self.charmander.setPos(_CHARMANDER_POS)
        self.charmander.setHpr(_CHARMANDER_HPR)

        """ charizard """
        self.charizard = load_model("charizard.egg")
        self.charizard.reparentTo(render)
        self.charizard.setPos(_CHARIZARD_POS)
        self.charizard.setHpr(_CHARIZARD_HPR)

        """ blastoise """
        self.blastoise = load_model("blastoise.egg")
        self.blastoise.reparentTo(render)
        self.blastoise.setPos(_BLASTOISE_POS)
        self.blastoise.setHpr(_BLASTOISE_HPR)

        """ Squirtle """
        self.squirtle = load_model("squirtle.egg")
        self.squirtle.reparentTo(render)
        self.squirtle.setPos(_SQUIRTLE_POS)
        self.squirtle.setHpr(_SQUIRTLE_HPR)

        """ Dragonite """
        self.dragonite = load_model("dragonite.egg")
        self.dragonite.reparentTo(render)
        self.dragonite.setPos(_DRAGONITE_POS)
        self.dragonite.setHpr(_DRAGONITE_HPR)
        
        _FLAME.setPos(_FLAME_POS)
        _FLAME.setScale(0.1)
        _FLAME.start(parent=render, renderParent=render)
        
        """ venusaur """
        self.venusaur = load_model("venusaur.egg")
        self.venusaur.reparentTo(render)
        self.venusaur.setPos(_VENUSAUR_POS)
        self.venusaur.setHpr(_VENUSAUR_HPR)
        
    def loadRalph(self):
        # Create the main character, Ralph
        basePath = r"../google_drive/ball/data/models/"
        self.ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor(basePath+"ralph",{"run":basePath+"ralph-run",
                                  "walk":basePath+"ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(self.ralphStartPos)
        self.ralph.hide()                    

    def loadNextMusic(self, task):
        # random load background music
        if (self.music.status()!=self.music.PLAYING):
            # not playing
            self.musicCounter += 1
            index = self.musicCounter % len(_BGMUSIC)
            self.music = load_bgmusic(_BGMUSIC[index])
            self.music.play()
        return task.cont
        
    def keyControl(self):
        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("w",self.setKey,["upward",1])
        self.accept("w-up",self.setKey,["upward",0])
        self.accept("s",self.setKey,["downward",1])
        self.accept("s-up",self.setKey,["downward",0])
        self.accept("t", self.toggleMusic)
        self.accept("u", self.changeVolume, ['u'])
        self.accept("d", self.changeVolume, ['d'])
        self.accept("h", self.hideInstructions)

    def changeVolume(self, direction):
        if direction == 'u' and self.volume < 1:
            self.volume += 0.05
        else: # direction == 'd'
            if self.volume > 0:
                self.volume -= 0.05
        self.music.setVolume(self.volume)
            
    def toggleMusic(self):
        self.music.stop()
        self.musicCounter += 1 # increment the counter by 
        index = self.musicCounter % len(_BGMUSIC)
        self.music = load_bgmusic(_BGMUSIC[index])
        self.music.play()
        
    def displayInformation(self):
        self.title = addTitle("My Pokemon - Roam Mode")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Arrow Keys]: Move")
        self.inst3 = addInstructions(0.85, "[w]: look up")
        self.inst4 = addInstructions(0.80, "[s]: look down")
        self.inst5 = addInstructions(0.75, "[t]: toggle next song")
        self.inst6 = addInstructions(0.70, "[u]: volume up")
        self.inst7 = addInstructions(0.65, "[d]: volume down")
        self.inst8 = addInstructions(0.60, "[h]: hide/show instructions")
        self.insts = [self.title, self.inst1, self.inst2, self.inst3,
                      self.inst4, self.inst5, self.inst6, self.inst7,
                      self.inst8]

    def hideInstructions(self):
        if self.instStatus == "show":
            self.instStatus = "hide"
            groupHide(self.insts)
        else: # instructions are hidden
            self.instStatus = "show"
            groupShow(self.insts)
        
    def __init__(self):
        base.enableParticles()
        self.keyMap = {"left":0, "right":0, "forward":0,"backward":0,
                       "upward":0, "downward":0, "leftward":0,"rightward":0,
                       "cam-left":0, "cam-right":0}
        _GOLD_PARTICLES.start(parent=render, renderParent=render)
        _GOLD_PARTICLES.setScale(200)
        self.instStatus = "show"
        self.musicCounter = 0
        self.music = load_bgmusic(_BGMUSIC[0])
        # self.music.play()
        self.volume = 0
        self.music.setVolume(self.volume)
        base.win.setClearColor(Vec4(0,0,0,1))
        self.above = 3.0
        # load environment
        self.loadEnviron()
        # load ralph
        self.loadRalph()
        # load sky box
        self.skyBoxLoad()
        # load pokemon
        self.loadPokemon()

        self.displayInformation()
        self.keyControl()
        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)
        taskMgr.add(self.move,"moveTask")
        taskMgr.add(self.setAbove,"setAbove")
        taskMgr.add(self.loadNextMusic, "loadRandomMusic")
        taskMgr.add(self.gold, "gold")
        # Game state variables
        self.isMoving = False
        # Set up the camera
        base.disableMouse()
        base.camera.setPos(self.ralph.getX(),self.ralph.getY(),2)
        self.cTrav = CollisionTraverser()
        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0,0,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()
        #self.camGroundColNp.show()
       
        # Uncomment this line to show a visual representation of the 
        # collisions occuring
        #self.cTrav.showCollisions(render)
        
        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def setAbove(self,task):
        if self.keyMap["upward"] == 1:
            self.above += 0.1
        if self.keyMap["downward"] == 1:
            self.above -= 0.1
        return task.cont
    #Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

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

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

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if (self.keyMap["left"]!=0):
            self.ralph.setH(self.ralph.getH() + 113 * globalClock.getDt())
            base.camera.setX(base.camera, +20 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 113 * globalClock.getDt())
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -75 * globalClock.getDt())
        if (self.keyMap["backward"] != 0):
            pass
            #self.ralph.setY(self.ralph, 75 * globalClock.getDt())
        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):# or (self.keyMap["backward"]!=0):
            if self.isMoving is False:
                #self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                #self.ralph.stop()
                #self.ralph.pose("walk",5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec*(5-camdist))
            camdist = 5.0

        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.
        
        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.camera.setZ(self.ralph.getZ() + 2.0)
            
        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        
        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + self.above)#self.above)
        
        base.camera.lookAt(self.floater)
        return task.cont
예제 #51
0
파일: pool.py 프로젝트: zhl8223/PlaneNet
class PoolBallGame(ShowBase):
    def __init__(self):
        # Initialize the ShowBase class from which we inherit, which will
        # create a window and set up everything we need for rendering into it.
        ShowBase.__init__(self)
        base.setBackgroundColor(0, 0, 0)

        self.accept("escape", sys.exit)  # Escape quits
        self.disableMouse()
        camera.setPosHpr(0, 0, 0, 0, 0, 0)

        lens = PerspectiveLens()
        lens.setFov(90, 60)
        lens.setNear(0.01)
        lens.setFar(100000)
        self.cam.node().setLens(lens)

        self.ballSize = 0.025
        self.cueLength = 0.2
        # self.ballRoot = render.attachNewNode("ballRoot")
        # #self.ball = loader.loadModel("models/ball")
        # self.ball = loader.loadModel("models/ball_0_center.egg")
        # #self.ball = loader.loadModel("models/ball.dae")
        # self.ball.setScale(ballSize, ballSize, ballSize)
        # self.ball.reparentTo(self.ballRoot)
        # #print(self.ball.getBounds())
        # #exit(1)
        # #self.ballSphere = self.ball.find("**/ball")
        # #print(self.ball.getScale()[0])
        # cs = CollisionSphere(0, 0, 0, 1)
        # self.ballSphere = self.ball.attachNewNode(CollisionNode('ball'))
        # self.ballSphere.node().addSolid(cs)

        # self.ballSphere.node().setFromCollideMask(BitMask32.bit(0))
        # self.ballSphere.node().setIntoCollideMask(BitMask32.bit(1))

        self.sceneIndex = 0
        self.planeInfo = PlaneScene(self.sceneIndex)

        self.planeScene = self.planeInfo.generateEggModel()
        self.planeScene.setTwoSided(True)
        self.planeScene.reparentTo(render)
        self.planeScene.hide()

        #get geometries from plane predictions
        planeTriangles, horizontalPlaneTriangles, self.gravityDirection = self.planeInfo.getPlaneTriangles(
        )

        # add pool balls
        self.ballRoots = []
        self.balls = []
        self.ballSpheres = []
        self.ballGroundRays = []
        for ballIndex in xrange(3):
            ballRoot = render.attachNewNode("ballRoot_" + str(ballIndex))
            ball = loader.loadModel("models/ball_" + str(ballIndex) +
                                    "_center.egg")
            ball.setScale(self.ballSize, self.ballSize, self.ballSize)

            cs = CollisionSphere(0, 0, 0, 1)
            ballSphere = ball.attachNewNode(
                CollisionNode('ball_' + str(ballIndex)))
            ballSphere.node().addSolid(cs)
            ballSphere.node().setFromCollideMask(
                BitMask32.bit(0) | BitMask32.bit(1) | BitMask32.bit(3)
                | BitMask32.bit(4))
            ballSphere.node().setIntoCollideMask(BitMask32.bit(1))

            ball.reparentTo(ballRoot)
            self.ballRoots.append(ballRoot)
            self.balls.append(ball)
            self.ballSpheres.append(ballSphere)

            ballGroundRay = CollisionRay()  # Create the ray
            ballGroundRay.setOrigin(0, 0, 0)  # Set its origin
            ballGroundRay.setDirection(
                self.gravityDirection[0], self.gravityDirection[1],
                self.gravityDirection[2])  # And its direction
            # Collision solids go in CollisionNode
            # Create and name the node
            ballGroundCol = CollisionNode('ball_ray_' + str(ballIndex))
            ballGroundCol.addSolid(ballGroundRay)  # Add the ray
            ballGroundCol.setFromCollideMask(
                BitMask32.bit(2))  # Set its bitmasks
            ballGroundCol.setIntoCollideMask(BitMask32.allOff())
            # Attach the node to the ballRoot so that the ray is relative to the ball
            # (it will always be 10 feet over the ball and point down)
            ballGroundColNp = ballRoot.attachNewNode(ballGroundCol)
            self.ballGroundRays.append(ballGroundColNp)

            ballRoot.hide()
            continue

        # Finally, we create a CollisionTraverser. CollisionTraversers are what
        # do the job of walking the scene graph and calculating collisions.
        # For a traverser to actually do collisions, you need to call
        # traverser.traverse() on a part of the scene. Fortunately, ShowBase
        # has a task that does this for the entire scene once a frame.  By
        # assigning it to self.cTrav, we designate that this is the one that
        # it should call traverse() on each frame.
        self.cTrav = CollisionTraverser()

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

        #self.cTrav.addCollider(self.ballSphere, self.cHandler)
        for ballSphere in self.ballSpheres:
            self.cTrav.addCollider(ballSphere, self.cHandler)
            continue
        for ballGroundRay in self.ballGroundRays:
            self.cTrav.addCollider(ballGroundRay, self.cHandler)
            continue
        #self.cTrav.addCollider(self.ballGroundColNp, self.cHandler)

        # Collision traversers have a built in tool to help visualize collisions.
        # Uncomment the next line to see it.
        #self.cTrav.showCollisions(render)

        # This section deals with lighting for the ball. Only the ball was lit
        # because the maze has static lighting pregenerated by the modeler
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.55, .55, .55, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(LVector3(0, 0, -1))
        directionalLight.setColor((0.375, 0.375, 0.375, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))

        for ballRoot in self.ballRoots:
            ballRoot.setLight(render.attachNewNode(ambientLight))
            ballRoot.setLight(render.attachNewNode(directionalLight))
            continue

        # This section deals with adding a specular highlight to the ball to make
        # it look shiny.  Normally, this is specified in the .egg file.
        m = Material()
        m.setSpecular((1, 1, 1, 1))
        m.setShininess(96)
        for ball in self.balls:
            ball.setMaterial(m, 1)
            continue

        # self.original = False
        # if self.original:
        #     camera.setPosHpr(0, 0, 25, 0, -90, 0)
        #     self.maze = loader.loadModel("models/maze")
        #     self.maze.reparentTo(render)
        #     self.walls = self.maze.find("**/wall_collide")
        #     self.walls.node().setIntoCollideMask(BitMask32.bit(0))
        #     self.walls.show()
        #     pass

        # create collision entities from plane predictions
        self.triNPs = []
        for triangleIndex, triangle in enumerate(planeTriangles):
            #print(triangleIndex)
            #for triangle in triangles:
            #print(triangle)
            tri = CollisionPolygon(
                Point3(triangle[0][0], triangle[0][1], triangle[0][2]),
                Point3(triangle[1][0], triangle[1][1], triangle[1][2]),
                Point3(triangle[2][0], triangle[2][1], triangle[2][2]))
            triNP = render.attachNewNode(
                CollisionNode('tri_' + str(triangleIndex)))
            triNP.node().setIntoCollideMask(BitMask32.bit(0))
            triNP.node().addSolid(tri)
            self.triNPs.append(triNP)
            #triNP.show()
            continue

        # create special collision entities for horizontal planes so that balls can fall on one horizontal plane and bounce on it
        for triangleIndex, triangle in enumerate(horizontalPlaneTriangles):
            #print(triangleIndex)
            #for triangle in triangles:
            #print(triangle)
            tri = CollisionPolygon(
                Point3(triangle[0][0], triangle[0][1], triangle[0][2]),
                Point3(triangle[1][0], triangle[1][1], triangle[1][2]),
                Point3(triangle[2][0], triangle[2][1], triangle[2][2]))
            triNP = render.attachNewNode(
                CollisionNode('ground_' + str(triangleIndex)))
            triNP.node().setIntoCollideMask(BitMask32.bit(2))
            triNP.node().addSolid(tri)
            self.triNPs.append(triNP)
            #triNP.show()
            continue

        # tri = CollisionPolygon(Point3(-1, 4, -1), Point3(2, 4, -1), Point3(2, 4, 2))
        # triNP = render.attachNewNode(CollisionNode('tri'))
        # triNP.node().setIntoCollideMask(BitMask32.bit(0))
        # triNP.node().addSolid(tri)
        # triNP.show()

        #self.planeScene.node().setIntoCollideMask(BitMask32.bit(0))
        # roomRootNP = self.planeScene
        # roomRootNP.flattenLight()
        # mesh = BulletTriangleMesh()
        # polygons = roomRootNP.findAllMatches("**/+GeomNode")

        # # p0 = Point3(-10, 4, -10)
        # # p1 = Point3(-10, 4, 10)
        # # p2 = Point3(10, 4, 10)
        # # p3 = Point3(10, 4, -10)
        # # mesh.addTriangle(p0, p1, p2)
        # # mesh.addTriangle(p1, p2, p3)

        # print(polygons)
        # for polygon in polygons:
        #     geom_node = polygon.node()
        #     #geom_node.reparentTo(self.render)
        #     #print(geom_node.getNumGeoms())
        #     ts = geom_node.getTransform()
        #     #print(ts)
        #     for geom in geom_node.getGeoms():
        #         mesh.addGeom(geom, ts)
        #         continue
        #     continue
        # #self.scene = roomRootNP
        # shape = BulletTriangleMeshShape(mesh, dynamic=False)
        # #shape = BulletPlaneShape(Vec3(0, 0, 1), 1)
        # room = BulletRigidBodyNode('scene')
        # room.addShape(shape)
        # #room.setLinearDamping(0.0)
        # #room.setFriction(0.0)
        # print(shape)
        # room.setDeactivationEnabled(False)
        # roomNP = render.attachNewNode(room)
        # roomNP.setPos(0, 0, 0)
        # roomNP.node().setIntoCollideMask(BitMask32.bit(0))
        # self.world = BulletWorld()
        # self.world.setGravity(Vec3(0, 0, 0))
        # self.world.attachRigidBody(roomNP.node())
        #room.setRestitution(1)

        #self.roomNP = self.scene

        # create the cue
        self.cueRoot = render.attachNewNode("cueRoot")
        self.cue = loader.loadModel("models/cue_center.egg")
        self.cue.setScale(self.cueLength * 3, self.cueLength * 3,
                          self.cueLength)
        self.cue.reparentTo(self.cueRoot)

        self.cuePos = (10, 0, 0)

        self.pickerNode = CollisionNode('mouseRay')
        # Attach that node to the camera since the ray will need to be positioned
        # relative to it
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        # Everything to be picked will use bit 1. This way if we were doing other
        # collision we could separate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(2))
        self.pickerNode.setIntoCollideMask(BitMask32.allOff())
        self.pickerRay = CollisionRay()  # Make our ray
        # Add it to the collision node
        self.pickerNode.addSolid(self.pickerRay)
        # Register the ray as something that can cause collisions
        self.cTrav.addCollider(self.pickerNP, self.cHandler)

        self.accept("mouse1", self.hit)  # left-click grabs a piece

        # create holes
        self.holeLength = 0.06
        holePos, holeHpr = self.planeInfo.getHolePos()
        self.holeRoot = render.attachNewNode("holeRoot")
        #self.hole = loader.loadModel("models/hole_horizontal_center.egg")
        self.hole = loader.loadModel("models/hole_color.egg")
        #self.hole = loader.loadModel("models/billiards_hole_center.egg")
        self.hole.setScale(self.holeLength, self.holeLength, self.holeLength)
        self.hole.reparentTo(self.holeRoot)
        self.hole.setTwoSided(True)
        self.holeRoot.setPos(holePos[0], holePos[1], holePos[2])
        self.holeRoot.setHpr(holeHpr[0], holeHpr[1], holeHpr[2])
        #tex = loader.loadTexture('models/Black_Hole.jpg')
        #self.hole.setTexture(tex, 1)
        self.holeRoot.hide()

        ct = CollisionTube(0, 0, 0, 0, 0.001, 0, 0.5)
        self.holeTube = self.hole.attachNewNode(CollisionNode('hole'))
        self.holeTube.node().addSolid(ct)
        self.holeTube.node().setFromCollideMask(BitMask32.allOff())
        self.holeTube.node().setIntoCollideMask(BitMask32.bit(4))
        #self.holeTube.show()

        # create portals
        inPortalPos, inPortalHpr, outPortalPos, outPortalHpr, self.portalNormal = self.planeInfo.getPortalPos(
        )
        self.portalLength = 0.06
        self.inPortalRoot = render.attachNewNode("inPortalRoot")
        self.inPortal = loader.loadModel("models/portal_2_center.egg")
        self.inPortal.setScale(self.portalLength, self.portalLength,
                               self.portalLength)
        self.inPortal.reparentTo(self.inPortalRoot)
        self.inPortalRoot.setPos(inPortalPos[0], inPortalPos[1],
                                 inPortalPos[2])
        self.inPortalRoot.setHpr(inPortalHpr[0], inPortalHpr[1],
                                 inPortalHpr[2])
        self.inPortalRoot.hide()

        ct = CollisionTube(0, 0, 0, 0, 0.001, 0, 1)
        self.inPortalTube = self.inPortal.attachNewNode(
            CollisionNode('portal_in'))
        self.inPortalTube.node().addSolid(ct)
        self.inPortalTube.node().setFromCollideMask(BitMask32.allOff())
        self.inPortalTube.node().setIntoCollideMask(BitMask32.bit(3))
        #self.inPortalTube.hide()

        self.outPortalRoot = render.attachNewNode("outPortalRoot")
        self.outPortal = loader.loadModel("models/portal_2_center.egg")
        self.outPortal.setScale(self.portalLength, self.portalLength,
                                self.portalLength)
        self.outPortal.reparentTo(self.outPortalRoot)
        self.outPortalRoot.setPos(outPortalPos[0], outPortalPos[1],
                                  outPortalPos[2])
        self.outPortalRoot.setHpr(outPortalHpr[0], outPortalHpr[1],
                                  outPortalHpr[2])
        self.outPortalRoot.hide()

        ct = CollisionTube(0, 0, 0, 0, 0.001, 0, 1)
        self.outPortalTube = self.outPortal.attachNewNode(
            CollisionNode('portal_out'))
        self.outPortalTube.node().addSolid(ct)
        self.outPortalTube.node().setFromCollideMask(BitMask32.allOff())
        self.outPortalTube.node().setIntoCollideMask(BitMask32.bit(3))
        #self.outPortalTube.hide()
        #self.inPortalTube.show()
        #self.outPortalTube.show()
        #self.holeTube.show()

        #self.cTrav.addCollider(self.holeTube, self.cHandler)

        # create background image
        background_image = loader.loadTexture('dump/' + str(self.sceneIndex) +
                                              '_image.png')
        cm = CardMaker('background')
        cm.setHas3dUvs(True)
        info = np.load('dump/' + str(self.sceneIndex) + '_info.npy')
        #self.camera = getCameraFromInfo(self.info)
        depth = 10.0
        sizeU = info[2] / info[0] * depth
        sizeV = info[6] / info[5] * depth
        cm.setFrame(Point3(-sizeU, depth, -sizeV),
                    Point3(sizeU, depth, -sizeV), Point3(sizeU, depth, sizeV),
                    Point3(-sizeU, depth, sizeV))
        self.card = self.render.attachNewNode(cm.generate())
        self.card.setTransparency(True)
        self.card.setTexture(background_image)
        self.card.hide()

        self.ballGroundMap = {}
        self.ballBouncing = np.full(len(self.balls), 3)

        self.started = False
        self.start()

        #self.hitIndex = -1

        self.showing = 'parts'
        self.showingProgress = 0

        partsScene = PartsScene(self.sceneIndex)
        self.planeNPs, self.planeCenters = partsScene.generateEggModel()
        return

    def start(self):
        #startPos = self.maze.find("**/start").getPos()
        #self.ballRoot.setPos(0.5, 0, 0)
        #self.ballV = LVector3(0, 0.5, 0)         # Initial velocity is 0
        #self.accelV = LVector3(0, 0, 0)        # Initial acceleration is 0

        self.ballVs = []
        self.accelVs = []
        for ballIndex in xrange(len(self.balls)):
            self.ballVs.append(LVector3(0, 0, 0))
            self.accelVs.append(LVector3(0, 0, 0))
            continue
        self.ballRoots[0].setPos(0.2, 1.05, -0.1)
        #self.ballVs[0] = LVector3(0, 0.0, 0)
        self.ballRoots[1].setPos(0.32, 1.2, -0.1)
        #self.ballRoots[2].setHpr(0, 0, 90)
        self.ballRoots[2].setPos(-0.4, 1.1, 0.4)
        axis = LVector3.up()
        prevRot = LRotationf(self.balls[2].getQuat())
        newRot = LRotationf(axis, 90)
        self.balls[2].setQuat(prevRot * newRot)

        # Create the movement task, but first make sure it is not already
        # running
        taskMgr.remove("rollTask")
        #taskMgr.remove("mouseTask")
        self.mainLoop = taskMgr.add(self.rollTask, "rollTask")
        #self.mainLoop = taskMgr.add(self.mouseTask, "mouseTask")

        return

    def hit(self):
        if abs(self.cuePos[0]) < 5:
            # direction and strength based on mouse position
            cueDirection = self.ballRoots[0].getPos() - LVector3(
                self.cuePos[0], self.cuePos[1], self.cuePos[2])
            power = cueDirection.length()
            cueDirection = cueDirection / cueDirection.length()
            self.ballVs[0] = cueDirection * np.sqrt(self.cuePower)

            # elif self.hitIndex == 0:
            #     self.ballVs[0] = LVector3(0.5, 0.47, 0)
            #     self.hitIndex += 1
            # elif self.hitIndex == 1:
            #     self.ballVs[0] = LVector3(0.072, 0.62, 0)
            #     self.hitIndex += 1
            # elif self.hitIndex == 2:
            #     self.ballVs[0] = LVector3(0.7, 0.0, 0)
            #     self.hitIndex += 1
            #     pass

            self.started = True
            print('hit', cueDirection)
            self.ballBouncing = np.full(len(self.balls), 3)
            pass

    # This function handles the collision between the ball and a wall
    def planeCollideHandler(self, colEntry):
        #return
        ballName = colEntry.getFromNode().getName()
        ballIndex = int(ballName[5:])

        # First we calculate some numbers we need to do a reflection
        # print(colEntry)
        # name = colEntry.getIntoNode().getName()
        # triangleIndex = int(name[4:])
        # print(triangleIndex)
        # print(self.planeNormals[triangleIndex])
        # print(colEntry.getSurfaceNormal(render))
        # exit(1)
        norm = colEntry.getSurfaceNormal(render) * -1  # The normal of the wall
        norm.normalize()
        curSpeed = self.ballVs[ballIndex].length()  # The current speed
        inVec = self.ballVs[ballIndex] / curSpeed  # The direction of travel
        velAngle = norm.dot(inVec)  # Angle of incidance
        hitDir = colEntry.getSurfacePoint(
            render) - self.ballRoots[ballIndex].getPos()
        hitDir.normalize()
        # The angle between the ball and the normal
        hitAngle = norm.dot(hitDir)

        # Ignore the collision if the ball is either moving away from the wall
        # already (so that we don't accidentally send it back into the wall)
        # and ignore it if the collision isn't dead-on (to avoid getting caught on
        # corners)
        #print(velAngle, hitAngle)

        if velAngle > 0 and hitAngle > .995:
            print('plane', ballName, velAngle)
            # Standard reflection equation
            reflectVec = (norm * norm.dot(inVec * -1) * 2) + inVec

            # This makes the velocity half of what it was if the hit was dead-on
            # and nearly exactly what it was if this is a glancing blow
            #self.ballVs[ballIndex] = reflectVec * (curSpeed * (((1 - velAngle) * .5) + .5))
            self.ballVs[ballIndex] = reflectVec * curSpeed
            # Since we have a collision, the ball is already a little bit buried in
            # the wall. This calculates a vector needed to move it so that it is
            # exactly touching the wall
            disp = (colEntry.getSurfacePoint(render) -
                    colEntry.getInteriorPoint(render))
            newPos = self.ballRoots[ballIndex].getPos() + disp
            self.ballRoots[ballIndex].setPos(newPos)
            pass
        return

    # This function handles the collision between the ball and a wall
    def portal(self, colEntry):
        ballName = colEntry.getFromNode().getName()
        print('portal', ballName)
        ballIndex = int(ballName[5:])

        #norm = colEntry.getSurfaceNormal(render) * -1  # The normal of the wall
        norm = LVector3(self.portalNormal[0], self.portalNormal[1],
                        self.portalNormal[2])
        norm.normalize()
        curSpeed = self.ballVs[ballIndex].length()  # The current speed
        inVec = self.ballVs[ballIndex] / curSpeed  # The direction of travel
        velAngle = norm.dot(inVec)  # Angle of incidance
        hitDir = colEntry.getSurfacePoint(
            render) - self.ballRoots[ballIndex].getPos()
        hitDir.normalize()
        # The angle between the ball and the normal
        #print(colEntry.getSurfacePoint(render), self.ballRoots[ballIndex].getPos())
        #print(norm, hitDir)
        hitAngle = norm.dot(hitDir)

        # Ignore the collision if the ball is either moving away from the wall
        # already (so that we don't accidentally send it back into the wall)
        # and ignore it if the collision isn't dead-on (to avoid getting caught on
        # corners)
        #print(velAngle, hitAngle)
        #print(velAngle, hitAngle)
        if velAngle > 0:
            print(colEntry.getIntoNode().getName())
            if '_in' in colEntry.getIntoNode().getName():
                self.ballRoots[ballIndex].setPos(self.outPortalRoot.getPos())
            else:
                self.ballRoots[ballIndex].setPos(self.inPortalRoot.getPos())
                pass
            print(self.ballVs[ballIndex],
                  ((norm * norm.dot(inVec * -1) * 2) + inVec) * curSpeed, norm)
            #exit(1)
            self.ballVs[ballIndex] = (
                (norm * norm.dot(inVec * -1) * 2) + inVec) * curSpeed
            #self.ballVs[ballIndex] *= -1
            pass
        return

    # This function handles the collision between the ball and a wall
    def ballCollideHandler(self, colEntry):
        # First we calculate some numbers we need to do a reflection
        fromBallName = colEntry.getFromNode().getName()
        fromBallIndex = int(fromBallName[5:])
        #if fromBallIndex != 0:
        #return
        intoBallName = colEntry.getIntoNode().getName()
        intoBallIndex = int(intoBallName[5:])

        print('ball', fromBallName, intoBallName)

        norm = colEntry.getSurfaceNormal(render) * -1  # The normal of the wall
        norm = norm / norm.length()
        curSpeed = self.ballVs[fromBallIndex].length()  # The current speed
        inVec = self.ballVs[fromBallIndex] / curSpeed  # The direction of travel
        velAngle = norm.dot(inVec)  # Angle of incidance
        hitDir = colEntry.getSurfacePoint(
            render) - self.ballRoots[fromBallIndex].getPos()
        hitDir.normalize()
        # The angle between the ball and the normal
        hitAngle = norm.dot(hitDir)

        # print(norm)
        # print(self.ballVs[fromBallIndex])
        # print(velAngle, hitAngle)
        # print(self.ballRoots[fromBallIndex].getPos())
        # print(self.ballRoots[intoBallIndex].getPos())
        # exit(1)
        #print(fromBallIndex, intoBallIndex)
        #exit(1)

        # Ignore the collision if the ball is either moving away from the wall
        # already (so that we don't accidentally send it back into the wall)
        # and ignore it if the collision isn't dead-on (to avoid getting caught on
        # corners)
        #print(velAngle, hitAngle)
        if velAngle > 0 and hitAngle > .995:
            # Standard reflection equation
            self.ballVs[fromBallIndex] = (
                (norm * norm.dot(inVec * -1)) + inVec) * curSpeed

            disp = (colEntry.getSurfacePoint(render) -
                    colEntry.getInteriorPoint(render))
            newPos = self.ballRoots[fromBallIndex].getPos() + disp
            self.ballRoots[fromBallIndex].setPos(newPos)

            self.ballVs[intoBallIndex] = norm * norm.dot(inVec) * curSpeed
            pass
        return

    # the function handles the situation when a ball falls on a lower horizontal plane
    def groundCollideHandler(self, colEntry):
        # Set the ball to the appropriate Z value for it to be exactly on the
        # ground
        ballName = colEntry.getFromNode().getName()

        if 'mouseRay' in ballName:
            for v in self.ballVs:
                if v.length() > 1e-4:
                    self.cuePos = (10, 0, 0)
                    return
                continue
            #print(self.mouseWatcherNode.hasMouse())
            norm = colEntry.getSurfaceNormal(render)
            norm.normalize()
            touchPoint = colEntry.getSurfacePoint(render)
            cuePoint = touchPoint + norm * self.ballSize
            cueDirection = self.ballRoots[0].getPos() - cuePoint
            self.cuePower = cueDirection.length()
            cueDirection = cueDirection / cueDirection.length()
            cuePoint = self.ballRoots[0].getPos(
            ) - cueDirection * self.cueLength
            self.cuePos = cuePoint
            #self.cueRoot.setH(np.rad2deg(np.arctan2(cueDirection[1], cueDirection[0])) + 90)
            self.cueRoot.setH(
                np.rad2deg(np.arctan2(cueDirection[1], cueDirection[0])) + 90)
            self.cueRoot.setP(-np.rad2deg(np.arcsin(cueDirection[2])) + 90)
            #self.cueRoot.setP(90)
            #print(np.rad2deg(np.arctan2(cueDirection[1], cueDirection[0])), np.rad2deg(np.arcsin(cueDirection[2])))

            # prevRot = LRotationf(self.cue.getQuat())
            # axis = LVector3.up().cross(self.ballVs[ballIndex])
            # newRot = LRotationf(axis, 45.5 * dt * self.ballVs[ballIndex].length())
            # self.balls[ballIndex].setQuat(prevRot * newRot)
            return

        #print('ground', ballName)
        #print(ballName, colEntry.getIntoNode().getName())
        #print(colEntry.getFromNode().getBitMask(), colEntry.getIntoNode().getBitMask())
        ballIndex = int(ballName[9:])

        groundName = colEntry.getIntoNode().getName()
        groundIndex = int(groundName[7:])
        #print(groundIndex)
        #print(self.ballGroundMap)
        if ballIndex == 0 and False:
            print(groundIndex, self.ballGroundMap)
            pass

        if ballIndex not in self.ballGroundMap or self.ballGroundMap[
                ballIndex][0] != groundIndex:
            return

        norm = -colEntry.getSurfaceNormal(render)
        norm = norm / norm.length()

        curSpeed = self.ballVs[ballIndex].length()  # The current speed
        inVec = self.ballVs[ballIndex] / max(curSpeed,
                                             1e-4)  # The direction of travel
        velAngle = norm.dot(inVec)  # Angle of incidance
        hitDir = colEntry.getSurfacePoint(
            render) - self.ballRoots[ballIndex].getPos()
        hitDir.normalize()
        # The angle between the ball and the normal
        hitAngle = norm.dot(hitDir)

        surfacePos = colEntry.getSurfacePoint(render)
        ballPos = self.ballRoots[ballIndex].getPos()
        surfacePos = ballPos + norm * norm.dot(surfacePos - ballPos)

        distance = norm.dot(surfacePos - ballPos)
        if distance < 0:
            return

        if distance < self.ballSize + 1e-3:
            self.ballRoots[ballIndex].setPos(surfacePos - norm * self.ballSize)
            if self.ballVs[ballIndex].length() > 1e-2:
                self.ballVs[ballIndex] = (-norm * velAngle + inVec) * curSpeed
                #self.ballVs[ballIndex] = -norm.cross(norm.cross(self.ballVs[ballIndex]))
                self.accelVs[ballIndex] = -self.ballVs[
                    ballIndex] / self.ballVs[ballIndex].length() * 0.0025
            else:
                self.ballVs[ballIndex] = LVector3(0, 0, 0)
                self.accelVs[ballIndex] = LVector3(0, 0, 0)
                pass
        else:
            self.accelVs[
                ballIndex] = self.accelVs[ballIndex] - norm * norm.dot(
                    self.accelVs[ballIndex]) + norm * 0.05
            pass
        return

        # if self.started:
        #     if abs(distance - self.ballSize) > 0.001 and abs(distance - self.ballSize) < self.ballSize:
        #         self.ballRoots[ballIndex].setPos(surfacePos - norm * self.ballSize)
        #         pass
        #     self.ballVs[ballIndex] = -norm.cross(norm.cross(self.ballVs[ballIndex]))
        #     if self.ballVs[ballIndex].length() > 1e-3:
        #         self.accelVs[ballIndex] = -self.ballVs[ballIndex] / self.ballVs[ballIndex].length() * 0.015
        #     else:
        #         self.ballVs[ballIndex] = LVector3(0, 0, 0)
        #         self.accelVs[ballIndex] = LVector3(0, 0, 0)
        #         pass
        #     #print(self.ballVs[ballIndex], self.accelVs[ballIndex])
        #     #print(surfacePos - norm * self.ballSize)

        #     return

        if ballIndex == 0:
            print('distance_1', self.started, distance, velAngle,
                  self.ballVs[ballIndex], self.accelVs[ballIndex])

        if distance < self.ballSize:
            self.ballRoots[ballIndex].setPos(surfacePos - norm * self.ballSize)
            if velAngle > 0 and hitAngle > .995:
                if abs(velAngle * curSpeed) < 0.2:
                    if ((-norm * velAngle + inVec) * curSpeed).length() < 0.02:
                        self.ballVs[ballIndex] = LVector3(0, 0, 0)
                        self.accelVs[ballIndex] = LVector3(0, 0, 0)
                        pass
                    pass
                else:
                    if self.ballBouncing[ballIndex] > 0:
                        if ballIndex == 0:
                            print('bouncing')
                            pass
                        self.ballVs[ballIndex] = (
                            -norm * velAngle + inVec
                        ) * curSpeed * 0.5 - norm * velAngle * curSpeed * 0.25
                        self.accelVs[ballIndex] = LVector3(0, 0, 0)
                        self.ballBouncing[ballIndex] -= 1
                    else:
                        self.ballVs[ballIndex] = (-norm * velAngle +
                                                  inVec) * curSpeed
                        self.accelVs[ballIndex] = LVector3(0, 0, 0)
                        pass
                    pass
                pass

            pass

        if (distance - self.ballSize) > 0.001:
            self.accelVs[
                ballIndex] = self.accelVs[ballIndex] - norm * norm.dot(
                    self.accelVs[ballIndex]) + norm * 0.1
            # print(self.accelVs[ballIndex] - norm * norm.dot(self.accelVs[ballIndex]))
            # print(norm)
            # print(inVec)
            # print(velAngle)
            # print(-norm * velAngle + inVec)
            # print(norm * 0.01)
            # exit(1)
        elif distance - self.ballSize > -0.001:
            if self.ballVs[ballIndex].length() < 0.001:
                #print('stop', self.ballVs[ballIndex], self.accelVs[ballIndex])

                self.ballVs[ballIndex] = LVector3(0, 0, 0)
                self.accelVs[ballIndex] = LVector3(0, 0, 0)
                self.started = False
            else:
                if abs(velAngle) < 1e-3:
                    self.ballVs[ballIndex] = (-norm * velAngle +
                                              inVec) * curSpeed
                    #self.ballVs[ballIndex] = -norm.cross(norm.cross(self.ballVs[ballIndex]))
                    self.accelVs[ballIndex] = -self.ballVs[
                        ballIndex] / self.ballVs[ballIndex].length() * 0.01
                    #print('speed', self.ballVs[ballIndex], self.accelVs[ballIndex])
                    pass
                pass
            pass

        # #print(distance - self.ballSize)
        # if (distance - self.ballSize) > 0.01:
        #     self.accelVs[ballIndex] = self.accelVs[ballIndex] - norm * norm.dot(self.accelVs[ballIndex]) + norm * 0.01
        #     #if ballIndex == 0:
        #     #print(velAngle, self.ballVs[ballIndex], self.accelVs[ballIndex], norm)
        #     #pass

        #     print('fall', self.accelVs[ballIndex], distance)
        #     # print(self.accelVs[ballIndex] - norm * norm.dot(self.accelVs[ballIndex]))
        #     # print(norm)
        #     # print(inVec)
        #     # print(velAngle)
        #     # print(-norm * velAngle + inVec)
        #     # print(norm * 0.01)
        #     # exit(1)
        # else:
        #     #hitAngle > .995
        #     #print(velAngle)
        #     #print(norm)

        #     #self.ballRoots[ballIndex].setPos(surfacePos - norm * self.ballSize)
        #     if curSpeed > 1e-1:
        #         print('angle', velAngle, norm)
        #         self.norm = norm
        #         pass
        #     if velAngle > 1e-3:
        #         if curSpeed < 1e-3:
        #             self.ballVs[ballIndex] = LVector3(0, 0, 0)
        #             self.accelVs[ballIndex] = LVector3(0, 0, 0)
        #             self.ballRoots[ballIndex].setPos(surfacePos - norm * self.ballSize)
        #         else:
        #             self.ballVs[ballIndex] = (-norm * velAngle + inVec) * curSpeed * 0.9 - norm * velAngle * curSpeed * 0.25
        #             self.accelVs[ballIndex] = LVector3(0, 0, 0)
        #             pass
        #         #print((-norm * velAngle + inVec) * curSpeed * 0.9, norm * velAngle * curSpeed * 0.25)
        #         #print(curSpeed, norm.dot(self.ballVs[ballIndex]) / self.ballVs[ballIndex].length(), self.ballVs[ballIndex], self.accelVs[ballIndex])
        #         #print(norm.dot(self.ballVs[ballIndex]) / self.ballVs[ballIndex].length(), norm.dot(self.accelVs[ballIndex]) / self.accelVs[ballIndex].length(), self.ballVs[ballIndex], self.accelVs[ballIndex])
        #     elif velAngle > -1e-3:
        #         if self.ballVs[ballIndex].length() < 0.001:
        #             #self.ballVs[ballIndex] = LVector3(0, 0, 0)
        #             #self.accelVs[ballIndex] = LVector3(0, 0, 0)
        #             #print('stop', self.ballVs[ballIndex], self.accelVs[ballIndex])
        #             pass
        #         else:
        #             #self.ballVs[ballIndex] = (-norm * velAngle + inVec) * curSpeed * 0.9
        #             #print(self.ballVs[ballIndex], self.accelVs[ballIndex])
        #             self.accelVs[ballIndex] = -(-norm * velAngle + inVec) * 0.1
        #             print('accel', self.accelVs[ballIndex])
        #             pass
        #         pass
        #     else:
        #         #print('stop', self.ballVs[ballIndex], self.accelVs[ballIndex])
        #         #self.ballVs[ballIndex] = LVector3(0, 0, 0)
        #         #self.accelVs[ballIndex] = LVector3(0, 0, 0)
        #         pass
        #     pass
        return

    # This is the task that deals with making everything interactive
    def rollTask(self, task):
        # Standard technique for finding the amount of time since the last
        # frame
        dt = globalClock.getDt()

        # If dt is large, then there has been a # hiccup that could cause the ball
        # to leave the field if this functions runs, so ignore the frame
        if dt > .2:
            return Task.cont

        # if base.mouseWatcherNode.is_button_down('a'):
        #     self.holeRoot.setH(self.holeRoot.getH() + 1)
        #     print(self.holeRoot.getHpr())
        #     pass
        # if base.mouseWatcherNode.is_button_down('s'):
        #     self.holeRoot.setP(self.holeRoot.getP() + 1)
        #     print(self.holeRoot.getHpr())
        #     pass
        # if base.mouseWatcherNode.is_button_down('d'):
        #     self.holeRoot.setR(self.holeRoot.getR() + 1)
        #     print(self.holeRoot.getHpr())
        #     pass

        # go through different visualizations
        if base.mouseWatcherNode.is_button_down(
                'space') and self.showing == 'none':
            self.showing = 'parts'
            self.showingProgress = 0
            pass
        #print(self.showing)
        #print(self.showing)
        if self.showing == 'none':
            return Task.cont
        if self.showing == 'parts':
            self.showingProgress += 0.01
            #self.showingProgress += 1
            #print(self.showingProgress)
            scale = 2 - self.showingProgress
            scaleY = 1 + (scale - 1) * 0.5
            for planeIndex, planeNP in enumerate(self.planeNPs):
                center = self.planeCenters[planeIndex]
                planeNP.setPos(center[0] * scale, center[1] * scaleY,
                               center[2] * scale)
                planeNP.reparentTo(self.render)
                planeNP.setTwoSided(True)
                continue
            if self.showingProgress > 1:
                self.showing = 'moving'
                for planeIndex, planeNP in enumerate(self.planeNPs):
                    planeNP.removeNode()
                    continue
                self.planeScene.show()
                self.showingProgress = 1
            return Task.cont
        if self.showing == 'moving':
            self.showingProgress += 0.005
            #self.showingProgress += 1
            #print(self.showingProgress, np.sign(self.showingProgress - 0.5) * min(self.showingProgress % 0.5, 0.5 - self.showingProgress % 0.5) * 4)
            self.camera.setPos(
                np.sign(self.showingProgress - 0.5) *
                min(self.showingProgress % 0.5,
                    0.5 - self.showingProgress % 0.5) * 3, 0, 0)
            #self.camera.setHpr(angleDegrees, 0, 0)
            #self.camera.lookAt(0, 0, 0)
            self.camera.lookAt(0, 3, 0)
            if self.showingProgress > 1:
                self.showing = 'geometry'
                self.camera.setPos(0, 0, 0)
                #self.planeScene.removeNode()
                # for triNP in self.triNPs:
                #     triNP.show()
                #     continue
                self.showingProgress = 1
            return Task.cont
        if self.showing == 'geometry':
            self.showingProgress += 0.02
            if self.showingProgress > 1:
                #self.showing = 'image'
                self.showing = 'placement'
                self.showingProgress = 0
                self.holeRoot.show()
                self.inPortalRoot.show()
                self.outPortalRoot.show()
                self.inPortalTube.show()
                self.outPortalTube.show()
                for ballRoot in self.ballRoots:
                    ballRoot.show()
                    continue
                self.showingProgress = 0
                pass
            return Task.cont
        # if self.showing == 'placement':
        #     self.showingProgress += 0.005
        #         continue

        # mouse pose
        if self.mouseWatcherNode.hasMouse():
            mpos = self.mouseWatcherNode.getMouse()
            self.mpos = mpos
            self.pickerRay.setFromLens(self.camNode, mpos.getX(), mpos.getY())
            pass

        #if base.mouseWatcherNode.is_button_down('space') and self.showing == 'placement':
        if self.showing == 'placement':
            self.card.show()
            self.planeScene.removeNode()
            self.showing = 'image'
            pass
        # if base.mouseWatcherNode.is_button_down('space') and self.showing == 'image':
        #     for triNP in self.triNPs:
        #         triNP.hide()
        #         continue
        #     self.showing = 'start'
        #     pass

        # for each plane, check which horizontal plane it is sitting on
        self.ballGroundMap = {}
        for i in range(self.cHandler.getNumEntries()):
            entry = self.cHandler.getEntry(i)
            ballName = entry.getFromNode().getName()
            groundName = entry.getIntoNode().getName()
            if 'ball_ray_' not in ballName:
                continue
            if 'ground_' not in groundName:
                continue
            ballIndex = int(ballName[9:])
            groundIndex = int(groundName[7:])
            norm = -entry.getSurfaceNormal(render)
            if norm.length() == 0:
                continue
            norm = norm / norm.length()
            distance = norm.dot(
                entry.getSurfacePoint(render) -
                self.ballRoots[ballIndex].getPos())
            #print(distance)
            if distance < 0:
                continue
            if ballIndex not in self.ballGroundMap or distance < self.ballGroundMap[
                    ballIndex][1]:
                self.ballGroundMap[ballIndex] = (groundIndex, distance)
                pass
            continue

        # The collision handler collects the collisions. We dispatch which function
        # to handle the collision based on the name of what was collided into
        for i in range(self.cHandler.getNumEntries()):
            entry = self.cHandler.getEntry(i)
            fromName = entry.getFromNode().getName()
            #if 'mouseRay' in fromName:
            #continue
            name = entry.getIntoNode().getName()
            #if name == "plane_collide":
            if 'tri_' in name:
                self.planeCollideHandler(entry)
            #elif name == "wall_collide":
            #self.wallCollideHandler(entry)
            #elif name == "ground_collide":
            #self.groundCollideHandler(entry)
            elif 'ball_' in name:
                self.ballCollideHandler(entry)
            elif 'ground_' in name:
                self.groundCollideHandler(entry)
            elif 'hole' in name:
                self.score(entry)
            elif 'portal_' in name:
                self.portal(entry)
                pass
            continue

        # Read the mouse position and tilt the maze accordingly
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()  # get the mouse position
            #self.maze.setP(mpos.getY() * -10)
            #self.maze.setR(mpos.getX() * 10)
            pass

        # if base.mouseWatcherNode.is_button_down('mouse1'):
        #     print(base.mouseWatcherNode.getMouseX())
        #     print(base.mouseWatcherNode.getMouseY())
        #     exit(1)

        # Finally, we move the ball
        # Update the velocity based on acceleration
        for ballIndex in xrange(len(self.balls)):
            if self.ballVs[ballIndex].length(
            ) < 1e-4 and self.ballVs[ballIndex].dot(
                    self.accelVs[ballIndex]) < -1e-4:
                self.ballVs[ballIndex] = LVector3(0, 0, 0)
                self.accelVs[ballIndex] = LVector3(0, 0, 0)
            else:
                self.ballVs[ballIndex] += self.accelVs[ballIndex] * dt * ACCEL
                pass
            #print('current speed', self.ballVs[ballIndex], self.accelVs[ballIndex])
            # Clamp the velocity to the maximum speed
            if self.ballVs[ballIndex].lengthSquared() > MAX_SPEED_SQ:
                self.ballVs[ballIndex].normalize()
                self.ballVs[ballIndex] *= MAX_SPEED
                pass
            #print(self.ballVs[ballIndex], self.accelVs[ballIndex], self.ballRoots[ballIndex].getPos())

            # Update the position based on the velocity
            self.ballRoots[ballIndex].setPos(
                self.ballRoots[ballIndex].getPos() +
                (self.ballVs[ballIndex] * dt))

            # This block of code rotates the ball. It uses something called a quaternion
            # to rotate the ball around an arbitrary axis. That axis perpendicular to
            # the balls rotation, and the amount has to do with the size of the ball
            # This is multiplied on the previous rotation to incrimentally turn it.
            prevRot = LRotationf(self.balls[ballIndex].getQuat())
            axis = LVector3.up().cross(self.ballVs[ballIndex])
            newRot = LRotationf(
                axis,
                np.rad2deg(dt * self.ballVs[ballIndex].length() /
                           self.ballSize))
            self.balls[ballIndex].setQuat(prevRot * newRot)
            continue

        self.cueRoot.setPos(self.cuePos[0], self.cuePos[1], self.cuePos[2])
        return Task.cont  # Continue the task indefinitely

    # handle scoring (when a ball fall in a hole)
    def score(self, colEntry):
        ballName = colEntry.getFromNode().getName()
        if 'ball_' not in ballName:
            return
        print('score', ballName)
        ballIndex = int(ballName[5:])
        self.ballRoots[ballIndex].removeNode()

        del self.ballRoots[ballIndex]
        del self.balls[ballIndex]
        del self.ballSpheres[ballIndex]
        del self.ballGroundRays[ballIndex]
        del self.ballVs[ballIndex]
        del self.accelVs[ballIndex]
        for otherIndex in xrange(ballIndex, len(self.balls)):
            self.ballSpheres[otherIndex].setName('ball_' + str(otherIndex))
            self.ballGroundRays[otherIndex].setName('ball_ray_' +
                                                    str(otherIndex))
            continue
        return
예제 #52
0
class World(DirectObject):
    mySound = base.loader.loadSfx("trial.mp3")

    #Used for adding a virus at a randomly generated position
    def random_vgen(self):
        print 'I am in random'
        for i in range(0, 5):

            self.a[random.randint(0, 7)][random.randint(0, 7)] = 1

    def initializer(self, level):

        self.turns = 0

        ##   Level Definition

        def levelone():
            self.a[4][4] = 1
            self.a[4][5] = 1
            self.a[4][6] = 1
            self.a[5][2] = 1
            self.a[3][5] = 1
            self.a[4][6] = 1
            self.a[5][5] = 1

        def leveltwo():
            self.a[4][3] = 1
            self.a[4][5] = 1
            self.a[4][7] = 1
            self.a[5][2] = 1
            self.a[3][5] = 1
            self.a[2][2] = 1
            self.a[5][3] = 1
            self.a[1][2] = 1

        def levelthree():
            self.a[4][4] = 1
            self.a[4][5] = 1
            self.a[4][6] = 1
            self.a[5][2] = 1
            self.a[3][5] = 1
            self.a[4][6] = 1
            self.a[5][5] = 1
            self.a[4][3] = 1
            self.a[4][5] = 1
            self.a[4][7] = 1
            self.a[5][2] = 1
            self.a[3][5] = 1
            self.a[2][2] = 1
            self.a[5][3] = 1

        options = {1: levelone, 2: leveltwo, 3: levelthree}

        options[level]()

        print self.a
        temp = []
        count = 0
        for element in reversed(self.a):
            for ele in element:
                #print 'cheking element is 1 : ' + str(ele)
                if ele == 1:
                    temp.append(count)
                    self.pieces[count] = Monster(count, WHITE)
                    #self.squares[count].setColor(HIGHLIGHT)
                count = count + 1
        self.list = temp

    def showscore(self):
        try:
            self.score.destroy()
        except:
            pass
        self.score = OnscreenText(text='Number of Turns : %s' % (self.turns),
                                  pos=(0.5, 0.95),
                                  scale=0.07,
                                  mayChange=True)

    def menuscreen(self):

        # Callback function to set  text
        def setText():
            b.destroy()
            helptext.destroy()

        # Add button
        b = DirectButton(text=("START", "START", "START", "disabled"),
                         scale=0.15,
                         command=setText,
                         pos=(0, 0, 0.85))

        helptext = OnscreenText(text='''
    STORY:
    Hello Mad Scientist!
    You are so close to finding the cure to aids!
    You understood the behaviour and can finally manipulate the virus to kill itself!
    But time is running out!
    You have a red and white blood cell sample infected with AIDS Virus.

    INSTRUCTIONS:
    The AIDS Virus obeys the Conway's Game of Life. Who would have guessed?
    1.  If virus is surrounded by more than 3 viruses, it dies of suffocation
    2.  If virus is surrounded by less than 2 viruses, it dies of underpopulation
    3.  If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned due to breeding.

    AIM:
    To kill all the viruses, by moving one of them every turn.

    ''',
                                pos=(-0.90, 0.72),
                                frame=(123, 123, 123, 1),
                                wordwrap=25,
                                align=TextNode.ALeft,
                                bg=(0.23, 0.243, 0.13, 0.9))

    def endscreen(self):
        def restart():
            taskMgr.remove(self.mouseTask)
            for i in range(64):
                self.squares[i].setColor(SquareColor(i))
            scorecard.destroy()
            restartb.destroy()
            end.destroy()
            nextlevelb.destroy()
            self.reference.destroy()
            self.mySound.stop()
            try:
                self.score.destroy()
            except:
                pass
            print 'restarting'
            print self.a
            print self.list

            World()

        def quitgame():
            sys.exit()

        def nextLevel():
            self.currlevel = self.currlevel + 1
            nextlevelb.destroy()
            scorecard.destroy()
            restartb.destroy()
            end.destroy()
            self.score.destroy()
            self.initializer(self.currlevel)

        # Add button

        scorecard = OnscreenText(text='You finished it in %s turns! ' %
                                 (self.turns),
                                 frame=(123, 123, 123, 0),
                                 wordwrap=25,
                                 bg=(0.2, 0, 0.8, 1))

        nextlevelb = DirectButton(text=("NEXT LEVEL", "NEXT LEVEL",
                                        "NEXT LEVEL", "disabled"),
                                  scale=0.15,
                                  command=nextLevel,
                                  pos=(0, 0, -0.15))
        restartb = DirectButton(text=("RESTART", "RESTART", "RESTART",
                                      "disabled"),
                                scale=0.15,
                                command=restart,
                                pos=(0, 0, -0.35))
        end = DirectButton(text=("QUIT", "QUIT", "QUIT", "disabled"),
                           scale=0.15,
                           command=quitgame,
                           pos=(0, 0, -0.55))
        if self.currlevel == self.maxlevel:
            nextlevelb.destroy()

    def __init__(self):
        #music

        self.mySound.play()

        print 'I am being initialized'

        self.menuscreen()
        self.list = []
        self.turns = 0
        self.maxlevel = 3
        self.currlevel = 1
        self.a = [[0 for x in range(8)] for y in range(8)]

        #This code puts the standard title and instruction text on screen
        self.title = OnscreenText(text="Game of Life : Help in ending AIDS!",
                                  style=1,
                                  fg=(1, 1, 1, 1),
                                  pos=(0, -0.95),
                                  scale=.07)
        self.escapeEvent = OnscreenText(text="ESC: Quit",
                                        style=1,
                                        fg=(1, 1, 1, 1),
                                        pos=(-1.3, 0.95),
                                        align=TextNode.ALeft,
                                        scale=.05)
        ##    self.mouse1Event = OnscreenText(
        ##      text="Left-click and drag: Pick up virus and drag it to a new bloodcell",
        ##      style=1, fg=(1,1,1,1), pos=(-1.3, 0.90),
        ##      align=TextNode.ALeft, scale = .05)
        ##

        self.accept('escape', sys.exit)  #Escape quits

        base.disableMouse()  #Disble mouse camera control
        camera.setPosHpr(0, -13.75, 6, 0, -25, 0)  #Set the camera
        self.setupLights()  #Setup default lighting

        #Since we are using collision detection to do picking, we set it up like
        #any other collision detection system with a traverser and a handler
        self.picker = CollisionTraverser()  #Make a traverser
        self.pq = CollisionHandlerQueue()  #Make a handler
        #Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        #Attach that node to the camera since the ray will need to be positioned
        #relative to it
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        #Everything to be picked will use bit 1. This way if we were doing other
        #collision we could seperate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  #Make our ray
        self.pickerNode.addSolid(self.pickerRay)  #Add it to the collision node
        #Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)
        #self.picker.showCollisions(render)

        #We will attach all of the squares to their own root. This way we can do the
        #collision pass just on the sqaures and save the time of checking the rest
        #of the scene
        self.squareRoot = render.attachNewNode("squareRoot")

        #For each square
        self.squares = [None for i in range(64)]
        self.pieces = [None for i in range(64)]

        for i in range(64):
            #Load, parent, color, and position the model (a single square polygon)
            self.squares[i] = loader.loadModel("models/square")
            self.squares[i].reparentTo(self.squareRoot)
            self.squares[i].setPos(SquarePos1(i))
            self.squares[i].setColor(SquareColor(i))
            #Set the model itself to be collideable with the ray. If this model was
            #any more complex than a single polygon, you should set up a collision
            #sphere around it instead. But for single polygons this works fine.
            self.squares[i].find("**/polygon").node().setIntoCollideMask(
                BitMask32.bit(1))
            #Set a tag on the square's node so we can look up what square this is
            #later during the collision pass
            self.squares[i].find("**/polygon").node().setTag('square', str(i))

            #We will use this variable as a pointer to whatever piece is currently
            #in this square

        self.initializer(self.currlevel)

        #This will represent the index of the currently highlited square
        self.hiSq = False
        #This wil represent the index of the square where currently dragged piece
        #was grabbed from
        self.dragging = False

        #Start the task that handles the picking
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
        #self.trial = taskMgr.add(self.trial,'trial')
        self.accept("mouse1", self.grabPiece)  #left-click grabs a piece
        self.accept("mouse1-up", self.releasePiece)  #releasing places it

    #This function swaps the positions of two pieces
    def swapPieces(self, fr, to):
        temp = self.pieces[fr]
        self.pieces[fr] = self.pieces[to]
        self.pieces[to] = temp
        if self.pieces[fr]:
            print 'imma swapping'
            self.pieces[fr].square = fr
            print fr
            print SquarePos(fr)
            try:
                self.pieces[fr].obj.setPos(SquarePos(fr))
            except:
                pass
            print 'done'
        if self.pieces[to]:
            self.pieces[to].square = to
            try:
                self.pieces[to].obj.setPos(SquarePos(to))
            except:
                pass

    def trial(self):
        self.turns = self.turns + 1
        try:
            self.reference.destroy()
        except:
            pass
        self.reference = OnscreenText(text='''
Reference:
virus is surrounded by more than 3 viruses, it dies
virus is surrounded by less than 2 viruses, it dies
If dead empty cell, is surrounded by exactly 3 viruses, a new virus is spawned.
''',
                                      style=1,
                                      fg=(1, 1, 1, 1),
                                      pos=(-1, 0.95),
                                      align=TextNode.ALeft,
                                      scale=.05)

        self.showscore()
        a = self.a
        while True:
            for i in self.list:
                #insert deletion code
                print 'imma deleting the sq : ' + str(i)
                self.pieces[i].obj.delete()

                self.squares[i].setColor(SquareColor(i))
            count = 0
            a = [[([[
                sum(b[y1][x1]
                    for b in [[[(
                        (-1 < x2 + dx < len(a[0])) and
                        (-1 < y2 + dy < len(a))) and a[y2 + dy][x2 + dx] or 0
                                for x2 in range(len(a[0]))]
                               for y2 in range(len(a))]
                              for (dx, dy) in [(dx, dy) for dx in [-1, 0, 1]
                                               for dy in [-1, 0, 1] if
                                               (dy != 0 or dx != 0)]])
                for x1 in range(len(a[0]))
            ] for y1 in range(len(a))][y][x] == 3 or ([[
                sum(c[y3][x3]
                    for c in [[[(
                        (-1 < x4 + dx < len(a[0])) and
                        (-1 < y4 + dy < len(a))) and a[y4 + dy][x4 + dx] or 0
                                for x4 in range(len(a[0]))]
                               for y4 in range(len(a))]
                              for (dx, dy) in [(dx, dy) for dx in [-1, 0, 1]
                                               for dy in [-1, 0, 1] if
                                               (dy != 0 or dx != 0)]])
                for x3 in range(len(a[0]))
            ] for y3 in range(len(a))][y][x] == 2 and a[y][x] == 1)) and 1 or 0
                  for x in range(len(a[0]))] for y in range(len(a))]
            lis = []
            #insert a random virus at a probability of 1/5
            diceroll = random.randint(0, 5)
            if diceroll == 2:

                self.random_vgen()
            for element in reversed(a):

                for ele in element:
                    #print 'cheking element is 1 : ' + str(ele)
                    if ele == 1:
                        lis.append(count)
                    count = count + 1
            print lis
            self.list = lis

            self.a = a
            print self.list

            for i in self.list:
                self.pieces[i] = Monster(i, WHITE)
                #self.squares[i].setColor(HIGHLIGHT)
            print 'leaving trial'
            if len(self.list) == 0:
                self.endscreen()
            break

        return

    def mouseTask(self, task):
        #This task deals with the highlighting and dragging based on the mouse

        #First, clear the current highlight
        if self.hiSq is not False:
            self.squares[self.hiSq].setColor(SquareColor(self.hiSq))
            self.hiSq = False

        #Check to see if we can access the mouse. We need it to do anything else
        if base.mouseWatcherNode.hasMouse():
            #get the mouse position
            mpos = base.mouseWatcherNode.getMouse()

            #Set the position of the ray based on the mouse position
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())

            #If we are dragging something, set the position of the object
            #to be at the appropriate point over the plane of the board
            if self.dragging is not False:
                #Gets the point described by pickerRay.getOrigin(), which is relative to
                #camera, relative instead to render
                nearPoint = render.getRelativePoint(camera,
                                                    self.pickerRay.getOrigin())
                #Same thing with the direction of the ray
                nearVec = render.getRelativeVector(
                    camera, self.pickerRay.getDirection())
                try:
                    self.pieces[self.dragging].obj.setPos(
                        PointAtZ(.5, nearPoint, nearVec))
                except:
                    pass
            #Do the actual collision pass (Do it only on the squares for
            #efficiency purposes)
            self.picker.traverse(self.squareRoot)
            if self.pq.getNumEntries() > 0:
                #if we have hit something, sort the hits so that the closest
                #is first, and highlight that node
                self.pq.sortEntries()
                i = int(self.pq.getEntry(0).getIntoNode().getTag('square'))
                #Set the highlight on the picked square
                self.squares[i].setColor(HIGHLIGHT)
                self.hiSq = i
                #print 'selected is ' + str(i)

        return Task.cont

    def grabPiece(self):
        #If a square is highlighted and it has a piece, set it to dragging mode
        if (self.hiSq is not False and self.pieces[self.hiSq]):
            self.dragging = self.hiSq
            self.hiSq = False

    def releasePiece(self):
        #Letting go of a piece. If we are not on a square, return it to its original
        #position. Otherwise, swap it with the piece in the new square
        if self.dragging is not False:  #Make sure we really are dragging something
            #We have let go of the piece, but we are not on a square
            if self.hiSq is False:
                try:
                    self.pieces[self.dragging].obj.setPos(
                        SquarePos(self.dragging))
                except:
                    pass
            else:
                #Otherwise, swap the pieces
                self.swapPieces(self.dragging, self.hiSq)
                #self.draggin is the from
                print self.list
                print 'you picked this, so Imma deleting this ' + str(
                    self.dragging)
                #deletion of i after picking it up.
                try:
                    self.list.remove(self.dragging)
                except:
                    pass
                temp2 = []
                temp2 = SquarePosTuple(self.dragging)
                self.a[temp2[0]][temp2[1]] = 0

                i = self.hiSq
                print self.list
                print 'highlighted sq is ' + str(i)
                templis = []
                templis = SquarePosTuple(i)
                print templis
                self.list.append(i)
                print self.list
                print templis
                self.a[templis[0]][templis[1]] = 1

                for line in self.a:
                    print line
                self.trial()

        #We are no longer dragging anything
        self.dragging = False

    def setupLights(self):  #This function sets up some default lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.8, .8, .8, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0, 45, -45))
        directionalLight.setColor(Vec4(0.2, 0.2, 0.2, 1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(ambientLight))
예제 #53
0
파일: Ralph.py 프로젝트: jaimodha/MMOG
class World(DirectObject):

    def __init__(self):
        #create Queue to hold the incoming chat
        #request the heartbeat so that the caht interface is being refreshed in order to get the message from other player
        
        self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0, "charge":0}
        base.win.setClearColor(Vec4(0,0,0,1))

        self.cManager = ConnectionManager()
        self.cManager.startConnection()
        #------------------------------
        #Chat
        Chat(self.cManager)
        
        
        #send dummy login info of the particular client
        #send first chat info 
        #---------------------------------------
        self.userName = username
        dummy_login ={'user_id' : self.userName, 'factionId': faction, 'password': '******'}
        self.cManager.sendRequest(Constants.RAND_STRING, dummy_login)
        
        
        chat = { 'userName' : self.userName,     #username
                 'message'    : '-------Login------' }
        self.cManager.sendRequest(Constants.CMSG_CHAT, chat)

        #--------------------------------------
        #self.minimap = OnscreenImage(image="images/minimap.png", scale=(0.2,1,0.2), pos=(-1.1,0,0.8))

        #frame = DirectFrame(text="Resource Bar", scale=0.001)

        resource_bar = DirectWaitBar(text="",
            value=35, range=100, pos=(0,0,0.9), barColor=(255,255,0,1),
            frameSize=(-0.3,0.3,0,0.03))
        cp_bar = DirectWaitBar(text="",
            value=70, range=100, pos=(1.0,0,0.9), barColor=(0,0,255,1),
            frameSize=(-0.3,0.3,0,0.03), frameColor=(255,0,0,1))

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.  

        

        self.environ = loader.loadModel("models/world")      
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)
        
        # Create the main character, Ralph

        ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor("models/ralph",
                                 {"run":"models/ralph-run",
                                  "walk":"models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos)

        nameplate = TextNode('textNode username_' + str(self.userName))
        nameplate.setText(self.userName)
        npNodePath = self.ralph.attachNewNode(nameplate)
        npNodePath.setScale(0.8)
        npNodePath.setBillboardPointEye()
        #npNodePath.setPos(1.0,0,6.0)
        npNodePath.setZ(6.5)

        bar = DirectWaitBar(value=100, scale=1.0)
        bar.setColor(255,0,0)
        #bar.setBarRelief()
        bar.setZ(6.0)
        bar.setBillboardPointEye()
        bar.reparentTo(self.ralph)

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("a", self.setKey, ["cam-left",1])
        self.accept("s", self.setKey, ["cam-right",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("a-up", self.setKey, ["cam-left",0])
        self.accept("s-up", self.setKey, ["cam-right",0])
        self.accept("c", self.setKey, ["charge",1])
        self.accept("c-up", self.setKey, ["charge",0])

        taskMgr.add(self.move,"moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera
        
        base.disableMouse()
        base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,2)
        
        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above ralph's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.

        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0,0,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()
        #self.camGroundColNp.show()
       
        # Uncomment this line to show a visual representation of the 
        # collisions occuring
        #self.cTrav.showCollisions(render)
        
        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))
    
 

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

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

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        base.camera.lookAt(self.ralph)
        if (self.keyMap["cam-left"]!=0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["cam-right"]!=0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())

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

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if (self.keyMap["left"]!=0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())
        if (self.keyMap["charge"]!=0):
            self.ralph.setY(self.ralph, -250 * globalClock.getDt())
            #ribbon = Ribbon(self.ralph, Vec4(1,1,1,1), 3, 10, 0.3)
            #ribbon.getRoot().setZ(2.0)

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"]!=0) or (self.keyMap["charge"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk",5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec*(5-camdist))
            camdist = 5.0

        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.
        
        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.camera.setZ(self.ralph.getZ() + 2.0)
            
        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        
        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        return task.cont
예제 #54
0
class Grabber(object):
    def __init__( self, levitNP):
        """ A widget to position, rotate, and scale Panda 3D Models and Actors
            * handleM1 decides what to do with a mouse1 click
            -- object selection by calling handleSelection when the grabModel is inactive (hidden)
            -- object manipulation by calling handleManipulationSetup (sets the stage for and launches the dragTask)

            isHidden() when nothing is selected
            isDragging means not running collision checks for selection setup and LMB is pressed

            call handleM1 from another class to push control up
            in the program hierarchy (remove inner class calls)
        """
        # TODO remove selection functionality from grabber and put it in a selector class
        self.levitorNP = levitNP  # TODO remove this and use barebonesNP
        self.selected = None
        self.initialize()

    def initialize(self):
        """Reset everything except LevitorNP and selected, also called inside __init__"""
        self.notify = DirectNotify().newCategory('grabberErr')
        self.currPlaneColNorm = Vec3(0.0)
        self.isCameraControlOn = False
        self.isDragging = False
        self.isMultiselect = False
        self.grabScaleFactor = .075
        self.currTransformDir = Point3(0.0)
        self.interFrameMousePosition = Point3(0.0)
        self.init3DemVal = Point3(0.0)
        # initCommVal holds the value before a command operation has taken place
        self.initialCommandTrgVal = None
        # To load the grabber model, this climbs up the absolute path to /barebones/ to gain access to the model folder
        self.grabModelNP = loader.loadModel(Filename.fromOsSpecific(
                                            ntpath.split( ntpath.split(inspect.stack()[0][1])[0] )[0])
                                            + '/EditorModels/widget')
        self.grabModelNP.setPos(0.0, 0.0, 0.0)
        self.grabModelNP.setBin("fixed", 40)
        self.grabModelNP.setDepthTest(False)
        self.grabModelNP.setDepthWrite(False)
        self.transformOpEnum = Enum('rot, scale, trans')
        self.currTransformOperation = None
        # TODO For readability, use this enum in the nested if/else as was the original intent.
        self.grabInd = Enum('xRot, yRot, zRot, xScaler, yScaler, zScaler, xTrans, yTrans, zTrans, xyTrans, xzTrans, zyTrans, grabCore')
        grbrNodLst = [self.grabModelNP.find("**/XRotator;+h-s-i"),       # 0
                       self.grabModelNP.find("**/YRotator;+h-s-i"),      # 1
                       self.grabModelNP.find("**/ZRotator;+h-s-i"),      # 2 end rotate
                       self.grabModelNP.find("**/XScaler;+h-s-i"),       # 3
                       self.grabModelNP.find("**/YScaler;+h-s-i"),       # 4
                       self.grabModelNP.find("**/ZScaler;+h-s-i"),       # 5 end scale
                       self.grabModelNP.find("**/XTranslator;+h-s-i"),   # 6
                       self.grabModelNP.find("**/YTranslator;+h-s-i"),   # 7
                       self.grabModelNP.find("**/ZTranslator;+h-s-i"),   # 8 end translate / end single dir operations
                       self.grabModelNP.find("**/XYTranslator;+h-s-i"),  # 9
                       self.grabModelNP.find("**/XZTranslator;+h-s-i"),  # 10
                       self.grabModelNP.find("**/ZYTranslator;+h-s-i"),  # 11 end bi-directional operations
                       self.grabModelNP.find("**/WidgetCore;+h-s-i")]    # 12
        #Mat4.yToZUpMat()  # change coordinate to z up
        grbrNodLst[12].getParent().setHprScale(0, 0, 0, 1, 1, -1)
        self.grabModelNP.setPythonTag('grabberRoot', grbrNodLst)
        self.grabModelNP.reparentTo(BBGlobalVars.bareBonesObj.levitorNP)
        self.grabModelNP.hide()
        #self.grabIntoBitMask = COLLISIONMASKS
        self.grabModelNP.setCollideMask(COLLISIONMASKS['default'])
        self.grabModelNP.setPythonTag('grabber', self)

        ##############################################################################
        # This whole section is the basics for setting up mouse selection
        # --The mouse events are added in the events section (next)

        # Create the collision node for the picker ray to add traverser as a 'from' collider
        self.grabberColNode = CollisionNode('grabberMouseRay')
        # Set the collision bitmask
        # TODO: define collision bitmask (let user define thiers? likely not)
        self.defaultBitMask = GeomNode.getDefaultCollideMask()
        self.grabberColNode.setFromCollideMask(self.defaultBitMask)
        self.grabberRayColNP = camera.attachNewNode(self.grabberColNode)
        # Create the grabberRay and add it to the picker CollisionNode
        self.grabberRay = CollisionRay(0.0, 0.0, 0.0,
                                       0.0, 1.0, 0.0)
        self.grabberRayNP = self.grabberColNode.addSolid(self.grabberRay)
        # create a collision queue for the traverser
        self.colHandlerQueue = CollisionHandlerQueue()
        # Create collision traverser
        self.colTraverser = CollisionTraverser('grabberTraverser')
        # Set the collision traverser's 'fromObj' and handler
        # e.g. trav.addCollider( fromObj, handler )
        self.colTraverser.addCollider(self.grabberRayColNP, self.colHandlerQueue)


        ############################################################
        # setup event handling with the messenger
        # URGENT remove all of this messenger code throughout Grabber, especially the camera control
        # disable the mouse when the ~ is pressed (w/o shift)
        self.disableCamera()                            # disable camera control by the mouse
        messenger.accept('`', self, self.enableCamera)  # enable camera control when the ~ key is pressed w/o shift
        messenger.accept('`-up', self, self.disableCamera)  # disable camera control when the ~ key is released

        # handle mouse selection/deselection & manipulating the scene
        messenger.accept('mouse1', self, self.handleM1, persistent=1)  # deselect in event handler

        taskMgr.add(self.scaleGrabber, 'scaleGrabber')
        # ////////////////////////////////////////////////////////////////////
        # comment out: good for debug info
        #taskMgr.add(self.watchMouseColl, name='grabberDebug')
        #this is only good for seeing types and hierarchy
        #self.grabModelNP.ls()
        #render.ls()
        # self.frames = 0  #remove
        # self.axis = loader.loadModel("zup-axis")
        # self.axis.reparentTo(self.grabModelNP)
        # self.axis.setScale(.15)
        # self.axis.setPos(0.0)
        # self.grabModelNP.append( 'newAttrib', self)
        # setattr( self.grabModelNP, 'newAttrib', self)


    def prepareForPickle(self):
        self.colTraverser = None     # Traversers are not picklable
        self.defaultBitMask = None   # BitMasks "..."
        # self.grabIntoBitMask = None  # "..."
        self.colHandlerQueue = None  # CollisonHandlerQueue "..."
        self.grabModelNP.removeNode()
        self.grabModelNP = None
        taskMgr.remove('scaleGrabber')


    def recoverFromPickle(self):
        self.initialize()
        if self.selected is not None:
            self.grabModelNP.setPos(render, self.selected.getPos(render))
            self.grabModelNP.show()
        print "grabber sel ", self.selected, " isHidden() ", self.grabModelNP.isHidden(), '\n'
        taskMgr.add(self.scaleGrabber, 'scaleGrabber')

    #### May use to gain control over pickling.
    # def __repr__(self): # for pickling purposes
    #     if self.colTraverser:
    #         self.colTraverser = None
    #
    #     dictrepr = dict.__repr__(self.__dict__)
    #     dictrepr = '%r(%r)' % (type(self).__name__, dictrepr)
    #     print dictrepr  # REMOVE
    #     return dictrepr


    def watchMouseColl(self, task):
        """ This exists for debugging purposes to perpetually watch mouse collisions.
        """
        # TODO make this highlight objects under the mouse for predictable object selection/grabber operations
        self.colTraverser.showCollisions(render)
        if base.mouseWatcherNode.hasMouse() and False == self.isCameraControlOn:
            # This gives the screen coordinates of the mouse.
            mPos = base.mouseWatcherNode.getMouse()
            # This makes the ray's origin the camera and makes the ray point
            # to the screen coordinates of the mouse.
            self.grabberRay.setFromLens(base.camNode, mPos.getX(), mPos.getY())
            # traverses the graph for collisions
            self.colTraverser.traverse(render)
        return task.cont


    def scaleGrabber(self, task):
        if self.grabModelNP.isHidden():
            return task.cont
        coreLst = self.grabModelNP.getPythonTag('grabberRoot')
        camPos = self.grabModelNP.getRelativePoint(self.grabModelNP, camera.getPos())

        if camPos.z >= 0:        # 1-4
            if camPos.x > 0.0 <= camPos.y:    # quad 1
                coreLst[12].getParent().setScale( 1, 1, -1)

            elif camPos.x < 0.0 <= camPos.y:  # quad 2
                coreLst[12].getParent().setScale( -1, 1, -1)

            elif camPos.x < 0.0 >= camPos.y:  # quad 3
                coreLst[12].getParent().setScale( -1, -1, -1)

            elif camPos.x > 0.0 >= camPos.y:  # quad 4
                coreLst[12].getParent().setScale( 1, -1, -1)

            else:
                self.notify.warning("if-else default, scaleGrabber cam.z > 0")

        else:      # 5-8
            if camPos.x > 0.0 <= camPos.y:    # quad 5
                coreLst[12].getParent().setScale( 1, 1, 1)

            elif camPos.x < 0.0 <= camPos.y:  # quad 6
                coreLst[12].getParent().setScale( -1, 1, 1)

            elif camPos.x < 0.0 >= camPos.y:  # quad 7
                coreLst[12].getParent().setScale( -1, -1, 1)

            elif camPos.x > 0.0 >= camPos.y:  # quad 8
                coreLst[12].getParent().setScale( 1, -1, 1)

            else:
                self.notify.warning("if-else default, scaleGrabber cam.z z < 0")


        distToCam = (camera.getPos() - render.getRelativePoint(BBGlobalVars.currCoordSysNP, self.grabModelNP.getPos())).length()
        self.grabModelNP.setScale(self.grabScaleFactor * distToCam,
                                  self.grabScaleFactor * distToCam,
                                  self.grabScaleFactor * distToCam)
        # keep the position identical to the selection
        # for when outside objects like undo/redo move selected
        self.grabModelNP.setPos(render, self.selected.getPos(render))
        return task.cont

    # TODO find a way to move camera control to a proper camera handler, perhaps move these to a global
    def enableCamera(self):
        self.isCameraControlOn = True
        PanditorEnableMouseFunc()

    def disableCamera(self):
        self.isCameraControlOn = False
        PanditorDisableMouseFunc()


    def handleM3(self):
        """Deselect the selected object."""
        if not self.grabModelNP.isHidden() and not self.isCameraControlOn:
            # if the grab model is in the scene and the camera is not in control
            if base.mouseWatcherNode.hasMouse() and not self.isDragging:
                # we're ignoring accidental mouse3 clicks while dragging here with not isDragging
                self.selected = None              # empty the selected, will be turned back on once something's selected
                messenger.ignore('mouse3', self)  # turn the deselect event off
                self.grabModelNP.hide()           # hide the grab model and set it back to render's pos
                self.grabModelNP.setPos(0.0)


    def handleM1Up(self):
        """Stop dragging the selected object."""
        taskMgr.remove('mouse1Dragging')
        self.isDragging = False
        self.currTransformOperation = None  # NOTE other references have been added, but no other object references them
        # record the mouse1 operation
        BBGlobalVars.undoHandler.record(self.selected, CommandUndo([self.initialCommandTrgVal],
                                                                    self.selected.setMat, self.selected.getMat(render)))
        messenger.ignore('mouse1-up', self)


    def handleM1(self):
        """Decides how to handle a mouse1 click."""
        if self.isCameraControlOn:
            return

        if base.mouseWatcherNode.hasMouse():
            # give the grabber first chance
            if self.grabModelNP.isHidden():
                # no collisions w/ grabber or nothing selected
                # handle selection with scene objects
                self.handleSelection()

            elif not self.isDragging:
                # The grabber is in place but not dragging. Get ready to drag.
                self.handleManipulationSetup()  # it'll call self.handleSelection() if no collision w/ grabber
                # TODO (if warranted) make self.handleManipulationSetup() return false if no col w/ grabber, call selection here instead


    def handleManipulationSetup(self):
        """Sets up all the attributes needed for the mouse dragging task."""
        # This makes the ray's origin the camera and makes the ray point
        # to the screen coordinates of the mouse.
        if self.isDragging:
            return
        camVec = self.grabModelNP.getRelativeVector(self.grabModelNP, camera.getPos())
        mPos = base.mouseWatcherNode.getMouse()
        self.grabberRay.setFromLens(base.camNode, mPos.getX(), mPos.getY())
        self.colTraverser.traverse(self.grabModelNP)  # look for collisions on the grabber

        if not self.isCameraControlOn and self.colHandlerQueue.getNumEntries() > 0 and not self.grabModelNP.isHidden():
            # see if collided with the grabber if not handle re or multi selection
            self.colHandlerQueue.sortEntries()
            grabberObj = self.colHandlerQueue.getEntry(0).getIntoNodePath()
            grabberLst = self.grabModelNP.getPythonTag('grabberRoot')  # see __init__

            # the index gives the operations rot < 3 scale < 6 trans < 9 trans2D < 12
            # mod index gives axis 0 == x, 1 == y, 2 == z
            ind = -1
            for i in range(0, 13):
                if grabberObj == grabberLst[i]:
                    ind = i
                    grabberObj = grabberLst[i]
            # ensure we are not picking ourselves, ahem, the grabber
            assert(not self.grabModelNP.isAncestorOf(self.selected))
            mPos3D = Point3(0.0)
            xVec = Vec3(1, 0, 0)
            yVec = Vec3(0, 1, 0)
            zVec = Vec3(0, 0, 1)
            # TODO: ??? break this up into translate rotate and scale function to make it readable
            if -1 < ind < 3:             # rotate
                if ind % 3 == 0:    # x
                    self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.rot,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))
                elif ind % 3 == 1:  # y
                    self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.rot,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))
                else:               # z
                    self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.rot,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))

            elif ind < 6:                 # scale
                if ind % 3 == 0:    # x
                    self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.scale,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))
                elif ind % 3 == 1:  # y
                    # self.currTransformDir = Point3( 0.0, 1.0, 0.0)
                    self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.scale,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))
                else:               # z
                    # self.currTransformDir = Point3( 0.0, 0.0, 1.0)
                    self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.scale,
                                             Point3(mPos.getX(), mPos.getY(), 0.0))

            elif ind < 9:                 # translate
                if ind % 3 == 0:    # x
                    # if the camera's too flat to the collision plane bad things happen
                    if camVec.angleDeg( zVec) < 89.0 and self.getMousePlaneIntersect(mPos3D, zVec):
                        self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.trans, mPos3D, zVec)

                    elif self.getMousePlaneIntersect(mPos3D, yVec):
                        self.initializeManipVars(Point3(1.0, 0.0, 0.0), self.transformOpEnum.trans, mPos3D, yVec)

                elif ind % 3 == 1:  # y
                    if camVec.angleDeg( zVec) < 89.0 and self.getMousePlaneIntersect(mPos3D, zVec):
                        self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.trans, mPos3D, zVec)

                    elif self.getMousePlaneIntersect(mPos3D, xVec):
                        self.initializeManipVars(Point3(0.0, 1.0, 0.0), self.transformOpEnum.trans, mPos3D, xVec)

                else:               # z
                    if camVec.angleDeg( yVec) < 89.0 and self.getMousePlaneIntersect(mPos3D, yVec):
                        self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.trans, mPos3D, yVec)

                    elif self.getMousePlaneIntersect(mPos3D, xVec):
                        self.initializeManipVars(Point3(0.0, 0.0, 1.0), self.transformOpEnum.trans, mPos3D, xVec)

            elif ind < 12:            # translate 2D
                if ind % 3 == 0:    # xy
                    if self.getMousePlaneIntersect(mPos3D, zVec):
                        self.initializeManipVars(Point3(1.0, 1.0, 0.0), self.transformOpEnum.trans, mPos3D, zVec)

                elif ind % 3 == 1:  # xz
                    if self.getMousePlaneIntersect(mPos3D, yVec):
                        self.initializeManipVars(Point3(1.0, 0.0, 1.0), self.transformOpEnum.trans, mPos3D, yVec)
                else:               # zy
                    if self.getMousePlaneIntersect(mPos3D, xVec):
                        self.initializeManipVars(Point3(0.0, 1.0, 1.0), self.transformOpEnum.trans, mPos3D, xVec)

            elif ind == 12:  # scale in three directions
                self.initializeManipVars(Point3(1.0, 1.0, 1.0), self.transformOpEnum.scale,
                                         Point3(mPos.getX(), mPos.getY(), 0.0))

            else:
                self.notify.warning("Grabber Err: no grabber collision when col entries > 0 AND grabber not hidden")

            # Save initial value for save/undo.
            # The end result of the operation is sent to the undo handler on mouse up event.
            if self.selected:
                self.initialCommandTrgVal = self.selected.getMat(render)
        else:
            # no collisions w/ grabber or nothing selected
            # handle reselection or multi-selection (not yet implemented) with other scene obj
            self.handleSelection()


    def handleSelection(self):
        if self.isDragging:
            return

        # First check that the mouse is not outside the screen.
        if base.mouseWatcherNode.hasMouse() and False == self.isCameraControlOn:

            self.grabberColNode.setFromCollideMask(self.defaultBitMask)
            # This gives the screen coordinates of the mouse.
            mPos = base.mouseWatcherNode.getMouse()

            # This makes the ray's origin the camera and makes the ray point
            # to the screen coordinates of the mouse.
            self.colHandlerQueue.clearEntries()
            self.grabberRay.setFromLens(base.camNode, mPos.getX(), mPos.getY())
            self.colTraverser.traverse(render)  # look for collisions

            if self.colHandlerQueue.getNumEntries() > 0:
                self.colHandlerQueue.sortEntries()
                grabbedObj = self.colHandlerQueue.getEntry(0).getIntoNodePath()
                if not grabbedObj.findNetTag('pickable').isEmpty():
                    grabbedObj = grabbedObj.findNetTag('pickable')
                    self.selected = grabbedObj
                    self.grabModelNP.setPos(render,
                                            grabbedObj.getPos(render).x,
                                            grabbedObj.getPos(render).y,
                                            grabbedObj.getPos(render).z)
                    self.grabModelNP.show()
                    messenger.accept('mouse3', self, self.handleM3)

    def handleDragging(self, task):
        """ Does the actual work of manipulating objects,
            once the needed attributes have been setup by handleManipulationSetup().
        """

        if not self.isDragging:
            return task.done
        mPos3D = Point3(0.0)
        #
        # This section handles the actual translating rotating or scale after it's been set up in mouse1SetupManip...()
        # ONLY one operation is preformed per frame
        if self.currTransformOperation == self.transformOpEnum.trans:
            # 1st translation, rotation's section is at next elif
            if self.getMousePlaneIntersect(mPos3D, self.currPlaneColNorm):

                # get the difference between the last mouse and this frames mouse
                selectedNewPos = mPos3D - self.interFrameMousePosition
                # store this frames mouse
                self.interFrameMousePosition = mPos3D
                # add the difference to the selected object's pos
                self.selected.setPos(render, self.selected.getPos(render).x + self.currTransformDir.x * selectedNewPos.x,
                                             self.selected.getPos(render).y + self.currTransformDir.y * selectedNewPos.y,
                                             self.selected.getPos(render).z + self.currTransformDir.z * selectedNewPos.z)

                self.grabModelNP.setPos(render, self.selected.getPos(render))

        elif self.currTransformOperation == self.transformOpEnum.rot:
            # 2nd rotation, followed finally by scaling
            # if operating on the z-axis, use the y (vertical screen coordinates otherwise use x (horizontal)
            mPos = base.mouseWatcherNode.getMouse()
            #rotMag = 0.0
            if self.currTransformDir == Vec3( 0.0, 0.0, 1.0):
                rotMag = (mPos.x - self.interFrameMousePosition.x) * 1000
            else:
                rotMag = (self.interFrameMousePosition.y - mPos.y) * 1000

            initPos = self.selected.getPos()
            initPar = self.selected.getParent()
            self.selected.wrtReparentTo(render)
            self.selected.setMat(self.selected.getMat() * Mat4.rotateMat(rotMag, self.currTransformDir))
            self.selected.wrtReparentTo(initPar)
            self.selected.setPos(initPos)

            self.interFrameMousePosition = Point3(mPos.x, mPos.y, 0.0)

        elif self.currTransformOperation == self.transformOpEnum.scale:
            # 3rd and final is scaling
            mPos = base.mouseWatcherNode.getMouse()
            # TODO: make dragging away from the object larger and to the object smaller (not simply left right up down)
            # td The problem with this MAY come if negative, mirrored, scaling is implemented.

            # if operating on the z-axis, use the y (vertical screen coordinates otherwise use x (horizontal)
            if self.currTransformDir == Point3( 0.0, 0.0, 1.0):
                sclMag = (mPos.y - self.interFrameMousePosition.y) * 5.5
            elif self.currTransformDir == Point3( 0.0, 1.0, 0.0):
                sclMag = (mPos.x - self.interFrameMousePosition.x) * 5.5
            else:
                sclMag = (self.interFrameMousePosition.x - mPos.x) * 5.5

            # This is the line that prevents scaling past the origin. Flipping the faces doesn't seem to work.
            if -0.0001 < sclMag < 0.0001:
                sclMag = 0.000001

            # create a dummy node to parent to and position such that applying scale to it will scale selected properly
            dummy = self.levitorNP.attachNewNode('dummy')
            initScl = dummy.getScale()
            # Don't forget the parent. Selected needs put back in place
            initPar = self.selected.getParent()
            initPos = self.selected.getPos()
            self.selected.wrtReparentTo(dummy)

            dummy.setScale(initScl.x + sclMag * self.currTransformDir.x,
                           initScl.y + sclMag * self.currTransformDir.y,
                           initScl.z + sclMag * self.currTransformDir.z)

            # reset selected's parent then destroy dummy
            self.selected.wrtReparentTo(initPar)
            self.selected.setPos(initPos)
            dummy.removeNode()
            dummy = None

            self.interFrameMousePosition = Point3( mPos.x, mPos.y, 0.0)
        else:
            self.notify.error("Err: Dragging with invalid curTransformOperation enum in handleDragging")

        return task.cont  # ended by handleM1Up(), the mouse1-up event handler


    def initializeManipVars(self, transformDir, transformOp, mPos3D, planeNormVec=None):
        self.currTransformDir = transformDir
        self.currPlaneColNorm = planeNormVec  # set the norm for the collision plane to be used in mouse1Dragging
        self.interFrameMousePosition = mPos3D
        self.currTransformOperation = transformOp
        self.isDragging = True
        taskMgr.add(self.handleDragging, 'mouse1Dragging')
        messenger.accept('mouse1-up', self, self.handleM1Up)


    def getMousePlaneIntersect(self, mPos3Dref, normVec):
        mPos = base.mouseWatcherNode.getMouse()
        plane = Plane(normVec, self.grabModelNP.getPos())
        nearPoint = Point3()
        farPoint = Point3()
        base.camLens.extrude(mPos, nearPoint, farPoint)
        if plane.intersectsLine(mPos3Dref,
            render.getRelativePoint(camera, nearPoint),
            render.getRelativePoint(camera, farPoint)):
            return True
        return False



    def destroy(self):
        raise NotImplementedError('Make sure messenger etc are cleared of refs and the model node is deleted')
        self.grabModelNP.clearPythonTag('grabberRoot')
        self.grabModelNP.clearPythonTag('grabber')
        self.grabModelNP = None
        messenger.ignoreAll(self)
예제 #55
0
파일: usuario.py 프로젝트: PlumpMath/vinerx
class Usuario(object):
    '''
    Usuario
    '''
    def __init__(self):
        self.habilitado = False

        self.estaMovendo = False
        self.estaRodando = False
        self.timeIniMover = 0
        self.timeIniRodar = 0
        self.keyMap = {
            TECLA_esquerda: EVENT_up,
            TECLA_direita: EVENT_up,
            TECLA_frente: EVENT_up,
            TECLA_traz: EVENT_up
        }

        self.login = None
        self.senha = None
        self.nick = None

        self.vida_real = None
        self.vida_total = None
        self.mana_real = None
        self.mana_total = None
        self.forca = None
        self.velocidade = None
        self.velocidade_atack = None

        self.key = None
        self.addr = None
        self.login = None

        pandaFileModelo = get_path_modelo("ralph")

        self.__modelo = Actor(pandaFileModelo)
        self.__modelo.reparentTo(render)
        self.__modelo.setScale(SCALE_MODELOS)

        modeloStartPos = vinerWorld.mapa.modelo.find("**/start_point").getPos()
        self.set_pos(modeloStartPos)

        self.__setup_collision()

    def get_x(self):
        return self.__modelo.getX()

    def get_y(self):
        return self.__modelo.getY()

    def get_z(self):
        return self.__modelo.getZ()

    def get_h(self):
        return self.__modelo.getH()

    def get_pos(self):
        return self.__modelo.getPos()

    def set_x(self, x):
        self.__modelo.setX(x)

    def set_y(self, y):
        self.__modelo.setY(y)

    def set_z(self, z):
        self.__modelo.setZ(z)

    def set_h(self, h):
        self.__modelo.setH(h)

    def set_pos(self, pos):
        self.__modelo.setPos(pos)

    def get_dados(self):

        return [
            self.key,
            self.nick,
            self.vida_real,
            self.vida_total,
            self.mana_real,
            self.mana_total,
            self.forca,
            self.velocidade,
            self.velocidade_atack,
            self.get_x(),
            self.get_y(),
            self.get_z(),
            self.get_h(),
        ]

    def stop_task_movimentacao(self):
        taskMgr.remove(self.key)

    def inicia_task_movimentacao(self):
        if self.key != "":
            taskMgr.add(self.__task_movimentacao, self.key, sort=1)

    def __setup_collision(self):
        #Colisao
        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 5)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.__modelo.attachNewNode(
            self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()

        base.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)
        #Colisao

    def __task_movimentacao(self, task):
        dt = globalClock.getDt()
        startpos = self.__modelo.getPos()

        #rodar usuario
        if self.keyMap[TECLA_esquerda] == EVENT_down and self.keyMap[
                TECLA_direita] == EVENT_up:

            if time.time() < self.timeIniRodar + 4:
                self.estaRodando = True

                self.__modelo.setH(self.__modelo, ((self.velocidade * 5) * dt))
            else:
                h = self.get_h()
                vinerOnline.envia_pacote_todos(
                    1, ACAO_CLIENT_rodar,
                    [self.key, TECLA_esquerda, EVENT_up, h])

                self.estaRodando = False
                self.keyMap[TECLA_esquerda] = EVENT_up

        elif self.keyMap[TECLA_direita] == EVENT_down and self.keyMap[
                TECLA_esquerda] == EVENT_up:

            if time.time() < self.timeIniRodar + 4:
                self.estaRodando = True

                self.__modelo.setH(self.__modelo,
                                   ((self.velocidade * 5) * dt) * -1)
            else:
                h = self.get_h()
                vinerOnline.envia_pacote_todos(
                    1, ACAO_CLIENT_rodar,
                    [self.key, TECLA_direita, EVENT_up, h])

                self.estaRodando = False
                self.keyMap[TECLA_direita] = EVENT_up
        elif self.estaRodando:
            self.estaRodando = False
        #rodar usuario

        #mover usuario
        if self.keyMap[TECLA_frente] == EVENT_down and self.keyMap[
                TECLA_traz] == EVENT_up:

            if time.time() < self.timeIniMover + 4:
                self.estaMovendo = True

                self.__modelo.setY(self.__modelo,
                                   ((self.velocidade * 2) * dt) * -1)
            else:
                x = self.get_x()
                y = self.get_y()
                z = self.get_z()
                vinerOnline.envia_pacote_todos(
                    1, ACAO_CLIENT_mover,
                    [self.key, TECLA_frente, EVENT_up, x, y, z])

                self.estaMovendo = False
                self.keyMap[TECLA_frente] = EVENT_up

        elif self.keyMap[TECLA_traz] == EVENT_down and self.keyMap[
                TECLA_frente] == EVENT_up:

            if time.time() < self.timeIniMover + 4:
                self.estaMovendo = True

                self.__modelo.setY(self.__modelo, (self.velocidade * dt))
            else:
                x = self.get_x()
                y = self.get_y()
                z = self.get_z()
                vinerOnline.envia_pacote_todos(
                    1, ACAO_CLIENT_mover,
                    [self.key, TECLA_traz, EVENT_up, x, y, z])

                self.estaMovendo = False
                self.keyMap[TECLA_traz] = EVENT_up

        elif self.estaMovendo:
            self.estaMovendo = False
        #mover usuario

        #se esta moventdo trata colisao
        if self.estaMovendo:

            base.cTrav.traverse(render)

            if self.ralphGroundHandler.getNumEntries() == 1:
                entry = self.ralphGroundHandler.getEntry(0)
                if entry.getIntoNode().getName() == "terrain":
                    self.__modelo.setZ(entry.getSurfacePoint(render).getZ())
            else:
                self.__modelo.setPos(startpos)
        #se esta moventdo trata colisao

        return task.cont
class World(DirectObject):

    def __init__(self):
        
        self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0}
        base.win.setClearColor(Vec4(0,0,0,1))

        # Post the instructions

        self.title = addTitle("Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward")
        self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left")
        self.inst7 = addInstructions(0.65, "[S]: Rotate Camera Right")
        
        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.  

        self.environ = loader.loadModel("models/world")      
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)
        
        # Create the main character, Ralph
        ralphStartPos = self.environ.find("**/start_point").getPos()
        
        #self.addRalph(ralphStartPos)
       

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("a", self.setKey, ["cam-left",1])
        self.accept("s", self.setKey, ["cam-right",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("a-up", self.setKey, ["cam-left",0])
        self.accept("s-up", self.setKey, ["cam-right",0])

        taskMgr.add(self.move,"moveTask")

        # Game state variables
        self.isMoving = False

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

       

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()
        #self.camGroundColNp.show()
       
        # Uncomment this line to show a visual representation of the 
        # collisions occuring
        #self.cTrav.showCollisions(render)
        
        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))
        
        # Add some text
        '''
        bk_text = "This is a test"
        textObject = OnscreenText(text = bk_text, pos = (0.95,-0.35), 
        scale = 0.07,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=1)
        '''
    
    #MS: Adds a Roaming Ralph
    def addRalph(self, pos):
        ralphStartPos = pos
        self.ralph = Actor("models/ralph",
                                 {"run":"models/ralph-run",
                                  "walk":"models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos)
        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0,0,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)
        
    
    #Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value
    

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

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        base.camera.lookAt(self.ralph)
        if (self.keyMap["cam-left"]!=0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["cam-right"]!=0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())

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

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if (self.keyMap["left"]!=0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk",5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec*(5-camdist))
            camdist = 5.0

        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.
        
        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.camera.setZ(self.ralph.getZ() + 2.0)
            
        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.
        
        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        return task.cont
예제 #57
0
class World(DirectObject):

    def __init__(self):
        self.itemID = 0
        self.switchState = True
        self.iAktion = "E"
        self.altIPos = [0,0]
        self.switchCam = False
        self.kampf = Battle.Kampf()
        self.itemDa = False
        self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0}
        base.win.setClearColor(Vec4(0,0,0,1))

        self.environ = loader.loadModel("models/world")      
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)

 
        self.spieler = Players.Player(Actor("models/box.x"))
        self.spieler.actor.reparentTo(render)
        spielerStartPos = (-107.575, 26.6066, -0.490075)
        self.spieler.actor.setPos(spielerStartPos)
        self.textObjectSpieler = OnscreenText(text = self.spieler.name+":  "+str(self.spieler.energie)+"/"+str(self.spieler.maxenergie)+" HP", pos = (-0.90, -0.98), scale = 0.07, fg = (1,0,0,1))        

        # Erstellt Gegner
        
        self.gegnerStartPos = ([(-39.1143569946,25.1781406403,-0.136657714844),
                                (-102.375793457,-30.6321983337,0.0),
                                (-56.927986145, -34.6329650879, -0.16748046875),
                                (-79.6673126221,30.8231620789,2.89721679688),
                                (-4.37648868561,30.5158863068,2.18450927734),
                                (22.6527004242,4.99837779999,3.11364746094),
                                (-23.8257598877,-7.87773084641,1.36920166016),
                                (-80.6140823364,19.5769443512,4.70764160156),
                                (-75.0773696899,-15.2991075516,6.24676513672)
                                ])
        
        gegnerPos = random.choice(self.gegnerStartPos)
        self.gegnerErstellen(gegnerPos)
        self.textObjectGegner = OnscreenText(text = str(self.gegner.name)+": "+str(self.gegner.energie)+"/"+str(self.gegner.maxenergie)+" HP", pos = (0.90, -0.98), scale = 0.07, fg = (1,0,0,1))
        
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        self.item = None
        
        # Handling der Usereingaben für Bewegung

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("a", self.setKey, ["cam-left",1])
        self.accept("s", self.setKey, ["cam-right",1])
        self.accept("i", self.setKey, ["inventar",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("a-up", self.setKey, ["cam-left",0])
        self.accept("s-up", self.setKey, ["cam-right",0])

        self.accept("e", self.iAktionsHandler,["e"])
        self.accept("v", self.iAktionsHandler,["v"])
        self.accept("w", self.iAktionsHandler,["w"])
        
        taskMgr.add(self.move,"moveTask")
        taskMgr.add(self.erkenneKampf,"Kampferkennung")
        taskMgr.add(self.screentexts,"Screentexte")


        # Menü erstellen

        self.createMenu()
        
        # Kameraeinstellungen
        
        base.disableMouse()
        base.camera.setPos(self.spieler.actor.getX(),self.spieler.actor.getY()+10,2)
        
        self.collisionInit();
        
        self.setAI()
        
        # Licht
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

        # Hintergrund (Himmel)

        self.setupSkySphere()

    def iAktionsHandler(self,key):
        if key == "e":
            self.iAktion = "E"
        elif key == "w":
            self.iAktion = "W"
        elif key == "v":
            self.iAktion = "V"
            

    def collisionInit(self):
        # Kollisionserkennung, um auf dem Boden zu laufen. Der Collisionray
        # erkennt die Hoehe des Gelaendes und wenn ein Objekt da ist, wird 
        # die Bewegung als illegal gewertet.

        self.cTrav = CollisionTraverser()

        self.spielerGroundRay = CollisionRay()
        self.spielerGroundRay.setOrigin(0,0,1000)
        self.spielerGroundRay.setDirection(0,0,-1)
        self.spielerGroundCol = CollisionNode('spielerRay')
        self.spielerGroundCol.addSolid(self.spielerGroundRay)
        self.spielerGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.spielerGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.spielerGroundColNp = self.spieler.actor.attachNewNode(self.spielerGroundCol)
        self.spielerGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.spielerGroundColNp, self.spielerGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0,0,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        self.gegnerGroundRay = CollisionRay()
        self.gegnerGroundRay.setOrigin(0,0,1000)
        self.gegnerGroundRay.setDirection(0,0,-1)
        self.gegnerGroundCol = CollisionNode('gegnerRay')
        self.gegnerGroundCol.addSolid(self.gegnerGroundRay)
        self.gegnerGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.gegnerGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.gegnerGroundColNp = self.gegner.actor.attachNewNode(self.gegnerGroundCol)
        self.gegnerGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.gegnerGroundColNp, self.gegnerGroundHandler)


    def setupSkySphere(self):
        self.skysphere = loader.loadModel("models/LinearPinkSkySphere.bam")
        # Textur für den Himmel laden
        self.sky_tex = loader.loadTexture("Images/Sterne.jpg")
        # Himmel Textur konfigurieren
        self.skysphere.setTexture(self.sky_tex, 1)
	self.skysphere.setBin('background', 1) 
        self.skysphere.setDepthWrite(0) 
        self.skysphere.reparentTo(render)
        self.skysphere.setScale(40)
        taskMgr.add(self.skysphereTask, "SkySphere Task") 

    def skysphereTask(self, task): 
        self.skysphere.setPos(base.camera, 0, 0, 0) 
        return task.cont

    def createMenu(self):
        self.createFrame()
        itemListe = self.spieler.inventar.anzeigen(1)
        standardpos = [0.18, 0.98, 0.83]
        self.buttonListe = []
        beutelLabel = DirectLabel(text = itemListe[0][0], pos = (0.18, 0.98, 0.95), scale = 0.07, text_fg = (1,0,0,1), text_bg = (0, 50, 50, 1), textMayChange = 1)
        del itemListe [0][0]
        for zeile in range(4):
            for i in range(0,5):
                Button = DirectButton(text = itemListe [zeile] [i], pos = standardpos, scale = 0.07, text_fg = (1,0,0,1), text_bg = (0, 50, 50, 1), textMayChange = 1, extraArgs = [zeile,i], command = self.inventarAktion)
                self.buttonListe.append (Button)
                standardpos[0] += 0.25
            standardpos[0] = 0.18    
            standardpos[2] -= 0.15
            
    def createFrame(self):
        self.myFrame = DirectFrame(frameColor=(0, 50, 50, 0.5),
                      frameSize=(-1, 1, -.7, 1),
                      pos=(1, -1, 1))

    def inventarAktion(self,zeile,spalte):
        if self.iAktion == "E":
            self.spieler.inventar.entfernen(1,[zeile,spalte])
            self.myFrame.destroy()
            i = 0
            for item in self.buttonListe:
                    self.buttonListe [i].destroy()
                    i += 1
            del self.buttonListe[:]
            self.createMenu()  
        elif self.iAktion == "W":
            self.altIPos = [zeile,spalte]
        elif self.iAktion == "V":
            self.spieler.inventar.verschieben(1,1,self.altIPos,[zeile,spalte])
            self.myFrame.destroy()
            i = 0
            for item in self.buttonListe:
                    self.buttonListe [i].destroy()
                    i += 1
            del self.buttonListe[:]
            self.createMenu()        
        
        
    # Erkennt den Status der Eingabe
    def setKey(self, key, value):
        self.keyMap[key] = value

    def screentexts(self,task):
        self.textObjectSpieler.destroy()
        self.textObjectSpieler = OnscreenText(text = self.spieler.name+":  "+str(self.spieler.energie)+"/"+str(self.spieler.maxenergie)+" HP", pos = (-0.90, -0.98), scale = 0.07, fg = (1,0,0,1))
        self.textObjectGegner.destroy()
        if self.kampf.active == True:
            self.textObjectGegner = OnscreenText(text = str(self.gegner.name)+": "+str(self.gegner.energie)+"/"+str(self.gegner.maxenergie)+" HP", pos = (0.90, -0.98), scale = 0.07, fg = (1,0,0,1))
        else:
            self.textObjectGegner = OnscreenText(text = "Kein Gegner vorhanden", pos = (0.90, -0.98), scale = 0.07, fg = (1,0,0,1))
        return Task.cont

    def camera(self):
         # cam-left Key: Kamera nach links
        # cam-right Key: Kamera nach rechts
        base.camera.lookAt(self.spieler.actor)
        if (self.keyMap["cam-left"]!=0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["cam-right"]!=0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())

        # Wenn die Kamera zu weit weg ist, zoom heran.
        # Wenn die Kamera zu nah dran ist, zoom weg.

        camvec = self.spieler.actor.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec*(5-camdist))
            camdist = 5.0

        # Haelt die Kamera einen Schritt über dem Boden
        # oder zwei Schritte ueber dem Spieler, je nachdem, was groesser ist.
        
        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0)
        if (base.camera.getZ() < self.spieler.actor.getZ() + 2.0):
            base.camera.setZ(self.spieler.actor.getZ() + 2.0)
            
        # Die Kamera soll in die Richtung des Spielers gucken, aber auch
        # immer horizontal bleiben.
        
        self.floater.setPos(self.spieler.actor.getPos())
        self.floater.setZ(self.spieler.actor.getZ() + 2.0)
        base.camera.lookAt(self.floater)

    def collisions(self,startpos):
        
        # Überprüfen auf Itemkollision
        
        if self.item <> None:
            if (self.item.actor.getX() - self.spieler.actor.getX() < 1
            and self.item.actor.getY() - self.spieler.actor.getY() < 1
            and self.item.actor.getZ() - self.spieler.actor.getZ() <1
            and self.itemDa == True):
                self.itemDa = False
                self.item.actor.detachNode()
                self.spieler.inventar.einfuegen(self.item)
                self.myFrame.destroy()
                del self.buttonListe[:]
                self.createMenu()

         # Start der Kollisionserkennung

        self.cTrav.traverse(render)


        # Aendert die Z Koordinate des Spielers. Wenn er etwas trifft, bewegt
        # ihn entsprechend, wenn er nichts trifft, setzt die Koordinate 
        # auf den Stand des letzten Frames
        self.dummyMethode(self.spielerGroundHandler, self.spieler.actor,startpos)

    
    def move(self,task):

        self.camera();
        
        # Speichert die Startposition, damit der Spieler zurueckgesetzt
        # werden kann, sollte er irgendwo runterfallen

        startpos = self.spieler.actor.getPos()

        # Wenn einer der Move Keys gedrueckt wird, wird der Spieler
        # in die ensprechende Richtung bewegt

        if (self.keyMap["left"]!=0):
            self.spieler.actor.setH(self.spieler.actor.getH() + 150 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.spieler.actor.setH(self.spieler.actor.getH() - 150 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.spieler.actor.setY(self.spieler.actor, -12 * globalClock.getDt())

        self.collisions(startpos);

        return Task.cont

    def gegnermove(self):
 
        # Zeit seit dem letzten Frame. Benötigt fuer
        # framerateunabhaengige Bewegung.
        elapsed = globalClock.getDt()

        startpos = self.gegner.actor.getPos()
 
        # Aendert die Z Koordinate des Gegners. Wenn er etwas trifft, bewegt
        # ihn entsprechend, wenn er nichts trifft, setzt die Koordinate 
        # auf den Stand des letzten Frames
 
        self.cTrav.traverse(render)
        self.dummyMethode(self.gegnerGroundHandler, self.gegner.actor,startpos)
 
        self.gegner.actor.setP(0)
        if self.gegner.energie == 0:
            return Task.done
        else:
            return Task.cont

    def dummyMethode(self, handler, actor,startpos):
        entries = []
        for i in range(handler.getNumEntries()):
            entry = handler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            actor.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            actor.setPos(startpos)
	
	
	
    def setAI(self):
        # Erstellt die AI World
        self.AIworld = AIWorld(render)
 
        self.AIchar = AICharacter("gegner",self.gegner.actor, 100, 0.02, 1)
        self.AIworld.addAiChar(self.AIchar)
        self.AIbehaviors = self.AIchar.getAiBehaviors()
 
        self.AIbehaviors.wander(360, 0, 15, 1.0)
 
        #AI World update zum Tasknamager hinzufügen       
        taskMgr.add(self.AIUpdate,"AIUpdate")
 
 
    # Update der AI World   
    def AIUpdate(self,task):
        if self.kampf.active == False:
            self.AIworld.update()
            self.gegnermove()
 
        return Task.cont

    # Startet bei einem Abstand von 4 zwischen Spieler und Gegner einen Kampf
    def erkenneKampf(self,task):
        if (self.spieler.actor.getX() - self.gegner.actor.getX() < 4
        and self.spieler.actor.getX() - self.gegner.actor.getX() > -4
        and self.kampf.active == False):
            self.kampf.active = True
            self.startzeit = globalClock.getLongTime()
        if self.kampf.active == True:
            self.Kampf(self)
        if self.gegner.energie == 0:
            return Task.done
        else:
            return Task.cont

    def gegnerErstellen(self,pos):
        self.gegner = Monster.Goblin(Actor("models/box.x"))
        self.gegner.actor.reparentTo(render)
        self.gegner.actor.setPos(pos)
        self.gegnerAltPos = pos
        self.setAI()

    def gegnerTod(self):
        self.kampf.active = False
        itemPos = self.gegner.actor.getPos()
        self.gegner.actor.detachNode()
        self.item = Items.Axt()
        self.item.ID = self.itemID
        self.itemID += 1
        self.itemDa = True
        self.item.actor.setScale(0.3)
        self.item.actor.reparentTo(render)
        self.item.actor.setPos(itemPos)
        gegnerNeuPos = random.choice(self.gegnerStartPos)
        while gegnerNeuPos == self.gegnerAltPos:
            gegnerNeuPos = random.choice(self.gegnerStartPos)
        self.gegnerErstellen(gegnerNeuPos)

    # Lässt Spieler und Gegner nach bestimmter Zeit Aktionen ausführen. Bei Tod des
    # Gegners wird ein neuer Gegner sowie ein Item generiert
    def Kampf(self,task):
        if ((int(globalClock.getLongTime()) - int(self.startzeit)) % 5 == 0
        and self.kampf.active == True):
            erg = self.kampf.Kampf(self.spieler,self.gegner)
            self.spieler = erg[0]
            self.gegner = erg[1]
            self.startzeit -= 1
            if self.spieler.energie == 0:
                sys.exit
            elif self.gegner.energie == 0:
                self.gegnerTod();
        if self.startzeit <= 0:
            self.startzeit = globalClock.getLongTime()
예제 #58
0
파일: Ralph.py 프로젝트: jaimodha/MMOG
class World(DirectObject):
    def __init__(self):
        #create Queue to hold the incoming chat
        #request the heartbeat so that the caht interface is being refreshed in order to get the message from other player

        self.keyMap = {
            "left": 0,
            "right": 0,
            "forward": 0,
            "cam-left": 0,
            "cam-right": 0,
            "charge": 0
        }
        base.win.setClearColor(Vec4(0, 0, 0, 1))

        self.cManager = ConnectionManager()
        self.cManager.startConnection()
        #------------------------------
        #Chat
        Chat(self.cManager)

        #send dummy login info of the particular client
        #send first chat info
        #---------------------------------------
        self.userName = username
        dummy_login = {
            'user_id': self.userName,
            'factionId': faction,
            'password': '******'
        }
        self.cManager.sendRequest(Constants.RAND_STRING, dummy_login)

        chat = {
            'userName': self.userName,  #username
            'message': '-------Login------'
        }
        self.cManager.sendRequest(Constants.CMSG_CHAT, chat)

        #--------------------------------------
        #self.minimap = OnscreenImage(image="images/minimap.png", scale=(0.2,1,0.2), pos=(-1.1,0,0.8))

        #frame = DirectFrame(text="Resource Bar", scale=0.001)

        resource_bar = DirectWaitBar(text="",
                                     value=35,
                                     range=100,
                                     pos=(0, 0, 0.9),
                                     barColor=(255, 255, 0, 1),
                                     frameSize=(-0.3, 0.3, 0, 0.03))
        cp_bar = DirectWaitBar(text="",
                               value=70,
                               range=100,
                               pos=(1.0, 0, 0.9),
                               barColor=(0, 0, 255, 1),
                               frameSize=(-0.3, 0.3, 0, 0.03),
                               frameColor=(255, 0, 0, 1))

        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.

        self.environ = loader.loadModel("models/world")
        self.environ.reparentTo(render)
        self.environ.setPos(0, 0, 0)

        # Create the main character, Ralph

        ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor("models/ralph", {
            "run": "models/ralph-run",
            "walk": "models/ralph-walk"
        })
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos)

        nameplate = TextNode('textNode username_' + str(self.userName))
        nameplate.setText(self.userName)
        npNodePath = self.ralph.attachNewNode(nameplate)
        npNodePath.setScale(0.8)
        npNodePath.setBillboardPointEye()
        #npNodePath.setPos(1.0,0,6.0)
        npNodePath.setZ(6.5)

        bar = DirectWaitBar(value=100, scale=1.0)
        bar.setColor(255, 0, 0)
        #bar.setBarRelief()
        bar.setZ(6.0)
        bar.setBillboardPointEye()
        bar.reparentTo(self.ralph)

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("arrow_up", self.setKey, ["forward", 1])
        self.accept("a", self.setKey, ["cam-left", 1])
        self.accept("s", self.setKey, ["cam-right", 1])
        self.accept("arrow_left-up", self.setKey, ["left", 0])
        self.accept("arrow_right-up", self.setKey, ["right", 0])
        self.accept("arrow_up-up", self.setKey, ["forward", 0])
        self.accept("a-up", self.setKey, ["cam-left", 0])
        self.accept("s-up", self.setKey, ["cam-right", 0])
        self.accept("c", self.setKey, ["charge", 1])
        self.accept("c-up", self.setKey, ["charge", 0])

        taskMgr.add(self.move, "moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera

        base.disableMouse()
        base.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2)

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

        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 1000)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 1000)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

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

        # Uncomment this line to show a visual representation of the
        # collisions occuring
        #self.cTrav.showCollisions(render)

        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

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

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

        # If the camera-left key is pressed, move camera left.
        # If the camera-right key is pressed, move camera right.

        base.camera.lookAt(self.ralph)
        if (self.keyMap["cam-left"] != 0):
            base.camera.setX(base.camera, -20 * globalClock.getDt())
        if (self.keyMap["cam-right"] != 0):
            base.camera.setX(base.camera, +20 * globalClock.getDt())

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

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if (self.keyMap["left"] != 0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"] != 0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"] != 0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())
        if (self.keyMap["charge"] != 0):
            self.ralph.setY(self.ralph, -250 * globalClock.getDt())
            #ribbon = Ribbon(self.ralph, Vec4(1,1,1,1), 3, 10, 0.3)
            #ribbon.getRoot().setZ(2.0)

        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"] != 0) or (self.keyMap["charge"] != 0) or (
                self.keyMap["left"] != 0) or (self.keyMap["right"] != 0):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        # If the camera is too far from ralph, move it closer.
        # If the camera is too close to ralph, move it farther.

        camvec = self.ralph.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if (camdist > 10.0):
            base.camera.setPos(base.camera.getPos() + camvec * (camdist - 10))
            camdist = 10.0
        if (camdist < 5.0):
            base.camera.setPos(base.camera.getPos() - camvec * (5 - camdist))
            camdist = 5.0

        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(
            y.getSurfacePoint(render).getZ(),
            x.getSurfacePoint(render).getZ()))
        if (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                   == "terrain"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)

        # Keep the camera at one foot above the terrain,
        # or two feet above ralph, whichever is greater.

        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(
            y.getSurfacePoint(render).getZ(),
            x.getSurfacePoint(render).getZ()))
        if (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                   == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)
        if (base.camera.getZ() < self.ralph.getZ() + 2.0):
            base.camera.setZ(self.ralph.getZ() + 2.0)

        # The camera should look in ralph's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above ralph's head.

        self.floater.setPos(self.ralph.getPos())
        self.floater.setZ(self.ralph.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        return task.cont
예제 #59
0
class MousePicker(object):
    def __init__(self,
                 pickTag='MyPickingTag',
                 nodeName='pickRay',
                 showCollisions=False):
        self.pickTag = pickTag
        self.nodeName = nodeName
        self.showCollisions = showCollisions

    def create(self):
        self.mPickerTraverser = CollisionTraverser()
        self.mCollisionQue = CollisionHandlerQueue()

        self.mPickRay = CollisionRay()
        self.mPickRay.setOrigin(base.camera.getPos(base.render))
        self.mPickRay.setDirection(
            base.render.getRelativeVector(base.camera, Vec3(0, 1, 0)))

        #create our collison Node to hold the ray
        self.mPickNode = CollisionNode(self.nodeName)
        self.mPickNode.addSolid(self.mPickRay)

        #Attach that node to the camera since the ray will need to be positioned
        #relative to it, returns a new nodepath
        #well use the default geometry mask
        #this is inefficent but its for mouse picking only

        self.mPickNP = base.camera.attachNewNode(self.mPickNode)

        #we'll use what panda calls the "from" node.  This is reall a silly convention
        #but from nodes are nodes that are active, while into nodes are usually passive environments
        #this isnt a hard rule, but following it usually reduces processing

        #Everything to be picked will use bit 1. This way if we were doing other
        #collision we could seperate it, we use bitmasks to determine what we check other objects against
        #if they dont have a bitmask for bit 1 well skip them!
        self.mPickNode.setFromCollideMask(BitMask32(1))

        #Register the ray as something that can cause collisions
        self.mPickerTraverser.addCollider(self.mPickNP, self.mCollisionQue)

        #Setup 2D picker
        self.mPickerTraverser2D = CollisionTraverser()
        self.mCollisionQue2D = CollisionHandlerQueue()

        self.mPickNode2D = CollisionNode('2D PickNode')
        self.mPickNode2D.setFromCollideMask(BitMask32(1))
        self.mPickNode2D.setIntoCollideMask(BitMask32.allOff())

        self.mPick2DNP = base.camera2d.attachNewNode(self.mPickNode2D)

        self.mPickRay2D = CollisionRay()
        self.mPickNode2D.addSolid(self.mPickRay2D)

        self.mPickerTraverser2D.addCollider(self.mPick2DNP,
                                            self.mCollisionQue2D)

        if self.showCollisions:
            self.mPickerTraverser.showCollisions(base.render)
            self.mPickerTraverser2D.showCollisions(base.aspect2d)

    def mousePick(self, traverse=None, tag=None):
        #do we have a mouse
        if (base.mouseWatcherNode.hasMouse() == False):
            return None, None

        traverse = traverse or base.render
        tag = tag or self.pickTag

        mpos = base.mouseWatcherNode.getMouse()

        #Set the position of the ray based on the mouse position
        self.mPickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
        self.mPickerTraverser.traverse(traverse)

        if (self.mCollisionQue.getNumEntries() > 0):
            self.mCollisionQue.sortEntries()

            for entry in self.mCollisionQue.getEntries():
                pickedObj = entry.getIntoNodePath()
                pickedObj = pickedObj.findNetTag(tag)

                if not pickedObj.isEmpty():
                    pos = entry.getSurfacePoint(base.render)
                    return pickedObj, pos

        return None, None

    def mousePick2D(self, traverse=None, tag=None, all=False):
        #do we have a mouse
        if (base.mouseWatcherNode.hasMouse() == False):
            return None, None

        traverse = traverse or base.render
        tag = tag or self.pickTag

        mpos = base.mouseWatcherNode.getMouse()

        self.mPickRay2D.setFromLens(base.cam2d.node(), mpos.getX(),
                                    mpos.getY())

        self.mPickerTraverser2D.traverse(base.aspect2d)

        if self.mCollisionQue2D.getNumEntries() > 0:
            self.mCollisionQue2D.sortEntries()

            if all:
                return [(entry.getIntoNodePath().findNetTag(tag),
                         entry.getSurfacePoint(base.aspect2d))
                        for entry in self.mCollisionQue2D.getEntries()], None
            else:
                entry = self.mCollisionQue2D.getEntry(0)
                pickedObj = entry.getIntoNodePath()

                pickedObj = pickedObj.findNetTag(tag)
                if not pickedObj.isEmpty():
                    pos = entry.getSurfacePoint(base.aspect2d)
                    return pickedObj, pos

        return None, None