예제 #1
0
 def getMouseRay(self, collRay=False):
     ray = CollisionRay()
     ray.setFromLens(self.camNode, self.getMouse())
     if collRay:
         return ray
     else:
         return Ray(ray.getOrigin(), ray.getDirection())
예제 #2
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])
예제 #3
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
예제 #4
0
class MouseCollision:
    def __init__(self, game):

        self.game = game

        self.c_trav = CollisionTraverser()

        self.mouse_groundHandler = CollisionHandlerQueue()
        self.mouse_ground_ray = CollisionRay()
        self.mouse_ground_col = CollisionNode('mouseRay')

        self.mouse_ground_ray.setOrigin(0, 0, 0)
        self.mouse_ground_ray.setDirection(0, -1, 0)

        self.mouse_ground_col.addSolid(self.mouse_ground_ray)
        self.mouse_ground_col.setFromCollideMask(CollideMask.bit(0))
        self.mouse_ground_col.setIntoCollideMask(CollideMask.allOff())

        self.mouse_ground_col_np = self.game.camera.attachNewNode(
            self.mouse_ground_col)

        self.c_trav.addCollider(self.mouse_ground_col_np,
                                self.mouse_groundHandler)

        self.game.taskMgr.add(self.update, 'updateMouse')

    def update(self, task):

        if self.game.mouseWatcherNode.hasMouse():
            if self.game.ship.model:

                mouse_pos = self.game.mouseWatcherNode.getMouse()

                self.mouse_ground_ray.setFromLens(self.game.camNode,
                                                  mouse_pos.getX(),
                                                  mouse_pos.getY())

                near_point = render.getRelativePoint(
                    self.game.camera, self.mouse_ground_ray.getOrigin())
                near_vec = render.getRelativeVector(
                    self.game.camera, self.mouse_ground_ray.getDirection())

                self.game.ship.shipPoint.setPos(
                    self.PointAtY(self.game.ship.model.getY(), near_point,
                                  near_vec))

        return task.cont

    def PointAtY(self, y, point, vec):
        return point + vec * ((y - point.getY()) / vec.getY())
예제 #5
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
예제 #6
0
class MouseCollision:
    def __init__(self, game):

        self.game = game

        self.c_trav = CollisionTraverser()

        self.mouse_groundHandler = CollisionHandlerQueue()
        self.mouse_ground_ray = CollisionRay()
        self.mouse_ground_col = CollisionNode('mouseRay')

        self.mouse_ground_ray.setOrigin(0, 0, 0)
        self.mouse_ground_ray.setDirection(0, -1, 0)

        self.mouse_ground_col.addSolid(self.mouse_ground_ray)
        self.mouse_ground_col.setFromCollideMask(CollideMask.bit(0))
        self.mouse_ground_col.setIntoCollideMask(CollideMask.allOff())

        self.mouse_ground_col_np = self.game.camera.attachNewNode(self.mouse_ground_col)

        self.c_trav.addCollider(self.mouse_ground_col_np, self.mouse_groundHandler)

        self.game.taskMgr.add(self.update, 'updateMouse')

    def update(self, task):

        if self.game.mouseWatcherNode.hasMouse():
            if self.game.ship.model:

                mouse_pos = self.game.mouseWatcherNode.getMouse()

                self.mouse_ground_ray.setFromLens(self.game.camNode, mouse_pos.getX(), mouse_pos.getY())

                near_point = render.getRelativePoint(self.game.camera, self.mouse_ground_ray.getOrigin())
                near_vec = render.getRelativeVector(self.game.camera, self.mouse_ground_ray.getDirection())

                self.game.ship.shipPoint.setPos(self.PointAtY(self.game.ship.model.getY(), near_point, near_vec))

        return task.cont

    def PointAtY(self, y, point, vec):
        return point + vec * ((y - point.getY()) / vec.getY())
예제 #7
0
    def _get_collision(self, node, debug=False):
        mx = self.mouseWatcherNode.getMouseX()
        my = self.mouseWatcherNode.getMouseY()
        if debug:
            print "mouse:", (mx, my)

        # get the origin and direction of the ray extending from the
        # camera to the mouse pointer
        cm = np.array(self.cam.getNetTransform().getMat())
        cr = CollisionRay()
        cr.setFromLens(self.cam.node(), (mx, my))
        cp = np.hstack([cr.getOrigin(), 1])
        cd = np.hstack([cr.getDirection(), 0])
        cp = np.dot(cm.T, cp)[:3]
        cd = np.dot(cm.T, cd)[:3]
        if cd[2] > -1:
            cd[2] = -1
        if debug:
            print "direction:", cd
            print "origin:", cp

        # point on the plane, z-axis
        pz = node.getPos(self.render)[2]
        sz = node.getScale(self.render)[2] / 2.0
        p0 = np.array([0, 0, pz + sz])
        if debug:
            print "p0:", p0

        # this is the intersection equation that we want to solve,
        # where s is the point on the line that intersects
        #     e_z(cp + s*cd - p0) = 0
        s = (p0[2] - cp[2]) / cd[2]
        if debug:
            print "s:", s

        # transform the collision point from line coordinates to world
        # coordinates
        cv = cp + s * cd
        if debug:
            print "collision:", cv

        return cv
예제 #8
0
    def _get_collision(self, node, debug=False):
        mx = self.mouseWatcherNode.getMouseX()
        my = self.mouseWatcherNode.getMouseY()
        if debug:
            print "mouse:", (mx, my)

        # get the origin and direction of the ray extending from the
        # camera to the mouse pointer
        cm = np.array(self.cam.getNetTransform().getMat())
        cr = CollisionRay()
        cr.setFromLens(self.cam.node(), (mx, my))
        cp = np.hstack([cr.getOrigin(), 1])
        cd = np.hstack([cr.getDirection(), 0])
        cp = np.dot(cm.T, cp)[:3]
        cd = np.dot(cm.T, cd)[:3]
        if cd[2] > -1:
            cd[2] = -1
        if debug:
            print "direction:", cd
            print "origin:", cp

        # point on the plane, z-axis
        pz = node.getPos(self.render)[2]
        sz = node.getScale(self.render)[2] / 2.0
        p0 = np.array([0, 0, pz + sz])
        if debug:
            print "p0:", p0

        # this is the intersection equation that we want to solve,
        # where s is the point on the line that intersects
        #     e_z(cp + s*cd - p0) = 0
        s = (p0[2] - cp[2]) / cd[2]
        if debug:
            print "s:", s

        # transform the collision point from line coordinates to world
        # coordinates
        cv = cp + s * cd
        if debug:
            print "collision:", cv

        return cv
예제 #9
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
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])
예제 #11
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
예제 #12
0
파일: gamingcam.py 프로젝트: onze/goLive
class GamingCam(object,DirectObject):
   yshift,zshift=5,5
   ymin,ymax=10,70
   zmin,zmax=10,70
   zoom_speed=.1
   move_speed=.5
   def __init__(self,gmap,gaming_zone):
      DirectObject.__init__(self)
      #gaming zone (used for mouse movement), as a tools.Rectangle
      self.gaming_zone=gaming_zone
      #actual camera node
      self.p3dcam=base.camera
      #what the cam is oriented to
      self._target=base.render.attachNewNode('GaminCam.target')
      #range=[0,1] between min and max closeness to ground
      self.level=.7
      #
      #keys_down acts as a pool containing keys (+mouse buttons) currently down
      self.keys_down=[]
      update_list.append(self.update)
      #setup for mouse picking
      picker_node=CollisionNode('gcam_to_mouse_ray')#general collision node
      picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask())
      self.picker_ray=CollisionRay()#solid ray to attach to coll node
      picker_node.addSolid(self.picker_ray)
      self.picker_np=self.p3dcam.attachNewNode(picker_node)#attach this node to gcam
      self.collision_queue=CollisionHandlerQueue()#stores collisions
      self.collision_traverser=CollisionTraverser('gcam_traverser')#actual computer
      self.collision_traverser.addCollider(self.picker_np,self.collision_queue)
      base.cTrav=self.collision_traverser
      self.gmap=gmap
      #stack of states (state=pos+zoom)
      self.states_stack=[]
      #enable the cam to move according to keyboard and mouse
      self.move_enabled=True

   def __del__(self):
      update_list.remove(self.update)
      self.ignoreAll()
      
   def center(self):
      self._target.setPos(0,0,0)
      
   def disable_move(self):
      self.move_enabled=False

   def enable_move(self):
      self.move_enabled=True

   def get_level(self):
      return self._level
   
   def get_picked_tile(self):
      '''
      returns
      '''
      if base.mouseWatcherNode.hasMouse():
         #get the mouse position
         mpos = base.mouseWatcherNode.getMouse()
         #Set the position of the ray based on the mouse position
#         self.picker_ray.setFromLens(self.p3dcam.node().getLens(), mpos.getX(), mpos.getY())
         self.picker_ray.setFromLens(base.camNode, mpos.getX(), mpos.getY())
         self.collision_traverser.traverse(self.gmap.tile_matrix_node)
         if self.collision_queue.getNumEntries()>0:
            #useless since collision test is done against a single object
            self.collision_queue.sortEntries()
            entry=self.collision_queue.getEntry(0)
            x,y,_=entry.getSurfacePoint(self.gmap.tile_matrix_node)
            x=(x+self.gmap.resx)/2.
            y=(y+self.gmap.resy)/2.
            x=max(x,0)
            x=min(x,self.gmap.resx)
            y=max(y,0)
            y=min(y,self.gmap.resy)
            x=int(x)
            y=int(y)
            #out(pos=(x,y,z))
            return self.gmap.tile_matrix[x][y]
      return None
   
   def get_picked_unit(self):
      if base.mouseWatcherNode.hasMouse():
         #get the mouse position
         mpos = base.mouseWatcherNode.getMouse()
         #Set the position of the ray based on the mouse position
#         self.picker_ray.setFromLens(self.p3dcam.node().getLens(), mpos.getX(), mpos.getY())
         self.picker_ray.setFromLens(base.camNode, mpos.getX(), mpos.getY())
         self.collision_traverser.traverse(self.gmap.units_node)
         if self.collision_queue.getNumEntries()>0:
            #useless since collision test is done against a single object
            self.collision_queue.sortEntries()
            entry=self.collision_queue.getEntry(0)
            return entry.getIntoNodePath().findNetTag('GUnit-pickable')
      return None
      

   def get_target(self):
      return self._target
   
   def mouse_up(self,btn):
      if btn=='left':
         target=self.get_picked_tile()
         #out(target)
         #print NodePath(self.gmap.tile_matrix_node).ls()
         #print render.analyze()
         if target:
            network.serverproxy.send({network.cts_dbg_dump_entity:{'eid':target.eid}})
      elif btn=='middle':
         self.set_level(.7)
         self.set_target(Vec3(0,-9,0))

   def move(self,dx=0,dy=0):
      self._target.setPos(self._target,dx,dy,0)
      self.update_cam()

   def push_state(self):
      out('GCam.push_state()')
      pos,zoom=self._target.getPos(),self.level
      self.states_stack.append((pos,zoom))
      
   def pop_state(self):
      out('GCam.pop_state()')
      pos,zoom=self.states_stack.pop(-1)
      self._target.setPos(*pos)
      self.level=zoom
      self.update_cam()

   def set_level(self,level):
      self._level=level
      self.update_cam()

   def set_target(self,target):
      '''
      make the cam look at the given target.
      target can be a set of coordinates, or a node/nodepath.
      '''
      if isinstance(target,PandaNode) or isinstance(target,NodePath):
         self._target.setPos(target,0,0,0)
      if isinstance(target,tuple):
         self._target.setPos(Vec3(*target))
      else:
         self._target.setPos(target)
      self.update_cam()

   def start_accepting(self):
      '''
      the gaming cam is created at gmap creation, so it has to wait
      until all data structures are created before accepting events.
      '''
      self.accept(ConfigVariableString('key-cam-zoom-in').getValue()+'-up',self.zoom,extraArgs=[-GamingCam.zoom_speed])
      self.accept(ConfigVariableString('key-cam-zoom-out').getValue()+'-up',self.zoom,extraArgs=[GamingCam.zoom_speed])
      self.accept(ConfigVariableString('key-cam-right').getValue(),self.keys_down.append,extraArgs=['r'])
      self.accept(ConfigVariableString('key-cam-right').getValue()+'-up',self.keys_down.remove,extraArgs=['r'])
      self.accept(ConfigVariableString('key-cam-up').getValue(),self.keys_down.append,extraArgs=['u'])
      self.accept(ConfigVariableString('key-cam-up').getValue()+'-up',self.keys_down.remove,extraArgs=['u'])
      self.accept(ConfigVariableString('key-cam-left').getValue(),self.keys_down.append,extraArgs=['l'])
      self.accept(ConfigVariableString('key-cam-left').getValue()+'-up',self.keys_down.remove,extraArgs=['l'])
      self.accept(ConfigVariableString('key-cam-down').getValue(),self.keys_down.append,extraArgs=['d'])
      self.accept(ConfigVariableString('key-cam-down').getValue()+'-up',self.keys_down.remove,extraArgs=['d'])
      self.accept('mouse1-up',self.mouse_up,extraArgs=['left'])
      self.accept('mouse2-up',self.mouse_up,extraArgs=['middle'])
      

   def update(self):
      dx,dy=0,0
      for k in self.keys_down:
         if k=='r':dx+=GamingCam.move_speed
         if k=='l':dx-=GamingCam.move_speed
         if k=='u':dy+=GamingCam.move_speed
         if k=='d':dy-=GamingCam.move_speed
         if k=='m':
            pass
            #dx+=mouse.getMouseX()
            #dy+=mouse.getMouseY()
      if self.move_enabled:
         self.move(dx,dy)

   def update_cam(self):
      self.p3dcam.setPos(   self._target,
                     0,
                     -(GamingCam.ymin+GamingCam.yshift+self._level*GamingCam.ymax),
                     GamingCam.zmin+GamingCam.zshift+self._level*GamingCam.zmax
                     )
      self.p3dcam.lookAt(self._target)

   def zoom(self,delta):
      #TODO: smoothen the zoom with a task (interpolation)
      if 0<self._level+delta<1.:
         self.level+=delta

   level=property(get_level,set_level)
   target=property(get_target,set_target)
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
예제 #14
0
파일: battle.py 프로젝트: Allexit/tgc-game
class Battle(object, DirectObject):
    """ Battle shows UI, includes controller etc.
    """
    def __init__(self, nick):
        self.player = player.Player(nick=nick)
        self.controller = controller.ClientController(self.player)
        self.handgui = hand.HandGUI(self.player.hand)
        camera.setPos(0, -20, 0)
        self.accept("turn_time_changed", self.update_turn_time)
        self.turn_timer = TurnTimer()

        # Mouse detection:
        base.cTrav = CollisionTraverser()
        self.mouse_ray_handler = CollisionHandlerQueue()
        mouse_ray_node = CollisionNode('mouse_ray')
        mouse_ray_np = camera.attachNewNode(mouse_ray_node)
        mouse_ray_node.setFromCollideMask(GeomNode.getDefaultCollideMask())
        mouse_ray_node.setIntoCollideMask(0)
        self.mouse_ray = CollisionRay()
        mouse_ray_node.addSolid(self.mouse_ray)
        base.cTrav.addCollider(mouse_ray_np, self.mouse_ray_handler)

        self.mouse_overed_entry = None

        self.accept("mouse_enter", self.enlarge_entry)
        self.accept("mouse_leave", self.shrink_entry)

        self.accept("p-up", self.change_card_picture)

        taskMgr.doMethodLater(0.1, self.check_mouse_over, "check_mouse_over")

    def update_turn_time(self, turn_time):
        self.turn_timer.time_left = turn_time
        self.turn_timer.update_displayed_time()

    def check_mouse_over(self, task):
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            self.mouse_ray.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            base.cTrav.traverse(render)

            entries_amount = self.mouse_ray_handler.getNumEntries()

            if entries_amount > 0:
                self.mouse_ray_handler.sortEntries()
                entry = self.mouse_ray_handler.getEntry(0)
                if entry != self.mouse_overed_entry:
                    messenger.send('mouse_leave', [self.mouse_overed_entry])
                    messenger.send('mouse_enter', [entry])
                self.mouse_overed_entry = entry
                self.mouse_over(entry)
            else:
                if self.mouse_overed_entry:
                    # TODO: Make sure this does not cause referencing errors
                    messenger.send('mouse_leave', [self.mouse_overed_entry])
                self.mouse_overed_entry = None

        return task.again

    def mouse_over(self, entry):
        object_np = entry.getIntoNodePath()
        objekt = object_np.findNetTag("object_type")  # object is reserved word

        if objekt.isEmpty():
            print "No object type detected"
            return

        object_type = objekt.getTag("object_type")
        if object_type == "card":
            self.handgui.mouse_over(objekt.getPythonTag('owner'))

    def enlarge_entry(self, entry):
        entry_np = entry.getIntoNodePath()
        card_root = None
        if entry_np.hasPythonTag('root'):
            card_root = entry_np.getPythonTag('root')

        # TODO: Replace magic number with variable
        card_root.setY(self.handgui.nodepath, -15)

    def shrink_entry(self, entry):
        if not entry:
            return

        entry_np = entry.getIntoNodePath()

        card_root = None
        if entry_np.hasPythonTag('root'):
            card_root = entry_np.getPythonTag('root')
        card_root.setY(self.handgui.nodepath, 0)

    def change_card_picture(self):
        self.handgui.hand[0].change_picture()
예제 #15
0
class CameraManager():
  ZOOM_SPEED = 50

  CAM_X = 'camX'
  CAM_Y = 'camY'
  CAM_Z = 'camZ'

  def __init__(self, showBase, camDict):
    self.showBase = showBase
    self.showBase.disableMouse()
    self.setSettings(camDict)
    self.initMouseToWorldCoordConversion()
    self.initMouseRayCollision()
    self.savedCollisionPoint = Vec3(0, 0, 0)
  # End
  
  """ init helpers """
  def setSettings(self, camDict):
    cam = self.showBase.camera
    cam.setPos(50, 0, -1000)
    self.camPos = cam.getPos()
    cam.setHpr(0, 90, 0)
    self.showBase.camLens.setFov(10)
    self.dragging = False
    self.loadSettings(camDict)
    
    
  
  def initMouseRayCollision(self):
    z = 0
    self.plane = Plane(Vec3(0, 0, 1), Point3(0, 0, z))

  def initMouseToWorldCoordConversion(self):
    self.picker = CollisionTraverser()
    self.pq = CollisionHandlerQueue()

    self.pickerNode = CollisionNode('mouseRay')
    self.pickerNP = self.showBase.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)
  
  
  """ Events """
  def zoomIn(self):
    camera = self.showBase.camera
    curPos = camera.getPos()
    curPos.z += CameraManager.ZOOM_SPEED

    camera.setPos(curPos)
    self.saveSettings(self.camDict)

  def zoomOut(self):
    camera = self.showBase.camera
    curPos = camera.getPos()
    curPos.z += -CameraManager.ZOOM_SPEED

    camera.setPos(curPos)
    self.saveSettings(self.camDict)

  def mouse1Down(self):
    self.savedCollisionPoint = self.getMouseCollisionToPlane(self.plane)
    # print("mouse1Down")
    
  def mouseMove(self, task):
    collisionPoint = self.getMouseCollisionToPlane(self.plane)
    delta = self.getDelta(collisionPoint, self.savedCollisionPoint)

    self.addToCameraPos(delta) # Collision point changes if camera position changes

    collisionPoint = self.getMouseCollisionToPlane(self.plane)
    self.savedCollisionPoint = collisionPoint
    return Task.cont


  """ mouse1Down and mouseMove helpers """
  def getMouseCollisionToPlane(self, plane):
    mouseWatcherNode = self.showBase.mouseWatcherNode
    if mouseWatcherNode.hasMouse():
      mpos = mouseWatcherNode.getMouse()

      pos3d = Point3()
      nearPoint = Point3()
      farPoint = Point3()
      self.showBase.camLens.extrude(mpos, nearPoint, farPoint)

      render = self.showBase.render
      camera = self.showBase.camera
      if plane.intersectsLine(pos3d,
        render.getRelativePoint(camera, nearPoint),
        render.getRelativePoint(camera, farPoint)):
        return pos3d
    return None
  
  
  
  """ mouseMove helpers """
  def getDelta(self, point1, point2):
    delta = Vec3()
    if point1 is not None:
      if point1.almostEqual(point2) is False:
        delta = point2 - point1
    return delta

  def addToCameraPos(self, delta):
    camera = self.showBase.camera
    curPos = camera.getPos()
    camera.setPos(curPos + delta)

    self.saveSettings(self.camDict)

  def setViewBasedOnNodePos(self, pos):
    camera = self.showBase.camera
    newPos = Vec3(camera.getPos())
    newPos.x = pos.x
    newPos.y = pos.y
    camera.setPos(newPos)
    
  # NodePath datection is manage internally in Panda3D, NodeManager should have been
  # managing NodePath, but it can be handled by communication with Camera and 
  # Panda3D already, so NodeManager is not needed anymore here
  # TODO: Refactor
  def getClickedNodePath(self):
    mouseWatcherNode = self.showBase.mouseWatcherNode
    if mouseWatcherNode.hasMouse():
      mpos = mouseWatcherNode.getMouse()
      
      self.pickerRay.setFromLens(self.showBase.camNode, mpos.getX(), mpos.getY())
      
      self.picker.traverse(self.showBase.render)
      
      if self.pq.getNumEntries() > 0:
        self.pq.sortEntries()
        return self.pq.getEntry(0).getIntoNodePath()
    return None

  def getCoordinates(self):
    mouseWatcherNode = self.showBase.mouseWatcherNode
    mpos = mouseWatcherNode.getMouse()

    self.pickerRay.setFromLens(self.showBase.camNode, 
      mpos.getX(), mpos.getY())

    render = self.showBase.render
    camera = self.showBase.camera
    nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin())

    return mpos, nearPoint

  def saveSettings(self, camDict):
    self.camDict = camDict
    cam = self.showBase.camera
    pos = cam.getPos()

    camDict[CameraManager.CAM_X] = pos.x
    camDict[CameraManager.CAM_Y] = pos.y
    camDict[CameraManager.CAM_Z] = pos.z

  def loadSettings(self, camDict):
    self.camDict = camDict
    if camDict is None:
      self.camDict = {}
    if camDict.get(CameraManager.CAM_X) is not None:
      camera = self.showBase.camera
      camera.setPos(camDict[CameraManager.CAM_X], 
        camDict[CameraManager.CAM_Y], 
        camDict[CameraManager.CAM_Z])
    


  def showValues(self):
    print("camera pos " + str(self.showBase.camera.getPos()))
    print("camera hpr " + str(self.showBase.camera.getHpr()))
    print("camera x " + str(self.showBase.camera.getX()))
    print("camera y " + str(self.showBase.camera.getY()))
    print("camera z " + str(self.showBase.camera.getZ()))
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
class p3dApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self);
        
        # setup the environment or model
        self.model = \
            self.loader.loadModel("/usr/share/panda3d/models/box");
        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;
예제 #17
0
파일: game.py 프로젝트: pennomi/pastry
class ChessboardDemo(ShowBase):
    def __init__(self, client):
        ShowBase.__init__(self)
        self.client = client

        # 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), shadow=(0, 0, 0, 1),
                                  pos=(0.8, -0.95), scale = .07)
        self.escapeEvent = OnscreenText(
            text="ESC: Quit", parent=base.a2dTopLeft,
            style=1, fg=(1, 1, 1, 1), pos=(0.06, -0.1),
            align=TextNode.ALeft, scale = .05)
        self.mouse1Event = OnscreenText(
            text="Left-click and drag: Pick up and drag piece",
            parent=base.a2dTopLeft, align=TextNode.ALeft,
            style=1, fg=(1, 1, 1, 1), pos=(0.06, -0.16), scale=.05)

        self.accept('escape', sys.exit)  # Escape quits
        self.disableMouse()  # Disable mouse camera control
        camera.setPosHpr(0, -12, 8, 0, -35, 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 collisions we could separate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  # Make our ray
        # Add it to the collision node
        self.pickerNode.addSolid(self.pickerRay)
        # Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)
        # self.picker.showCollisions(render)

        # 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 squares and save the time of
        # checking the rest of the scene
        self.square_root = render.attachNewNode("square_root")

        # For each square
        self.squares = [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.square_root)
            self.squares[i].setPos(square_pos(i))
            self.squares[i].setColor(square_color(i))
            # Set the model itself to be collidable with the ray. If this model
            # is 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 it 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

        # This will represent the index of the currently highlighted square
        self.hiSq = False
        # Represents 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.grab_piece)  # left-click grabs a piece
        self.accept("mouse1-up", self.release_piece)  # releasing places it

    def swap_pieces(self, fr, to):
        # Get the objects from the square references
        fr_model, fr_do = self.model_at(fr), self.piece_at(fr)
        to_model, to_do = self.model_at(to), self.piece_at(to)

        # Handle the from model
        fr_model.setPos(square_pos(to))
        fr_do.square = to
        self.client._save(fr_do)

        # Handle the to model if it exists
        if to_do:
            to_model.setPos(square_pos(fr))
            to_do.square = fr
            self.client._save(to_do)

    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(square_color(self.hiSq))
            self.hiSq = False

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

            # Set the position of the ray based on the mouse position
            self.pickerRay.setFromLens(
                self.camNode, mouse_pos.getX(), mouse_pos.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())
                model = self.model_at(self.dragging)
                model.setPos(
                    point_at_z(.5, nearPoint, nearVec))

            # Do the actual collision pass (Do it only on the squares for
            # efficiency purposes)
            # noinspection PyArgumentList
            self.picker.traverse(self.square_root)
            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 piece_at(self, square):
        for p in self.client.objects:
            if p.square == square:
                return p
        return None

    def model_at(self, square):
        for p in self.client.objects:
            if p.square == square:
                return self.client.models[p.id]
        return None

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

    def release_piece(self):
        # If we are not on a square, return it to its original position.
        # Otherwise, swap it with the piece in the new square
        # Make sure we really are dragging something
        if self.dragging is not False:
            # We have let go of the piece, but we are not on a square
            if self.hiSq is False:
                model = self.model_at(self.dragging)
                model.setPos(
                    square_pos(self.dragging))
            else:
                # Otherwise, swap the pieces
                self.swap_pieces(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((.8, .8, .8, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(LVector3(0, 45, -45))
        directionalLight.setColor((0.2, 0.2, 0.2, 1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(ambientLight))
예제 #18
0
class Picker(object):
    """
    Generic object picker class for Panda3d. Given a top Node Path to search,
    it finds the closest collision object under the mouse pointer.

    Picker takes a topNode to test for mouse ray collisions.

    the pick() method returns (NodePathPicked, 3dPosition, rawNode) underneath the mouse position.
    If no collision was detected, it returns None, None, None.

    'NodePathPicked' is the deepest NAMED node path that was collided with, this is
    usually what you want. rawNode is the deep node (such as geom) if you want to
    play with that. 3dPosition is where the mouse ray touched the surface.

    The picker object uses base.camera to collide, so if you have a custom camera,
    well, sorry bout that.

    pseudo code:
    p = Picker(mycollisionTopNode)
    thingPicked, positionPicked, rawNode = p.pick()
    if thingPicked:
        # do something here like
        thingPicked.ls()

    """
    def __init__(self, topNode, cameraObject = None):
        self.traverser = CollisionTraverser()
        self.handler = CollisionHandlerQueue()
        self.topNode = topNode
        self.cam = cameraObject

        pickerNode  = CollisionNode('MouseRay')

        #NEEDS to be set to global camera. boo hoo
        self.pickerNP = base.camera.attachNewNode(pickerNode)

        # this seems to enter the bowels of the node graph, making it
        # difficult to perform logic on
        pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())

        self.pickRay = CollisionRay()
        #pickerNode.setCollideMask(BitMask32.allOff())
        pickerNode.addSolid(self.pickRay)
        self.traverser.addCollider(self.pickerNP, self.handler)

    def setTopNode(self, topNode):
        """set the topmost node to traverse when detecting collisions"""
        self.topNode = topNode

    def destroy(self):
        """clean up my stuff."""
        self.ignoreAll()
        # remove colliders, subnodes and such
        self.pickerNP.remove()
        self.traverser.clearColliders()

    def pick(self):
        """
        pick closest object under the mouse if available.
        returns ( NodePathPicked, surfacePoint, rawNode )
        or (None, None None)
        """
        if not self.topNode:
            return None, None, None

        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()

            self.pickRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            self.traverser.traverse(self.topNode)

            if self.handler.getNumEntries() > 0:
                self.handler.sortEntries()
                picked = self.handler.getEntry(0).getIntoNodePath()
                thepoint = self.handler.getEntry(0).getSurfacePoint(self.topNode)
                return self.getFirstParentWithName(picked), thepoint, picked

        return None, None, None

    def getFirstParentWithName(self, pickedObject):
        """
        return first named object up the node chain from the picked node. This
        helps remove drudgery when you just want to find a simple object to
        work with. Normally, you wouldn't use this method directly.
        """
        name = pickedObject.getName()
        parent = pickedObject
        while not name:
            parent = parent.getParent()
            if not parent:
                raise Exception("Node '%s' needs a parent with a name to accept clicks." % (str(pickedObject)))

            name = parent.getName()
        if parent == self.topNode:
            raise Exception("Collision parent '%s' is top Node, surely you wanted to click something beneath it..." % (str(parent)))

        return parent
예제 #19
0
파일: selection.py 프로젝트: tgbugs/desc
class HasSelectables(HasKeybinds): #mixin see chessboard example
    def __init__(self):
        #selection detection
        self.picker = CollisionTraverser()
        self.pq = CollisionHandlerQueue()
        self.pickerNode = CollisionNode('mouseRay')
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        #self.pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) #TODO WOW geometry collision is SUPER slow...
        self.pickerNode.setFromCollideMask(BitMask32.bit(BITMASK_COLL_CLICK))
        #render.find('**selectable').node().setIntoCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        self.picker.addCollider(self.pickerNP, self.pq)
        #self.picker.showCollisions(render)

        #box selection detection HINT: start with drawing the 2d thing yo!

        self.__shift__ = False
        self.accept("shift", self.shiftOn)
        self.accept("shift-up", self.shiftOff)

        self.__ctrl__ = False
        self.accept("control", self.ctrlOn)
        self.accept("control-up", self.ctrlOff)

        #mouse handling
        self.accept("mouse1", self.clickHandler)
        self.accept("shift-mouse1", self.clickHandler)
        self.accept("mouse1-up", self.releaseHandler)

        #dragging
        self.dragTask = taskMgr.add(self.dragTask, 'dragTask')

    def getClickTarget(self,rootSelNode=None):
        """ traverse from the root of the selectable tree """
        #print('getting target....')
        if rootSelNode == None:
            rootSelNode = render

        if base.mouseWatcherNode.hasMouse():
            self.pickerRay.setFromLens(base.camNode, *base.mouseWatcherNode.getMouse())

            self.picker.traverse(rootSelNode)
            if self.pq.getNumEntries() > 0: #if we got something sort it
                self.pq.sortEntries()
                return self.pq.getEntry(0)



        #nearPoint = render.getRelativePoint(camera, self.pickerRay.getOrigin())
        #nearVec = render.getRelativeVector(camera, self.pickerRay.getDirection())
        #thingToDrag.obj.setPos(PointAtZ(.5, nearPoint, nearVec)) #not sure how this works

    def ctrlOn(self):
        self.__ctrl__ = True

    def ctrlOff(self):
        self.__ctrl__ = False

    def shiftOn(self):
        self.__shift__ = True

    def shiftOff(self):
        self.__shift__ = False

    @event_callback
    def clickHandler(self):
        pass

    @event_callback
    def releaseHandler(self):
        pass

    def dragTask(self, task):
        pass

    def clickSelectObject(self): #shif to multiselect... ?? to unselect invidiual??
        pass

    def dragSelectObjects(self): #always drag in the plane of the camera
        pass
예제 #20
0
class World(DirectObject):
    def __init__(self):
        self.winprops=WindowProperties()
        self.winprops.setCursorFilename(Filename.binaryFilename("question-icon.ico"))
        
        base.win.setClearColorActive(True)
        base.win.setClearColor(VBase4(0, 0, 0, 1))
        
        base.win.requestProperties(self.winprops) 
        self.enemyLights = []
        self.cameraPositions = [((0, 95, 75), (180, -27, 0)),((0, 55, 25), (180, -15, 0)),((0, -55, 25), (0, -15, 0))]
        self.cameraIndex = 0
        base.disableMouse()
        base.enableParticles()
        self.setupLights()
        self.setupPicking()
        #Prepare the vehicular manslaughter!
        self.boosterLightNP = None
        self.flameLights = None
        self.player = Vehicle("ralph_models/vampire_car", "ralph_models/vampire_car", self, "player")

        self.finalGas = None

        self.livesFrame = DirectFrame(frameColor=(0, 0, 0, 0), parent = base.a2dTopLeft)

        self.livesSprites = list()
        for i in range(0,self.player.health):
            sprite = OnscreenImage(image = 'images/healthicon.png', parent = self.livesFrame, scale = 0.08, pos = (0.2*i+0.1,0,-0.1))
            sprite.setTransparency(TransparencyAttrib.MAlpha)
            self.livesSprites.append(sprite)

        self.progressFrame = DirectFrame(frameColor=(0, 0, 0, 0), parent = base.a2dpTopRight)
        gasIcon = OnscreenImage(image = 'images/gas_icon.png', parent = self.progressFrame, scale = 0.04, pos = (-1,0,-0.05))
        # gasIcon.reparentTo(aspect2d)
        gasIcon.setTransparency(TransparencyAttrib.MAlpha)
                    
        # gasBar = OnscreenImage(image = 'images/gas_bar.png', parent = self.progressFrame, scale = 0.4)#, pos = (-0.9,0,-0.05))
        self.gasMax = DirectFrame(frameColor=(.133, .149, .149, 1),frameSize=(-1, 1, -1, 1), parent = self.progressFrame, scale = (0.432,1,0.055625), pos = (-.5,0,-0.04))
        self.gasLevel = DirectFrame(frameColor=(.433, .149, .149, 1),frameSize=(-1, -1, -1, 1), parent = self.progressFrame, scale = (0.432,1,0.055625), pos = (-.5,0,-0.04))
        gasBar = OnscreenImage(image = 'images/gas_bar_border.png', scale = (1,1,.9), pos = (-.0005,0,-0.04))
        gasBar.reparentTo(self.gasLevel)
        gasBar.setTransparency(TransparencyAttrib.MAlpha)

        timeBar = OnscreenImage(image = 'images/time_bar.png', parent = self.progressFrame, scale = (0.44,1,0.0525), pos = (-.47,0,-0.15))
        self.timePointer = OnscreenImage(image = 'images/time_bar_marker.png', parent = timeBar, scale = (0.05, 0, .2222), pos = (-.83,0,-0.15))
        # self.timePointer = OnscreenImage(image = 'images/time_bar_marker.png', parent = self.timeBar, scale = (0.44,1,0.0525), pos = (-.47,0,-0.2))
        timeBar.setTransparency(TransparencyAttrib.MAlpha)


        taskMgr.add(self.updateGasBar, "Update gas")

        self.loadModels()
        self.player.setPos(0,0,0)
        self.setupIntervals()
        camera.reparentTo(self.player)
        camera.setPos(self.cameraPositions[0][0][0],self.cameraPositions[0][0][1],self.cameraPositions[0][0][2])
        camera.setHpr(self.cameraPositions[0][1][0],self.cameraPositions[0][1][1],self.cameraPositions[0][1][2])
        self.setupCollisions()
        render.setShaderAuto() #you probably want to use this
        self.keyMap = {"left":0, "right":0, "forward":0, "backwards":0}
        taskMgr.add(self.player.move, "moveTask")
        
        #Give the vehicle direct access to the keyMap
        self.player.addKeyMap(self.keyMap)
        
        #Player Death
        taskMgr.add(self.deathChecker, "deathTask")
        
        #Sounds!
        self.loadSounds()
        self.currIcon = ""
        self.prevtime = 0
        self.isMoving = False
        self.accept("escape", sys.exit)
        
        self.accept("arrow_up", self.setKey, ["forward", 1])
        self.accept("w", self.setKey, ["forward", 1])
        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("d", self.setKey, ["right", 1])
        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("a", self.setKey, ["left", 1])
        self.accept("arrow_down", self.setKey, ["backwards", 1])
        self.accept("s", self.setKey, ["backwards", 1])
        
        self.accept("arrow_up-up", self.setKey, ["forward", 0])
        self.accept("w-up", self.setKey, ["forward", 0])
        self.accept("arrow_right-up", self.setKey, ["right", 0])
        self.accept("d-up", self.setKey, ["right", 0])
        self.accept("arrow_left-up", self.setKey, ["left", 0])
        self.accept("a-up", self.setKey, ["left", 0])
        self.accept("arrow_down-up", self.setKey, ["backwards", 0])
        self.accept("s-up", self.setKey, ["backwards", 0])
        
        self.accept("mouse1", self.startShoot)
        self.accept("mouse1-up", self.stopShoot)
        self.accept("mouse3", self.startDrain )
        self.accept("mouse3-up" , self.stopDrain)
        
        self.accept("tab", self.shiftCamera)   
        self.accept("space", self.player.startBoosters)
        
        self.accept("ate-smiley", self.eat)
        self.p1 = ParticleEffect()
        self.p2 = ParticleEffect()
        self.alan_var = False
        #Show collisiony stuff
        if DEBUG:
            base.cTrav.showCollisions(render)
        
        #f = open('testLog.txt', 'r+')
        #self.dfs(file = f)
        
        self.gasPlaying = False
        self.setLights()
    
        self.draining = False
        taskMgr.add(self.drain, 'drain')
        self.drainTime = 0.0
    
        self.flamethrowerActive = False
        self.gasLossTime = 0.0
        self.gasLossRate = 1.0    
        taskMgr.add(self.loseHealth, "loseGas")
        
        #After all the loading, we need to calculate our start time
        self.startTime = datetime.datetime.now()
        self.timeLimit = datetime.timedelta(seconds=175)
        
        timeInterval = LerpPosInterval(self.timePointer,
                                      self.timeLimit.seconds,
                                      (.8,0,-0.2))
        timeInterval.start()
    
        
        
    def setupPicking(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)
        
        self.staticRoot = render.attachNewNode('staticRoot')
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
        
    def dfs(self, item = render, depth = 0, file = None):
        if file:
            file.write(("-" * depth) + item.getName() + ": \n")
        # print(("-" * depth) + item.getName() + ": ")
        for i in range(item.getNumNodes()):
            if file:
                file.write((" " * depth) + "+" + item.getNode(i).getName() + ": " + str(item.getNode(i).getClassType()) + "\n")
            # print((" " * depth) + "+" + item.getNode(i).getName() + ": " + str(item.getNode(i).getClassType()))
        for i in range(item.getNumChildren()):
            self.dfs(item.getChild(i), depth + 1, file)
            
    def startDrain(self):
        if not self.flamethrowerActive:
            prevDraining = self.draining #previous value of draining
            if base.mouseWatcherNode.hasMouse():
                mpos = base.mouseWatcherNode.getMouse()
                self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
                self.picker.traverse(self.staticRoot)
                if self.pq.getNumEntries() > 0:
                    self.pq.sortEntries()
                    for i in range(self.pq.getNumEntries()):
                        if self.pq.getEntry(i).getIntoNode().getTag('car') != "":
                            self.target = int(self.pq.getEntry(i).getIntoNode().getTag('car'))
                            self.draining = True
            #Start sounds if self.draining started
            if self.draining and not prevDraining:
                self.drainSound.play()

    def drain(self, task):
        if self.draining and task.time - self.drainTime > DRAIN_DELAY:
            carpos = self.staticCars[self.target].getPos()
            playerpos = self.player.getPos()
            dist = math.sqrt( (carpos[0] - playerpos[0])**2 + (carpos[1] - playerpos[1])**2 + (carpos[2] - playerpos[2])**2 )
            if self.gasList[self.target] > 0 and dist < DRAIN_DIST:
                if not self.gasPlaying:
                    self.gasP.reset()
                    self.gasP = ParticleEffect()  
                    self.gasP.loadConfig(Filename('oil.ptf'))        
                    self.gasP.start(self.player)
                    self.gasNode.lookAt(self.staticCars[self.target])
                    self.gasP.setPos(0,0,2)
                    self.gasP.setScale(1.5)
                    self.gasP.setLightOff()
                    self.gasPlaying = True
                    self.alan_var = False
                self.gasNode.lookAt(self.staticCars[self.target])
                self.gasP.setHpr(self.gasNode.getH() + 180, 90, 0)
                self.player.totalGas = self.player.totalGas + 1
                self.gasList[self.target] = self.gasList[self.target] - 1
            else:
                self.alan_var = True
            # print "TotalGas: " + str(self.player.totalGas)
            self.drainTime = task.time
        elif not self.draining or self.alan_var:
            self.gasP.softStop()
            self.drainSound.stop()
            self.gasPlaying = False
        return Task.cont
                     
    def stopDrain(self):
        self.draining = False
           
    def loseHealth(self, task):
        if task.time - self.gasLossTime > GAS_TIME:
            if self.player.direction != 0:
                self.player.totalGas = self.player.totalGas - self.gasLossRate
            elif self.flamethrowerActive:
                self.player.totalGas = self.player.totalGas - self.gasLossRate
            self.gasLossTime = task.time
            # print self.player.totalGas
        return Task.cont
           
    def mouseTask(self, task):
        j = -1
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            self.picker.traverse(self.staticRoot)
            if self.pq.getNumEntries() > 0:
                self.pq.sortEntries()
                for i in range(self.pq.getNumEntries()):
                    if self.pq.getEntry(i).getIntoNode().getTag('car') != "":
                        j = int(self.pq.getEntry(i).getIntoNode().getTag('car'))
                        carpos = self.staticCars[j].getPos()  
                        playerpos = self.player.getPos()
                        dist = math.sqrt( (carpos[0] - playerpos[0])**2 + (carpos[1] - playerpos[1])**2 + (carpos[2] - playerpos[2])**2 )
                        if self.gasList[j] > 0 and dist < DRAIN_DIST:
                            self.winprops.setCursorFilename(Filename.binaryFilename("vamp-icon.ico"))
                            base.win.requestProperties(self.winprops)
                        elif self.gasList[j] > 0:
                            self.winprops.setCursorFilename(Filename.binaryFilename("vamp-off.ico"))
                            base.win.requestProperties(self.winprops)
                        else:
                            self.winprops.setCursorFilename(Filename.binaryFilename("empty-icon.ico"))
                            base.win.requestProperties(self.winprops)
                        break
        if j == -1:
            self.winprops.setCursorFilename(Filename.binaryFilename("question-icon.ico"))
            base.win.requestProperties(self.winprops)
        #print j
        return Task.cont
    
    def setupIntervals(self):
        self.lightOn = LerpFunc(self.lightModify,
                            fromData=0,
                            toData=100,
                            duration=0.2,
                            blendType='noBlend',
                            extraArgs=[True],
                            name="LightUp")
        self.lightOff = LerpFunc(self.lightModify,
                            fromData=0,
                            toData=100,
                            duration=0.2,
                            blendType='noBlend',
                            extraArgs=[False],
                            name="LightDown")
                            
        self.cameraMove = None
 
    def setKey(self, key, value):
        self.keyMap[key] = value
        
    def setWorldLight(self, object):
        object.setLight(self.keyLightNP)
        object.setLight(self.fillLightNP)
        object.setLight(self.boosterLightNP)
        for light in self.enemyLights:
            object.setLight(light)
        
    def setLights(self):
        self.setWorldLight(self.player)
        self.setWorldLight(self.env)
        for enemy in self.enemies:
            self.setWorldLight(enemy)
        for car in self.staticCars:
            self.setWorldLight(car)
        
    def shiftCamera(self):
        if self.cameraMove:
            self.cameraMove.finish()
        old = self.cameraIndex
        self.cameraIndex += 1
        if self.cameraIndex == len(self.cameraPositions):
            self.cameraIndex = 0
        self.cameraMove=LerpPosHprInterval(camera,
                                            .7, 
                                            self.cameraPositions[self.cameraIndex][0], 
                                            self.cameraPositions[self.cameraIndex][1],
                                            camera.getPos(), 
                                            camera.getHpr())
        self.cameraMove.start()
      
    def loadModels(self):
        self.player.setupBooster()
        self.env = loader.loadModel("ralph_models/final_terrain")      
        self.env.reparentTo(render)
        self.env.setScale(8)
        
        # Gas particles
        self.gasP = ParticleEffect()
        self.gasNode = self.player.attachNewNode('gasNode')
        
        # Node Map
        map = Node.NodeMap("nodes.txt")
            
        # enemies    
        self.enemies = []
        file = open('levels/enemies.txt' )
        line = file.readline().rstrip()
        
        self.staticCars = []
        self.gasList = []
        for currCar in carLocations.cars:
            target = loader.loadModel("ralph_models/" + currCar['color'] + "_car")
            target.setPos(currCar['position'])
            target.setHpr(currCar['direction'])
            target.reparentTo(self.staticRoot)
            self.staticCars.append(target)
            self.gasList.append(currCar['gas'])
            
        while line != "" :
            nums = line.split(',')
            convertedNums = []
            for i in range(len(nums)):
                if i != 0:
                    convertedNums.append(int(nums[i]))
            nodePos = map.nodeList[int(nums[0])].getPos()
            newEnemy = Enemy.Enemy(map, convertedNums, self, nodePos[0], nodePos[1], nodePos[2] )
            self.enemies.append( newEnemy )
            taskMgr.add(newEnemy.move, "Enemy Move " + str(i), extraArgs = [map], appendTask = True)
            line = file.readline().rstrip()
            i = i + 1
                  
    def loadSounds(self):
        self.flamethrowerSound = base.loader.loadSfx("sound/dragonflameloop2.wav")
        self.flamethrowerEndSound = base.loader.loadSfx("sound/dragonflameend.wav")
        self.collideSound = base.loader.loadSfx("sound/collide.wav")
        self.drainSound = base.loader.loadSfx("sound/gas_pump.wav")
        self.drainSound.setLoop(True)
        
    def setupLights(self):
        #ambient light
        self.ambientLight = AmbientLight("ambientLight")
        #four values, RGBA (alpha is largely irrelevent), value range is 0:1
        self.ambientLight.setColor((.30, .30, .30, 1))
        self.ambientLightNP = render.attachNewNode(self.ambientLight)
        #the nodepath that calls setLight is what gets illuminated by the light
        render.setLight(self.ambientLightNP)
        #call clearLight() to turn it off
        
        self.keyLight = DirectionalLight("keyLight")
        self.keyLight.setColor((.50,.50,.50, 1))
        self.keyLightNP = render.attachNewNode(self.keyLight)
        self.keyLightNP.setHpr(0, -26, 0)
        
        self.fillLight = DirectionalLight("fillLight")
        self.fillLight.setColor((.05,.05,.05, 1))
        self.fillLightNP = render.attachNewNode(self.fillLight)
        self.fillLightNP.setHpr(30, 0, 0)
               
    def setupCollisions(self):       
        base.cTrav = CollisionTraverser() 
        self.playerRay = CollisionRay()
        self.playerRay.setOrigin(0,0,1000)
        self.playerRay.setDirection(0,0,-1)
        self.playerNode = CollisionNode("playerRay")
        self.playerNode.addSolid(self.playerRay)
        self.playerNode.setFromCollideMask(BitMask32.bit(0))
        self.playerNode.setIntoCollideMask(BitMask32.allOff())
        self.playerNodePath = self.player.attachNewNode(self.playerNode)
        self.playerNodePath.show()
        self.playerGroundHandler = CollisionHandlerQueue()
        base.cTrav.addCollider(self.playerNodePath, self.playerGroundHandler)
        
        envcNode1 = CollisionNode("lot_bottom")
        envcNode1.setFromCollideMask(BitMask32.bit(0))
        temp = CollisionPolygon(Point3(12.56, 19.182, 0), Point3(12.56, -21.261, 0),
                                Point3(-13.217, -21.261, 0), Point3(-13.217, 19.182, 0))
        envcNode1.addSolid(temp)
        
        envcNode2 = CollisionNode("lot_ramp_bottom")
        envcNode2.setFromCollideMask(BitMask32.bit(0))
        temp = CollisionPolygon(Point3(32.715, -14.923, 3.5), Point3(32.715, -21.261, 3.5),
                                Point3(12.56, -21.261, 0), Point3(12.56, -14.923, 0))
        envcNode2.addSolid(temp)
        
        envcNode3 = CollisionNode("lot_middle")
        envcNode3.setFromCollideMask(BitMask32.bit(0))
        temp = CollisionPolygon(Point3(42.715, -14.923, 3.5), Point3(42.715, -21.261, 3.5),
                                Point3(32.715, -21.261, 3.5), Point3(32.715, -14.923, 3.5))
        envcNode3.addSolid(temp)
        
        envcNode4 = CollisionNode("lot_ramp_top")
        envcNode4.setFromCollideMask(BitMask32.bit(0))
        temp = CollisionPolygon(Point3(42.715, -8.845, 6), Point3(42.715, -14.923, 3.5),
                                Point3(32.715, -14.923, 3.5), Point3(32.715, -8.845, 6))
        envcNode4.addSolid(temp)
        
        envcNode5 = CollisionNode("lot_top")
        envcNode5.setFromCollideMask(BitMask32.bit(0))
        temp = CollisionPolygon(Point3(42.715, 16.155, 6), Point3(42.715, -8.845, 6),
                                Point3(17.715, -8.845, 6), Point3(17.715, 16.155, 6))
        envcNode5.addSolid(temp)
        
        wallCNode = CollisionNode("fence")
        wallCNode.setFromCollideMask(BitMask32.bit(0))
        temp = CollisionPolygon(Point3(12.56, 19.182, 0), Point3(12.56, -14.923, 0),
                                Point3(12.56, -14.923, 10), Point3(12.56, 19.182, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(12.56, -14.923, 0), Point3(32.715, -14.923, 3.5),
                                Point3(32.715, -14.923, 10), Point3(12.56, -14.923, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(32.715, -14.923, 3.5), Point3(32.715, -8.845, 6),
                                Point3(32.715, -8.845, 10), Point3(32.715, -14.923, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(32.715, -8.845, 6), Point3(17.715, -8.845, 6),
                                Point3(17.715, -8.845, 10), Point3(32.715, -8.845, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(17.715, -8.845, 6), Point3(17.715, 16.155, 6),
                                Point3(17.715, 16.155, 10), Point3(17.715, -8.845, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(17.715, 16.155, 6), Point3(42.715, 16.155, 6),
                                Point3(42.715, 16.155, 10), Point3(17.715, 16.155, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(42.715, 16.155, 6), Point3(42.715, -8.845, 6),
                                Point3(42.715, -8.845, 10), Point3(42.715, 16.155, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(42.715, -8.845, 6), Point3(42.715, -14.923, 3.5),
                                Point3(42.715, -14.923, 10), Point3(42.715, -8.845, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(42.715, -14.923, 3.5), Point3(42.715, -21.261, 3.5),
                                Point3(42.715, -21.261, 10), Point3(42.715, -14.923, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(42.715, -21.261, 3.5), Point3(32.715, -21.261, 3.5),
                                Point3(32.715, -21.261, 10), Point3(42.715, -21.261, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(32.715, -21.261, 3.5), Point3(12.56, -21.261, 0),
                                Point3(12.56, -21.261, 10), Point3(32.715, -21.261, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(12.56, -21.261, 0), Point3(-13.217, -21.261, 0),
                                Point3(-13.217, -21.261, 10), Point3(12.56, -21.261, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(-13.217, -21.261, 0), Point3(-13.217, 19.182, 0),
                                Point3(-13.217, 19.182, 10), Point3(-13.217, -21.261, 10))
        wallCNode.addSolid(temp)
        temp = CollisionPolygon(Point3(-13.217, 19.182, 0), Point3(12.56, 19.182, 0),
                                Point3(12.56, 19.182, 10), Point3(-13.217, 19.182, 10))
        wallCNode.addSolid(temp)
        
        
        envcNodePath1 = self.env.attachNewNode(envcNode1)
        envcNodePath2 = self.env.attachNewNode(envcNode2)
        envcNodePath3 = self.env.attachNewNode(envcNode3)
        envcNodePath4 = self.env.attachNewNode(envcNode4)
        envcNodePath5 = self.env.attachNewNode(envcNode5)
        
        self.cHandler = CollisionHandlerEvent()
        pusher = CollisionHandlerPusher()
        
        self.wallNode = self.env.attachNewNode('wallNode')
        wallCNodePath = self.wallNode.attachNewNode(wallCNode)
        if DEBUG:
            wallCNodePath.show()
            
        cNode = CollisionNode("player")
        temp = CollisionSphere((0,-5.5,10), 4)
        cNode.addSolid(temp)
        temp = CollisionSphere((0,-0.5,10), 4)
        cNode.addSolid(temp)
        temp = CollisionSphere((0,3.5,10), 4)
        cNode.addSolid(temp)
        cNode.setIntoCollideMask(BitMask32.allOff()) #player is *only* a from object
        cNodePath = self.player.attachNewNode(cNode)
        
        if DEBUG:
            cNodePath.show()
            
        base.cTrav.addCollider(cNodePath, pusher)
        pusher.addCollider(cNodePath, self.player)
        pusher.addInPattern('%fn-into-%in')
        self.accept('player-into-fence', self.collideWithFence)
        self.accept('player-into-staticCar', self.collideOther)
        self.accept('player-into-droneNode', self.collideOther)
        
        self.playerLightCollision = CollisionHandlerEvent()
        self.playerLightCollision.addInPattern('into-%in')
        
        cNode2 = CollisionNode("playerinto")
        
        #cNode.addSolid(segment1)
        #cNode.addSolid(segment2)
        #cNode.addSolid(segment3)
        #cNode.addSolid(segment4)
        temp = CollisionSphere((0,-5.5,1), 4)
        cNode2.addSolid(temp)
        temp = CollisionSphere((0,-0.5,1), 4)
        cNode2.addSolid(temp)
        temp = CollisionSphere((0,3.5,1), 4)
        cNode2.addSolid(temp)
        cNode2.setFromCollideMask(BitMask32.allOff()) #player is *only* a from object
        cNodePath2 = self.player.attachNewNode(cNode2)
        if DEBUG:
            cNodePath2.show()
        
        # FLAMETHROWER COLLISIONS
        # left
        flamethrowerLeft = CollisionSegment()
        flamethrowerLeft.setPointA(-2 , -4, 10)
        flamethrowerLeft.setPointB( -2 , -20 , 10 ) 
        
        # middle
        flamethrowerMiddle = CollisionSegment()
        flamethrowerMiddle.setPointA(0 , -4, 10)
        flamethrowerMiddle.setPointB( 0 , -20 , 10 ) 
        
        # right
        flamethrowerRight = CollisionSegment()
        flamethrowerRight.setPointA(2, -4, 10)
        flamethrowerRight.setPointB( 2 , -20 , 10 ) 
        
        flamethrowerNode = CollisionNode("flamethrower")
        flamethrowerNode.addSolid(flamethrowerLeft)
        flamethrowerNode.addSolid(flamethrowerMiddle)
        flamethrowerNode.addSolid(flamethrowerRight)
        flamethrowerNode.setIntoCollideMask(BitMask32.allOff())
        flamethrowerNode.setFromCollideMask(BitMask32.allOn())
        flamethrowerNodePath = self.player.attachNewNode(flamethrowerNode)
        
        #flamethrowerNodePath.show()
        
        self.flamethrowerCollision = CollisionHandlerEvent()
        self.flamethrowerCollision.addInPattern('into-%in')
        base.cTrav.addCollider(flamethrowerNodePath, self.flamethrowerCollision)
        self.accept('into-droneNode', self.hitEnemy)
        
        for i in range(len(self.staticCars)):
            staticNode = CollisionNode("staticCar")
            temp = CollisionSphere((0,-5.2,10), 4)
            staticNode.addSolid(temp)
            temp = CollisionSphere((0,-0.5,10), 4)
            staticNode.addSolid(temp)
            temp = CollisionSphere((0,5.5,10), 4)
            staticNode.addSolid(temp)
            staticNode.setIntoCollideMask(BitMask32.bit(1))
            staticNode.setFromCollideMask(BitMask32.bit(0))
            staticNodePath = self.staticCars[i].attachNewNode(staticNode)
            temp = CollisionTube(0,7,3,0,-6,3,3.5)
            sN = CollisionNode("staticTube")
            sN.addSolid(temp)
            staticNode.setFromCollideMask(BitMask32.bit(0))
            sNP = self.staticCars[i].attachNewNode(sN)
            sN.setTag('car', str(i))
            
        self.enemyHandler = CollisionHandlerEvent()    
        for i in range(len(self.enemies)):
            collideNode = CollisionNode("droneNode")
            temp = CollisionSphere((0,0,10), 4)
            collideNode.addSolid(temp)
            collideNode.setIntoCollideMask(BitMask32.bit(1))
            collideNode.setFromCollideMask(BitMask32.bit(0))
            enemycollideNodePath = self.enemies[i].attachNewNode(collideNode)
            
            collideNode.setTag('enemy',str(i))
            
            self.enemies[i].lightRay = CollisionSegment()
            self.enemies[i].lightRay.setPointA(0, -4, 4)
            self.enemies[i].lightRay.setPointB( 0 , -100 , 0 ) 
            
            # left
            self.enemies[i].lightRayLeft = CollisionSegment()
            self.enemies[i].lightRayLeft.setPointA(0, -4, 4)
            self.enemies[i].lightRayLeft.setPointB( -5 , -100 , 0 ) 
            
            # right
            self.enemies[i].lightRayRight = CollisionSegment()
            self.enemies[i].lightRayRight.setPointA(0, -4, 4)
            self.enemies[i].lightRayRight.setPointB( 5 , -100 , 0 ) 
            
            self.enemies[i].lightRayNode = CollisionNode("lightRay")
            self.enemies[i].lightRayNode.addSolid(self.enemies[i].lightRay)
            self.enemies[i].lightRayNode.addSolid(self.enemies[i].lightRayLeft)
            self.enemies[i].lightRayNode.addSolid(self.enemies[i].lightRayRight)
            
            self.enemies[i].lightRayNode.setTag('enemy',str(i))
            
            self.enemies[i].lightRayNode.setIntoCollideMask(BitMask32.allOff())
            self.enemies[i].lightRayNodePath = self.enemies[i].attachNewNode(self.enemies[i].lightRayNode)
            if DEBUG:
                self.enemies[i].lightRayNodePath.show()
            
            base.cTrav.addCollider(self.enemies[i].lightRayNodePath, self.playerLightCollision)
        self.accept('into-playerinto', self.player.takeHit)
    
    def collideWithFence(self, entry):
        self.player.speed = self.player.speed * 0.9
        if self.collideSound.status() != AudioSound.PLAYING:
            self.collideSound.play()
    
    def collideOther(self, entry):
        self.player.speed = self.player.speed * 0.9
        if self.collideSound.status() != AudioSound.PLAYING:
            self.collideSound.play()
        
    def lightModify(self, t, which_way):

        if which_way: #which_way == true then make it brighter
            value = t/100 * MAX_LIGHT
        else: #which_way == true then make it darker
            value = (100 - t)/100 * MAX_LIGHT
        for light in self.flameLights:
            light[0].setColor(VBase4(value,value,value,1))
        
    def startShoot(self):
        self.loadParticleConfig('flamethrower6.ptf')
        #self.lightOff.finish()
        #self.lightOn.start()
        
        #Get the flame noise started!
        self.flamethrowerSound.setLoop(True)
        self.flamethrowerSound.play()
        self.flamethrowerActive = True
        self.draining = False
        self.gasLossRate = 2.0
        
    def stopShoot(self):
        self.p1.softStop()
        self.p2.softStop()
        #self.lightOn.finish()
        #self.lightOff.start()
        
        self.flamethrowerSound.stop()
        self.flamethrowerEndSound.play()
        self.flamethrowerActive = False
        self.gasLossRate = 1.0
        
    def hitEnemy(self, entry):
        if self.flamethrowerActive:
            index = int(entry.getIntoNode().getTag('enemy'))
            if self.enemies[index].phase != STOPPED:
                self.enemies[index].prevPhase = self.enemies[index].phase
                self.enemies[index].phase = STOPPED
                self.enemies[index].headlight1.setColor(VBase4(0, 0, 0, 0))
        
    def loadParticleConfig(self, file):
        self.p1.reset()
        self.p1 = ParticleEffect()
        self.p1.loadConfig(Filename(file))        
        self.p1.start(self.player)
        self.p1.setPos(-1.75, -10, 1.375)
        self.p1.setHpr(0, 90, 0)
        self.p1.setScale(2.0)
        self.p1.setLightOff()
        self.p2.reset()
        self.p2 = ParticleEffect()
        self.p2.loadConfig(Filename(file))        
        self.p2.start(self.player)
        self.p2.setPos(1.75, -10, 1.375)
        self.p2.setHpr(0, 90, 0)
        self.p2.setScale(2.0)
        self.p2.setLightOff()
        
    def eat(self, cEntry):
        """handles the player eating a smiley"""
        #remove target from list of targets
        self.targets.remove(cEntry.getIntoNodePath().getParent())
        #remove from scene graph
        cEntry.getIntoNodePath().getParent().remove()
           
    def changeMouseCursor(self, cursorFile):
        if self.currIcon != cursorFile:
            self.currIcon = cursorFile
            # winprops.getParentWindow().getXSize()
            # print winprops.getXSize()
            # print "test"
            self.winprops.setCursorFilename(Filename.binaryFilename(cursorFile))
    
    def deathChecker(self, task):
        font = loader.loadFont('fonts/beneg.ttf')

        #Check for out of time
        currTime = datetime.datetime.now()
        if currTime > self.startTime + self.timeLimit or self.player.totalGas >= MAX_GAS:
            #print "OUT OF TIME!!!!!!!!!!!"

            if self.finalGas is None:
                self.finalGas = self.player.totalGas
            
            taskMgr.doMethodLater(5, self.STOPGAME, 'tickTask')
            self.loading = OnscreenImage(image = 'images/victory.png', scale = (1.3333333,0, 1))
            self.text = OnscreenText(text = "Gas Collected%s" %(self.finalGas), font = font, pos = (0,.2), fg = (255,255,255,1))
        #Check for death
        elif self.player.dead:
            if self.finalGas is None:
                self.finalGas = self.player.totalGas

            #print "THE PLAYER IS DEAD!!!!!!!!!!"
            taskMgr.doMethodLater(5, self.STOPGAME, 'tickTask')
            self.loading = OnscreenImage(image = 'images/lose_death.png', scale = (1.3333333,0, 1))
            self.text = OnscreenText(text = "Gas Collected %s" %(self.finalGas), font = font, pos = (0,.1), fg = (255,255,255,1))
        elif self.player.totalGas <= 0:
            #print "YOU SUCK. YOU RAN OUT OF GAS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
            taskMgr.doMethodLater(5, self.STOPGAME, 'tickTask')
            self.loading = OnscreenImage(image = 'images/lose_nogas.png', scale = (1.3333333,0, 1))
        return Task.cont

        
    def updateGasBar(self, task):
        self.gasLevel['frameSize'] = (-1,(self.player.totalGas / MAX_GAS)*2 - 1, -1, 1)
        return Task.cont
    def STOPGAME(self, SOMETHNG):
        taskMgr.stop()
예제 #21
0
파일: start.py 프로젝트: leohen/pandaMorp
class MyApp(ShowBase):
 
    def __init__(self):
        ShowBase.__init__(self)
        self.disableMouse()  
        camera.setPosHpr(0, -12, 8, 0, -35, 0)
        """
        self.environ = self.loader.loadModel("models/environment")
        # Reparent the model to render.
        self.environ.reparentTo(self.render)
        # Apply scale and position transforms on the model.
        self.environ.setScale(0.25, 0.25, 0.25)
        self.environ.setPos(-8, 42, 0)
        self.torus = loader.loadModel("torus.egg")
        self.torus.reparentTo(self.render)
        self.torus.setPos(circPos(0,1))
        self.torus.setColor(BLACK)
        self.torus.setScale(0.5,0.5,0.5)
        """
        self.setupLights()
        self.ended = False
        self.currentB = False
        self.firstTurn = True
        # Since we are using collision detection to do picking, we set it up like
        # any other collision detection system with a traverser and a handler
        self.picker = CollisionTraverser()  # Make a traverser
        self.pq = CollisionHandlerQueue()  # Make a handler
        # Make a collision node for our picker ray
        self.pickerNode = CollisionNode('mouseRay')
        # Attach that node to the camera since the ray will need to be positioned
        # relative to it
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        # Everything to be picked will use bit 1. This way if we were doing other
        # collision we could seperate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()  # Make our ray
        # Add it to the collision node
        self.pickerNode.addSolid(self.pickerRay)
        # Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)
        self.picker.showCollisions(render)
        self.whiteTurn = True
        # Now we create the chess board and its pieces

        # We will attach all of the squares to their own root. This way we can do the
        # collision pass just on the sqaures and save the time of checking the rest
        # of the scene
        self.batonsRoot = render.attachNewNode("batonsRoot")
        self.batons = [None for i in range(9)]
        self.torus = [[None for j in range(3)] for i in range(9)]
        self.org = [[[None for j in range(3)] for i in range(3)] for i in range(3)]
        for i in range(9):
            # Load, parent, color, and position the model (a single square
            # polygon)
            self.batons[i] = loader.loadModel("bois.egg")
            self.batons[i].reparentTo(self.batonsRoot)
            self.batons[i].setPos(circPos(i,0))
            self.batons[i].setColor(0.75,0.5,0)
            self.batons[i].setScale(0.75,0.75,0.5)
            # Set the model itself to be collideable with the ray. If this model was
            # any more complex than a single polygon, you should set up a collision
            # sphere around it instead. But for single polygons this works
            # fine.
            self.batons[i].find("**/Cylinder").node().setIntoCollideMask(
                BitMask32.bit(1))
            # Set a tag on the square's node so we can look up what square this is
            # later during the collision pass
            self.batons[i].find("**/Cylinder").setTag('baton', str(i))

            # We will use this variable as a pointer to whatever piece is currently
            # in this square
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
        self.accept("mouse1", self.click)
        self.accept("w", self.bestPossibleMove)
    def setupLights(self):  # This function sets up some default lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.8, .8, .8, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(LVector3(0, 45, -45))
        directionalLight.setColor((0.2, 0.2, 0.2, 1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(ambientLight))
    def mouseTask(self, task):
        # This task deals with the highlighting and dragging based on the mouse

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

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

            if self.currentB is not False:
                self.batons[self.currentB].setColor(0.75,0.5,0)
                self.currentB = False

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

        return Task.cont
    def click(self):
        if self.currentB is not False and not self.ended:
            self.addTorus(self.currentB)
    def testMorp(self, z, y, x):
        print(z,y,x)
        print([j for j in [self.org[w][y][w]for w in range(3)]if j == None])
        print([j for j in [self.org[w][y][w]for w in range(3)]if j == False])
        print(len([j for j in [self.org[w][y][w]for w in range(3)]if j == False]))
        if len([j for j in self.org[z][y] if j == None]) == 0:
            if len([j for j in self.org[z][y] if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in self.org[z][y] if j == True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j  for j in [self.org[z][w][x]for w in range(3)] if j == None]) == 0:
            if len([j  for j in [self.org[z][w][x]for w in range(3)] if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j  for j in [self.org[z][w][x]for w in range(3)] if j == True]) == 0:
                self.ended = True
                return "blackWin"
                
        if len([j  for j in [self.org[w][y][x]for w in range(3)] if j==None]) == 0:
            if len([j  for j in [self.org[w][y][x]for w in range(3)] if j==False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j  for j in [self.org[w][y][x]for w in range(3)] if j==True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j for j in [self.org[z][w][w]for w in range(3)]if j == None]) == 0:
            if len([j for j in [self.org[z][w][w]for w in range(3)]if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in [self.org[z][w][w]for w in range(3)]if j == True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j for j in [self.org[z][w][2 - w]for w in range(3)]if j == None]) == 0:
            if len([j for j in [self.org[z][w][2 - w]for w in range(3)]if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in [self.org[z][w][2 - w]for w in range(3)]if j == True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j for j in [self.org[w][w][x]for w in range(3)]if j == None]) == 0:
            if len([j for j in [self.org[w][w][x]for w in range(3)]if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in [self.org[w][w][x]for w in range(3)]if j == True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j for j in [self.org[w][2-w][x]for w in range(3)]if j == None]) == 0:
            if len([j for j in [self.org[w][2-w][x]for w in range(3)]if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in [self.org[w][2-w][x]for w in range(3)]if j == True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j for j in [self.org[w][y][w]for w in range(3)]if j == None]) == 0:
            print("wyw")
            if len([j for j in [self.org[w][y][w]for w in range(3)]if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in [self.org[w][y][w]for w in range(3)]if j == True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j for j in [self.org[2-w][y][w]for w in range(3)]if j == None]) == 0:
            if len([j for j in [self.org[2-w][y][w]for w in range(3)]if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in [self.org[2-w][y][w]for w in range(3)]if j == True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j for j in [self.org[w][w][w]for w in range(3)]if j == None]) == 0:
            if len([j for j in [self.org[w][w][w]for w in range(3)]if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in [self.org[w][w][w]for w in range(3)]if j == True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j for j in [self.org[2-w][w][w]for w in range(3)]if j == None]) == 0:
            if len([j for j in [self.org[2-w][w][w]for w in range(3)]if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in [self.org[2-w][w][w]for w in range(3)]if j == True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j for j in [self.org[w][w][2-w]for w in range(3)]if j == None]) == 0:
            if len([j for j in [self.org[w][w][2-w]for w in range(3)]if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in [self.org[w][w][2-w]for w in range(3)]if j == True]) == 0:
                self.ended = True
                return "blackWin"
        if len([j for j in [self.org[2-w][w][2-w]for w in range(3)]if j == None]) == 0:
            if len([j for j in [self.org[2-w][w][2-w]for w in range(3)]if j == False]) == 0:
                self.ended = True
                return "whiteWin"
            elif len([j for j in [self.org[2-w][w][2-w]for w in range(3)]if j == True]) == 0:
                self.ended = True
                return "blackWin"
        
            
        return "launched"
    def addTorus(self, i):
        minim = False
        for j,x in enumerate(self.torus[i]):
            if x is None:
                minim = j
                break
        if minim is not False:
            print(minim)
            print(self.whiteTurn)
            print()
            if (self.whiteTurn and not self.firstTurn) or  (self.firstTurn and not (minim == 0 and i//3 == 1 and i%3 == 1)):
                self.torus[i][minim] = loader.loadModel("torus.egg")
                self.torus[i][minim].reparentTo(self.render)
                self.torus[i][minim].setPos(circPos(i,j-1))
                self.torus[i][minim].setColor(WHITE)
                self.torus[i][minim].setScale(0.75,0.75,1.5)
                self.org[minim][i//3][i%3] = self.whiteTurn
                self.whiteTurn = not self.whiteTurn
                if self.firstTurn:
                    self.firstTurn = False
            elif not self.firstTurn:
                self.torus[i][minim] = loader.loadModel("torus.egg")
                self.torus[i][minim].reparentTo(self.render)
                self.torus[i][minim].setPos(circPos(i,j-1))
                self.torus[i][minim].setColor(BLACK)
                self.torus[i][minim].setScale(0.75,0.75,1.5)
                self.org[minim][i//3][i%3] = self.whiteTurn
                self.whiteTurn = not self.whiteTurn
            
            print(self.testMorp(minim, i//3, i%3))
    def possibleMoves(self, state, first):
        possibilities = []
        for r in range(9):
            if (((r is not 4) and first) or (not first)) and state[2][r//3][r%3] == None:
                possibilities.append(r)
        return possibilities
    def bestPossibleMove(self):
        temp = state
        for p in possibleMoves(self, state, first):
            p = 0
    def valeurBranche(self, state, first, Wturn, n):
        vblancs = 0
        vnoirs = 0
        pos = [None for p in possibleMoves(self, state, first) ]
        depth = pos
        for i,p in enumerate(possibleMoves(self, state, first)):
            tempEtat = addTorustemp(p, WTurn, state)
            temp = testMorptemp(tempEtat)
            if temp == 1 and Wturn:
                pos[i] = 1
                depth[i] = n + 1
            elif temp ==0 and Wturn:
                if first:
                    temp2 = valeurBranche(self, temp,not first, not Wturn,n+1)
                    if not (temp2[0] == 0):
                        pos[i] = -temp2[0]
                        depth[i] = temp2[1]
                    else:
                        pos[i] = 0
                        depth[i] = temp2[1]
                else:
                    temp2 = valeurBranche(self, temp, first, not Wturn,n+1)
                    if not (temp2[0] == 0):
                        pos[i] = -temp2[0]
                        depth[i] = temp2[1]
                    else :
                        pos[i] = 0
                        depth[i] = temp2[1]
            elif temp == 2 and (not Wturn):
                pos[i] = 1
            elif temp ==0 and (not Wturn):
                if first:
                    temp2 = valeurBranche(self, temp,not first, not Wturn,n+1)
                    if not (temp2[0] == 0):
                        pos[i] = -temp2[0]
                        depth[i] = temp2[1]
                    else:
                        pos[i] = 0
                        depth[i] = temp2[1]
                else:
                    temp2 = valeurBranche(self, temp, first, not Wturn,n+1)
                    if not (temp2[0] == 0):
                        pos[i] = -temp2[0]
                        depth[i] = temp2[1]
                    else :
                        pos[i] = 0
                        depth[i] = temp2[1]
            else:
                print("tu sais pas coder guillaume")
        if pos == []:
            return (0, n)
        else:
            vic = []
            zero = []
            for i,j in enumerate(pos):
                if j == 1:
                    vic.append(i)
                elif j == 0:
                    zero.append(i)
            if vic is not []:
                return 1, n
            elif zero is not []:
                dmax = 0
                for i in zero:
                    if depth[i] > dmax:
                        dmax = depth[i]
                return 0, dmax
            else:
                return -1, n
                
            
            
                
    def addTorustemp(self, i, whiteTurn, state):
        minim = False
        temp = state
        for j,x in enumerate([state[w][i//3][i%3] for w in range(3)]):
            if x is None:
                minim = j
                break
        if minim is not False:
            print(minim)
            print(whiteTurn)
            temp[minim][i//3][i%3] = whiteTurn
            return temp
    def testMorptemp(self, torg):
        for m in range(27):
            z = m//9
            y = m//3
            x = m%3
            if len([j for j in torg[z][y] if j == None]) == 0:
                if len([j for j in torg[z][y] if j == False]) == 0:
                    return 1
                elif len([j for j in torg[z][y] if j == True]) == 0:
                    return 2
            if len([j  for j in [torg[z][w][x]for w in range(3)] if j == None]) == 0:
                if len([j  for j in [torg[z][w][x]for w in range(3)] if j == False]) == 0:
                    return 1
                elif len([j  for j in [torg[z][w][x]for w in range(3)] if j == True]) == 0:
                    return 2
            if len([j  for j in [torg[w][y][x]for w in range(3)] if j==None]) == 0:
                if len([j  for j in [torg[w][y][x]for w in range(3)] if j==False]) == 0:
                    return 1
                elif len([j  for j in [torg[w][y][x]for w in range(3)] if j==True]) == 0:
                    return 2
            if len([j for j in [torg[z][w][w]for w in range(3)]if j == None]) == 0:
                if len([j for j in [torg[z][w][w]for w in range(3)]if j == False]) == 0:
                    return 1
                elif len([j for j in [torg[z][w][w]for w in range(3)]if j == True]) == 0:
                    return 2
            if len([j for j in [torg[z][w][2 - w]for w in range(3)]if j == None]) == 0:
                if len([j for j in [torg[z][w][2 - w]for w in range(3)]if j == False]) == 0:
                    return 1
                elif len([j for j in [torg[z][w][2 - w]for w in range(3)]if j == True]) == 0:
                    return 2
            if len([j for j in [torg[w][w][x]for w in range(3)]if j == None]) == 0:
                if len([j for j in [torg[w][w][x]for w in range(3)]if j == False]) == 0:
                    return 1
                elif len([j for j in [torg[w][w][x]for w in range(3)]if j == True]) == 0:
                    return 2
            if len([j for j in [torg[w][2-w][x]for w in range(3)]if j == None]) == 0:
                if len([j for j in [torg[w][2-w][x]for w in range(3)]if j == False]) == 0:
                    return 1
                elif len([j for j in [torg[w][2-w][x]for w in range(3)]if j == True]) == 0:
                    return 2
            if len([j for j in [torg[w][y][w]for w in range(3)]if j == None]) == 0:
                if len([j for j in [torg[w][y][w]for w in range(3)]if j == False]) == 0:
                    return 1
                elif len([j for j in [torg[w][y][w]for w in range(3)]if j == True]) == 0:
                    return 2
            if len([j for j in [torg[2-w][y][w]for w in range(3)]if j == None]) == 0:
                if len([j for j in [torg[2-w][y][w]for w in range(3)]if j == False]) == 0:
                    return 1
                elif len([j for j in [torg[2-w][y][w]for w in range(3)]if j == True]) == 0:
                    return 2
            if len([j for j in [torg[w][w][w]for w in range(3)]if j == None]) == 0:
                if len([j for j in [torg[w][w][w]for w in range(3)]if j == False]) == 0:
                    return 1
                elif len([j for j in [torg[w][w][w]for w in range(3)]if j == True]) == 0:
                    return 2
            if len([j for j in [torg[2-w][w][w]for w in range(3)]if j == None]) == 0:
                if len([j for j in [torg[2-w][w][w]for w in range(3)]if j == False]) == 0:
                    return 1
                elif len([j for j in [torg[2-w][w][w]for w in range(3)]if j == True]) == 0:
                    return 2
            if len([j for j in [torg[w][w][2-w]for w in range(3)]if j == None]) == 0:
                if len([j for j in [torg[w][w][2-w]for w in range(3)]if j == False]) == 0:
                    return 1
                elif len([j for j in [torg[w][w][2-w]for w in range(3)]if j == True]) == 0:
                    return 2
            if len([j for j in [torg[2-w][w][2-w]for w in range(3)]if j == None]) == 0:
                if len([j for j in [torg[2-w][w][2-w]for w in range(3)]if j == False]) == 0:
                    return 1
                elif len([j for j in [torg[2-w][w][2-w]for w in range(3)]if j == True]) == 0:
                    return 2
        
            return 0
예제 #22
0
class World(DirectObject):
    def __init__(self):
        #turn off mouse control, otherwise camera is not repositionable
        self.lightables = []
        self.cameraPositions = [((0, 5000, 5300), (180, -35, 0)),((0, 3000, 1300), (180, -15, 0))]
        self.cameraIndex = 0
        base.disableMouse()
        base.enableParticles()
        self.setupLights()
        self.setupPicking()
        #Prepare the vehicular manslaughter!
        self.boosterLightNP = None
        self.flameLights = None
        self.player = Vehicle("models/panda-model", "panda-walk4", self)
        
        self.loadModels()
        # self.player.setPos(self.env.find("**/start_point").getPos())
        self.player.setPos(0,0,0)
        self.setupIntervals()
        camera.reparentTo(self.player)
        camera.setPosHpr(0, 5000, 5300, 180, -35, 0)
        self.setupCollisions()
        render.setShaderAuto() #you probably want to use this
        self.keyMap = {"left":0, "right":0, "forward":0, "backwards":0}
        taskMgr.add(self.player.move, "moveTask")
        
        #Give the vehicle direct access to the keyMap
        self.player.addKeyMap(self.keyMap)
        
        self.prevtime = 0
        self.isMoving = False
        self.speed_norm = 8
        self.speed = self.speed_norm
        self.accept("escape", sys.exit)
        
        self.accept("arrow_up", self.setKey, ["forward", 1])
        self.accept("w", self.setKey, ["forward", 1])
        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("d", self.setKey, ["right", 1])
        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("a", self.setKey, ["left", 1])
        self.accept("arrow_down", self.setKey, ["backwards", 1])
        self.accept("s", self.setKey, ["backwards", 1])
        
        self.accept("arrow_up-up", self.setKey, ["forward", 0])
        self.accept("w-up", self.setKey, ["forward", 0])
        self.accept("arrow_right-up", self.setKey, ["right", 0])
        self.accept("d-up", self.setKey, ["right", 0])
        self.accept("arrow_left-up", self.setKey, ["left", 0])
        self.accept("a-up", self.setKey, ["left", 0])
        self.accept("arrow_down-up", self.setKey, ["backwards", 0])
        self.accept("s-up", self.setKey, ["backwards", 0])
        
        self.accept("mouse1", self.startShoot)
        self.accept("mouse1-up", self.stopShoot)
        self.accept("tab", self.shiftCamera)   
        self.accept("space", self.player.startBoosters)
        
        self.accept("ate-smiley", self.eat)
        self.accept("ground_collide", self.player.collider)
        self.p1 = ParticleEffect()
        self.p2 = ParticleEffect()
        
        #Show collisiony stuff
        base.cTrav.showCollisions(render)
        
    
    def setupPicking(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)
        
        self.targetRoot = render.attachNewNode('targetRoot')
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')
    
    def mouseTask(self, task):
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            self.picker.traverse(self.targetRoot)
            if self.pq.getNumEntries() > 0:
                self.pq.sortEntries()
                i = int(self.pq.getEntry(0).getIntoNode().getTag('target'))
                print("Found target: " + str(i))
                  
        return Task.cont

    def setupIntervals(self):
        self.lightOn = LerpFunc(self.lightModify,
                            fromData=0,
                            toData=100,
                            duration=0.2,
                            blendType='noBlend',
                            extraArgs=[True],
                            name="LightUp")
        self.lightOff = LerpFunc(self.lightModify,
                            fromData=0,
                            toData=100,
                            duration=0.2,
                            blendType='noBlend',
                            extraArgs=[False],
                            name="LightDown")
                            
        self.cameraMove = None
        
    def setKey(self, key, value):
        self.keyMap[key] = value
        
    def setWorldLight(self, object):
        self.lightables.append(object)
        object.setLight(self.keyLightNP)
        object.setLight(self.fillLightNP)
        object.setLight(self.boosterLightNP)
        for light in self.flameLights:
            object.setLight(light[1])
        
    def shiftCamera(self):
        if self.cameraMove:
            self.cameraMove.finish()
        old = self.cameraIndex
        self.cameraIndex += 1
        if self.cameraIndex == len(self.cameraPositions):
            self.cameraIndex = 0
        self.cameraMove=LerpPosHprInterval(camera,
                                            .7, 
                                            self.cameraPositions[self.cameraIndex][0], 
                                            self.cameraPositions[self.cameraIndex][1],
                                            camera.getPos(), 
                                            camera.getHpr())
        self.cameraMove.start()
     
    def loadModels(self):
        """loads models into the world"""
        #eat no longer exists? Phooey
        
        self.flameLights = []
        shadowcam = Spotlight('shadowlight')
        shadowcam.setColor(VBase4(0,0,0,1))
        lens = PerspectiveLens()
        shadowcam.setLens(lens)
        shadowcam.setAttenuation(Point3(0, 0.001, 0.001))
        shadowNP = self.player.attachNewNode(shadowcam)
        shadowNP.setPos(0, -1400, 450)
        shadowNP.lookAt(self.player)
        shadowNP.setScale(200)
        shadowNP.node().setShadowCaster(True)
        self.flameLights.append((shadowcam, shadowNP))
        
        for i in range(2):
            slight = PointLight('plight')
            slight.setColor(VBase4(0, 0, 0, 1))
            slight.setAttenuation(Point3(0, 0.001, 0.001))
            slnp = self.player.attachNewNode(slight)
            slnp.setPos(0, -750 - (950 * i), 450)
            slnp.setHpr(180, 0, 0)
            slnp.setScale(200)
            self.flameLights.append((slight, slnp))
        
        self.player.setupBooster()
        
        #self.env = loader.loadModel("models/environment")
        #self.env.reparentTo(render)
        #self.env.setScale(.25)
        #self.env.setPos(-8, 42, 0)
        self.env = loader.loadModel("models/terrain2")      
        self.env.reparentTo(render)
        self.env.setPos(0,0,0)
        
        self.setWorldLight(self.env)
        
        #load targets
        self.targets = []
        for i in range (10):
            target = loader.loadModel("smiley")
            target.setScale(.5)
            target.setPos(random.uniform(-20, 20), random.uniform(-15, 15), 2)
            target.reparentTo(self.targetRoot)
            self.targets.append(target)
            self.setWorldLight(target)
        
    def setupLights(self):
        #ambient light
        self.ambientLight = AmbientLight("ambientLight")
        #four values, RGBA (alpha is largely irrelevent), value range is 0:1
        self.ambientLight.setColor((.10, .10, .10, 1))
        self.ambientLightNP = render.attachNewNode(self.ambientLight)
        #the nodepath that calls setLight is what gets illuminated by the light
        render.setLight(self.ambientLightNP)
        #call clearLight() to turn it off
        
        self.keyLight = DirectionalLight("keyLight")
        self.keyLight.setColor((.20,.20,.20, 1))
        self.keyLightNP = render.attachNewNode(self.keyLight)
        self.keyLightNP.setHpr(0, -26, 0)
        
        self.fillLight = DirectionalLight("fillLight")
        self.fillLight.setColor((.05,.05,.05, 1))
        self.fillLightNP = render.attachNewNode(self.fillLight)
        self.fillLightNP.setHpr(30, 0, 0)
        
    def drive(self):
        """compound interval for driveing"""
        #some interval methods:
        # start(), loop(), pause(), resume(), finish()
        # start() can take arguments: start(starttime, endtime, playrate)
        dist = 5
        angle = deg2Rad(self.player.getH())
        dx = dist * math.sin(angle)
        dy = dist * -math.cos(angle)
        playerdrive = Parallel(self.player.posInterval(1, (self.player.getX() + dx, self.player.getY() + dy, 0)), \
            self.player.actorInterval("drive", loop=1, duration=2))
        playerdrive.start()
        
    def setupCollisions(self):
        #instantiates a collision traverser and sets it to the default
        base.cTrav = CollisionTraverser()
        self.cHandler = CollisionHandlerEvent()
        #set pattern for event sent on collision
        # "%in" is substituted with the name of the into object
        self.cHandler.setInPattern("ate-%in")
        
        cSphere = CollisionSphere((0,0,200), 450) #because the player is scaled way down
        self.playerRay = CollisionRay()
        self.playerRay.setOrigin(0,0,2000)
        self.playerRay.setDirection(0,0,-1)
        self.playerNode = CollisionNode("playerRay")
        self.playerNode.addSolid(self.playerRay)
        self.playerNode.setFromCollideMask(BitMask32.bit(0))
        self.playerNode.setIntoCollideMask(BitMask32.allOff())
        self.playerNodePath = self.player.attachNewNode(self.playerNode)
        self.playerNodePath.show()
        self.playerGroundHandler = CollisionHandlerFloor()
        self.playerGroundHandler.addCollider(self.playerNodePath, self.player)
        base.cTrav.addCollider(self.playerNodePath, self.playerGroundHandler)
        
        cNode = CollisionNode("player")
        cNode.addSolid(cSphere)
        cNode.setIntoCollideMask(BitMask32.allOff()) #player is *only* a from object
        #cNode.setFromCollideMask(BitMask32.bit(0))
        cNodePath = self.player.attachNewNode(cNode)
        #registers a from object with the traverser with a corresponding handler
        base.cTrav.addCollider(cNodePath, self.cHandler)
        i = 0
        for target in self.targets:
            cSphere = CollisionSphere((0,0,0), 2)
            cNode = CollisionNode("smiley")
            cNode.addSolid(cSphere)
            cNode.setIntoCollideMask(BitMask32.bit(1))
            cNode.setTag('target', str(i))
            cNodePath = target.attachNewNode(cNode)
            i += 1
    
    def lightModify(self, t, which_way):
        if which_way: #which_way == true then make it brighter
            value = t/100 * MAX_LIGHT
        else: #which_way == true then make it darker
            value = (100 - t)/100 * MAX_LIGHT
        for light in self.flameLights:
            light[0].setColor(VBase4(value,value,value,1))
        
    def startShoot(self):
        self.loadParticleConfig('flamethrower4.ptf')
        self.lightOff.finish()
        self.lightOn.start()
        
    def stopShoot(self):
        self.p1.softStop()
        self.p2.softStop()
        self.lightOn.finish()
        self.lightOff.start()
        
    def loadParticleConfig(self, file):
        self.p1.reset()
        self.p1 = ParticleEffect()
        self.p1.loadConfig(Filename(file))        
        self.p1.start(self.player)
        self.p1.setPos(-250, -700, 275)
        self.p1.setHpr(0, 90, 0)
        self.p1.setScale(200)
        self.p1.setLightOff()
        self.p2.reset()
        self.p2 = ParticleEffect()
        self.p2.loadConfig(Filename(file))        
        self.p2.start(self.player)
        self.p2.setPos(250, -700, 275)
        self.p2.setHpr(0, 90, 0)
        self.p2.setScale(200)
        self.p2.setLightOff()
        
    def eat(self, cEntry):
        """handles the player eating a smiley"""
        #remove target from list of targets
        self.targets.remove(cEntry.getIntoNodePath().getParent())
        #remove from scene graph
        cEntry.getIntoNodePath().getParent().remove()
예제 #23
0
파일: mode_head.py 프로젝트: noPounch/golog
class mode_head():
    def __init__(self,base,Golog, folder_path = None, parent = None):
        # Set up basic attributes
        self.base = base
        self.golog = Golog
        self.bools = {'textboxes':True}
        self.buttons = dict()
        self.window_tasks = dict()
        self.bt = None
        self.mw = None
        self.listener = DirectObject()
        self.folder_path = folder_path #absolute path of golog folder '/path/to/golog/folder'
        if self.folder_path:
            self.file_path = os.path.abspath(self.folder_path + '/' + self.golog.label+ '.golog')
            autosave = True
        self.has_window = False
        self.parent = parent #for autosaving up to original golog
        self.reset = self.basic_reset
        self.garbage = [] #list of deleted math_data/graphics_data etc.


        #create a 2d rende
        self.render2d = NodePath('2d render')
        self.camera2D = self.render2d.attachNewNode(Camera('2d Camera'))
        self.camera2D.setDepthTest(False)
        self.camera2D.setDepthWrite(False)
        lens = OrthographicLens()
        lens.setFilmSize(2, 2)
        lens.setNearFar(-1000, 1000)
        self.camera2D.node().setLens(lens)


        # make a dictionary of mode_heads in the underlying golog
        if hasattr(self.golog,'mode_heads'):
            m = 0
            while m in self.golog.mode_heads.keys(): m+=1 #get smallest unused mode_head index
            self.index = m
            self.label = self.golog.label+"_mode_head_"+str(self.index)
            self.golog.mode_heads[self.index] = self

        else:
            self.golog.mode_heads = dict()
            self.index = 0
            self.label = self.golog.label+"_mode_head_"+ str(self.index)
            self.golog.mode_heads[self.index] = self
        ##########

        ### set up collision handling ###
        self.queue = CollisionHandlerQueue()

        ### set up selection tools
        self.create_list = [[],[]] #select nodes and add to create_list in order to create higher simplecies
        self.bools = {'selecter':False,'textboxes':True,'shift_clicked':False} #some bools that will be usefull
        self.dict = {'shift_pt':[None,None]}


        # set up mouse picker
        self.pickerNode = CollisionNode('mouseRay')
        self.pickerNP = self.golog.camera.attachNewNode(self.pickerNode) #attach collision node to camera
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        self.pickerNode.set_into_collide_mask(0) #so that collision rays don't collide into each other if there are two mode_heads
        self.golog.cTrav.addCollider(self.pickerNP,self.queue) #send collisions to self.queue
        # set up plane for picking
        self.planeNode = self.golog.render.attachNewNode("plane")
        self.planeNode.setTag("mode_head",self.label) # tag to say it belongs to this mode_head
        self.planeNode.setTag("mode_node", 'plane')
        self.planeFromObject = self.planeNode.attachNewNode(CollisionNode("planeColNode"))
        self.planeFromObject.node().addSolid(CollisionPlane(Plane(Vec3(0,-1,0),Point3(0,0,0))))
        self.plane = self.planeFromObject.node().getSolid(0)
        ###
        # set up preview text
        self.textNP = self.render2d.attachNewNode(TextNode('text node'))
        self.textNP.setScale(.2)
        self.textNP.setPos(-1,0,0)
        self.textNP.show()
        #set up dragging info
        self.grabbed_dict = dict()
        self.drag_dict = dict() #a mapping from selected nodes to their original positions for dragging
        self.mouse_down_loc = (0,0,0)
        self.lowest_level = 3

    def open_math_data(self,math_data):
        if math_data.type == 'golog':
            golog_dict = math_data() #calls the mathdata (which is a golog_dict)
            subgolog = golog_dict['golog']
            subfolder_path = golog_dict['folder_path']

            #### just to be safe, but probably not needed
            subgolog_folder_path = os.path.join(self.folder_path,'subgologs')
            if not os.path.exists(subgolog_folder_path): os.mkdir(subgolog_folder_path)
            ####
            folder_path = os.path.join(self.folder_path, *golog_dict['folder_path'])
            print(folder_path)
            controllable_golog = mode_head(self.base, subgolog, folder_path = folder_path, parent = self)
            window_manager.modeHeadToWindow(self.base, controllable_golog)

        if math_data.type == 'file':
            file_name, file_extension = os.path.splitext(math_data()[-1])
            # if file_extension == '.txt':
            #     tk_funcs.edit_txt(os.path.join(self.folder_path,*math_data()))
            # else:
                #prompt user to select a program
            tk_funcs.run_program('',os.path.join(self.folder_path,*math_data()))
        if math_data.type == 'latex':
            file_dict = math_data()
            tex_folder = os.path.join(os.path.abspath(self.folder_path),*file_dict['folder'])
            tex_file = os.path.join(os.path.abspath(self.folder_path),*file_dict['tex'])




            if 'pdf' in file_dict.keys():
                pdf_file = os.path.join(self.folder_path, *file_dict['pdf'])
            elif os.path.exists(tex_file.split('.tex')[0]+'.pdf'): #if there is a pdf in the folder with the same name
                file_dict['pdf'] = file_dict['tex']
                file_dict['pdf'][-1] = file_dict['pdf'][-1].split('.tex')[0]+'.pdf' #change extension to .pdf
                pdf_file = os.path.join(self.folder_path, *file_dict['pdf'])
            else: pdf_file = None


            tk_funcs.pdf_or_tex(pdf_file, tex_file)

        if math_data.type == 'weblink':
            open_new_tab(math_data())

    def update_math_data(self,simplex, math_data_type, **kwargs):


        if autosave == True: self.save()

        if 'label' in kwargs: simplex.label = kwargs['label']
        self.golog.Simplex_to_Graphics[simplex].textNP.node().setText(simplex.label)
        self.golog.text_preview_set(self.bools['textboxes'])

        if simplex.math_data.type != 'None':
            answer = tk_funcs.are_you_sure('are you sure you want to delete the current math_data?')
            if answer == 'yes':
                self.delete_math_data(simplex)
            else: return
        if math_data_type == 'None':
            simplex.math_data = hcat.Math_Data(type = 'None')

        if math_data_type == 'golog':

            #create a path for all subgologs, if it doesn't already exist
            subgolog_folder_path = os.path.join(self.folder_path,'subgologs')
            if not os.path.exists(subgolog_folder_path): os.mkdir(subgolog_folder_path)




            new_golog = golog.golog(self.base, label = kwargs['label']) #create a new golog

            #create a unique folder path list in subgolog_folder_path
            unique_path = tk_funcs.unique_path(subgolog_folder_path,[kwargs['label']])
            new_folder_path = ['subgologs', *unique_path]
            os.mkdir(os.path.join(self.folder_path , *new_folder_path)) #make the directory as above
            #create a new golog save at new_folder_path/label.golog
            new_save_location = os.path.join(self.folder_path, *new_folder_path, kwargs['label']+'.golog')

            #new_save_location should be a subfolder of subgologs
            gexport(new_golog, new_save_location)

            #math data is a dictionary of the physical golog and it's relative save path list
            golog_dict = {'golog':new_golog, 'folder_path':new_folder_path}
            simplex.math_data = hcat.Math_Data(math_data = golog_dict, type = 'golog')

        if math_data_type == 'file':
            if not os.path.exists(os.path.join(self.folder_path,'files')): os.mkdir(os.path.join(self.folder_path,'files'))
            file_folder_path = ['files']

            file_location = tk_funcs.ask_file_location()
            if not file_location: return #if user cancels
            file_name = os.path.split(file_location)[1] #file name with extension
            file_path = tk_funcs.unique_path(os.path.join(self.folder_path),[*file_folder_path, file_name]) #get a unique file path starting from the file_folder
            copyfile(file_location, os.path.join(self.folder_path,*file_path))
            simplex.math_data = hcat.Math_Data(math_data = file_path, type = 'file')
            #? add handler for if user exits text editor
            #? make asynchronous

        if math_data_type == 'latex':
            #ensure latex folder exists
            if not os.path.exists(os.path.join(self.folder_path,'latex')): os.mkdir(os.path.join(self.folder_path,'latex'))

            # create a uniquely named folder in self.folder_path/latex/ based on simplex.label
            tex_folder_path = tk_funcs.unique_path(root = self.folder_path, path = ['latex',simplex.label])
            os.mkdir(os.path.join(self.folder_path, *tex_folder_path))
            #create a tex file in tex folder
            tex_file_path = [*tex_folder_path, simplex.label+'.tex']
            # ask if want new or to load one
            location = tk_funcs.load_tex(self.folder_path)
            # if new, returns True and copies template tex file
            # if load, returns a path and copies the path into tex_file_path
            true_path = os.path.join(self.folder_path,*tex_file_path)
            if location == True: copyfile(os.path.abspath('./misc_data/config_files/template.tex'), true_path)

                #
                # open(   true_path  , 'w').close()
            if isinstance(location, str): copyfile(location, true_path)

            # make a file dictionary with just tex file in it
            file_dict = {'tex':tex_file_path, 'folder':tex_folder_path}
            simplex.math_data = hcat.Math_Data(math_data = file_dict, type = 'latex')

        if math_data_type == 'weblink':
            weblink = tk_funcs.ask_weblink()
            simplex.math_data = hcat.Math_Data(math_data = weblink, type = 'weblink')


        if math_data_type == 'text':
            #create a text file
            if not os.path.exists(os.path.join(self.folder_path,'files')): os.mkdir(os.path.join(self.folder_path,'files'))
            file_folder_path = ['files']
            file_path = tk_funcs.unique_path(root = self.folder_path, path = ['files',simplex.label+'.txt' ])
            with open(os.path.join(self.folder_path, *file_path),'w') as file: pass
            #create a math_data for it
            simplex.math_data = hcat.Math_Data(math_data = file_path, type = 'file')



        #save golog
        if autosave == True: self.save()
        return simplex.math_data

    def delete_math_data(self,simplex,**kwargs):
        simplex.math_data.delete(self.folder_path)
        simplex.math_data = hcat.Math_Data(type = 'None')

    def setup_window(self, windict):
        self.windict = windict
        for button in self.buttons.keys():
            self.listener.accept(self.windict['bt'].prefix+button, self.buttons[button], extraArgs = [self.windict['mw']])
        for window_task in self.window_tasks.keys():
            base.taskMgr.add(self.window_tasks[window_task], window_task, extraArgs = [self.windict['mw']], appendTask = True)
        self.has_window = True

    def save(self, *ask):
        #if has a parent, save the parent. If not, save itself
        if not self.parent: #if doesn't have a parent mode_head, save parent
        #if we pass something to ask it will ask (this includes mousewatchers)
            if ask:
                save_location = tk_funcs.ask_file_location(initial_dir = self.folder_path)
                if not save_location: return #if user cancels
                print('saving to:\n'+save_location)
                gexport(self.golog,  self.folder_path)
            else:
                gexport(self.golog,  self.file_path)

        else: self.parent.save()# if parent has no mode_head, save itself

    #basic reset function which shuts off the listener and removes button bindings. Should only be called if no "reset" function exists
    def basic_reset(self,*args):
        self.buttons = dict()
        self.window_tasks = dict()
        self.listener.ignoreAll()

    #function to call before deleting the mode_head, for example when closing a window
    def clean(self):
        self.reset()

        #close window
        if self.has_window == True:
            if hasattr(mode_head,'windict'):
                if 'win' in mode_head.windict.keys():
                    self.base.closeWindow(mode_head.windict['win'], keepCamera = True, removeWindow = True)
            self.has_window = False
        del self.golog.mode_heads[self.index]
        del self.reset

    # function to return the only the relevant collision data from the mouseRay
    def get_relevant_entries(self, mw):
        # get list of entries by distance
        if not mw.node().hasMouse(): return
        mpos = mw.node().getMouse()
        self.pickerRay.setFromLens(self.golog.camNode,mpos.getX(),mpos.getY()) #mouse ray goes from camera through the 'lens plane' at position of mouse
        self.golog.cTrav.traverse(self.golog.render)
        self.queue.sortEntries()

        # get the first relevant node traversed by mouseRay
        #### ignore everything with a mode_head tag that is not defined by this mode_head
        for e in self.queue.getEntries():
            if e.getIntoNodePath().getParent().hasTag("mode_head"):
                if e.getIntoNodePath().getParent().getTag("mode_head") == self.label:
                    return (e.getIntoNodePath().getParent(), e.getIntoNodePath().getParent().getTag("mode_node"),e.getSurfacePoint(e.getIntoNodePath()))
                    break
            else:
                entry = e
                break

        #return node create_list in the golog
        entryNP = entry.getIntoNodePath().getParent()
        if entryNP.hasTag('level'): return (entryNP, entryNP.getTag('level'),entryNP.getPos())

    #function to 'pick up' a node by adding it to the dragged dictionary
    def pickup(self, mw):
        if not mw.node().hasMouse(): return
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
        


        ### get position on plane for mouseloc
        mpos = mw.node().getMouse()
        self.pickerRay.setFromLens(self.golog.camNode,mpos.getX(),mpos.getY()) #mouse ray goes from camera through the 'lens plane' at position of mouse
        self.golog.cTrav.traverse(self.golog.render)
        self.queue.sortEntries()
        for e in self.queue.getEntries():
            if e.getIntoNodePath().getParent().hasTag("mode_head"):
                if e.getIntoNodePath().getParent().getTag("mode_head") == self.label:
                    if e.getIntoNodePath().getParent().getTag("mode_node") == 'plane':
                        self.mouse_down_loc = e.getSurfacePoint(e.getIntoNodePath())
                        break


        #if selected node is in the drag_dict, use it to set a mouse location
        # if entryNP in self.drag_dict.keys(): self.mouse_down_loc = entryNP.getPos()

        if node_type in ['0','1']:
            self.grabbed_dict = {'graphics': self.golog.NP_to_Graphics[entryNP],'dragged':False,
                                                        'orig_pos': entryNP.getPos()}
        if node_type == 'plane':
            for node in self.create_list[0]: node.setColorScale(1,1,1,1) #turn white
            self.create_list = [[],[]]
            for node in self.drag_dict.keys():  node.setColorScale(1,1,1,1)
            self.drag_dict = dict() #drag dict is used for multi-dragging
            a = self.plane.distToPlane(self.golog.camera.getPos())/(2*self.golog.camera.node().getLens().getNear())# ratio for camera movement
            self.grabbed_dict = {'graphics':self.golog.camera, 'dragged':False, 'orig_pos': self.golog.camera.getPos(), 'mpos': LPoint3f(a*mpos.getX(),a*0,a*mpos.getY())}
            self.lowest_level = 3



    #function to 'put down' a node, returns true if it's dragged something
    def putdown(self, mw):
        for node in self.drag_dict.keys():
            self.drag_dict[node] = self.golog.NP_to_Graphics[node].graphics_kwargs['pos']
            self.lowest_level = min(self.lowest_level, int(node.getTag('level')))

        if 'dragged' in self.grabbed_dict.keys():
            if self.grabbed_dict['dragged'] == True:
                self.grabbed_dict = dict()
                return True
            self.grabbed_dict = dict()
    #function to select a node and add a 1-simplex between 2 create_list 0-simplecies
    def select_for_creation(self, mw):
        if not mw.node().hasMouse(): return
        #remove selected
        for node in self.drag_dict.keys():
            node.setColorScale(1,1,1,1)
        self.drag_dict = dict()
        self.lowest_level = 3

        ### selection ###
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
        if node_type == '0':# and set(create_list[1:]) = {[]}:
            if entryNP not in self.create_list[0]:
                #?  don't just append, re-sort
                self.create_list[0].append(entryNP)
            entryNP.setColorScale(1,0,0,0) #turn red

        if len(self.create_list[0]) == 2:
            # NP -> graphics -> simplex
            faces = tuple([self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[faceNP]] for faceNP in self.create_list[0][-1:-3:-1]])
            asked_list = tk_funcs.ask_math_data('1-Simplex')
            if not asked_list: #[label, math_data_type,]
                return
            simplex = self.golog.add(faces, label = asked_list[0]) #reversed create_list objects and creates a 1 - simplex from them
            self.update_math_data(simplex, asked_list[1], label = asked_list[0])
            for node in self.create_list[0]: node.setColorScale(1,1,1,1)
            self.create_list[0] = [] #reset create_list

    #open math_data of simplex under mouse
    def mouse_open(self, mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)

        # if spaced on a 0 simplex, open it's math data, or create it
        if node_type in ['0','1']:
            simplex = self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
            if not simplex.math_data():
                asked_list = tk_funcs.ask_math_data(simplex.label)
                if not asked_list:
                    return
                self.update_math_data(simplex, math_data_type = asked_list[1], label = asked_list[0])
                #? make asynchronous


            else:
                self.open_math_data(simplex.math_data)

    # delete a simplex, prompt to delete the math_data and (recursively) it's supported simplecies
    def delete(self,mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
        if node_type in ['0','1']:
            #warning about deleting supported simplecies

            graphics = self.golog.NP_to_Graphics[entryNP]
            simplex = self.golog.Graphics_to_Simplex[graphics]

            if simplex.supports:
                answer = tk_funcs.are_you_sure(simplex.label+' still supports other simplecies. Are you sure you wish to delete?')
                if answer != 'yes': return

            self.delete_math_data(simplex)
            graphics._remove()

    #update the math_data of a simplex under the mouse
    def mouse_update(self, mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
        if node_type in ['0','1']:
            simplex = self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
            asked_list = tk_funcs.ask_math_data(simplex.label)
            if not asked_list:
                return
            self.update_math_data(simplex, math_data_type = asked_list[1], label = asked_list[0])

    #create a simplex given a mouse position
    def create(self, mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)

        if node_type == 'plane':
            for node in self.create_list[0]: node.setColorScale(1,1,1,1) #turn white
            self.create_list = [[],[]]
            asked_list = tk_funcs.ask_math_data('0-Simplex')
            if not asked_list:
                return #if canceled, do not create a simplex
            simplex = self.golog.add(0, pos = entry_pos, label = asked_list[0]) #create a simplex
            self.update_math_data(simplex, math_data_type = asked_list[1], label = asked_list[0])

    #function which checks the drag dictionary and drags stuff
    def drag(self, mw):
        if self.grabbed_dict:
            #get mouse_loc
            mpos = mw.node().getMouse()
            self.pickerRay.setFromLens(self.golog.camNode,mpos.getX(),mpos.getY()) #mouse ray goes from camera through the 'lens plane' at position of mouse
            self.golog.cTrav.traverse(self.golog.render)
            self.queue.sortEntries()
            mouseloc = None
            for e in self.queue.getEntries():
                if e.getIntoNodePath().getParent().getTag("mode_node") == 'plane':
                    mouseloc = e.getSurfacePoint(e.getIntoNodePath())
                    break
            if not mouseloc:return

            self.bools['dragging'] = True


             # if there is something in the drag dict (for multiselect)
            if self.drag_dict:
                self.grabbed_dict['dragged'] = True
                #only drag lowest dim simplecies
                for node in self.drag_dict.keys():
                    if int(node.getTag('level')) == self.lowest_level: self.golog.NP_to_Graphics[node].update({'pos':self.drag_dict[node]+mouseloc-self.mouse_down_loc})

            #if nothing is selected, drag the thing below you
            elif self.grabbed_dict['graphics'] != self.golog.camera: 
                #radius of drag selection
                offset = mouseloc - self.grabbed_dict['graphics'].parent_pos_convolution()
                delta = offset - self.grabbed_dict['orig_pos']
                norm = delta.getX()**2 +delta.getY()**2 +delta.getZ()**2
                if self.grabbed_dict['dragged'] == True or norm > 1:
                    self.grabbed_dict['dragged'] = True
                #if offset magnitude is greater than 1 or dragged == true, actually drag it
                if self.grabbed_dict['dragged'] == True: self.grabbed_dict['graphics'].update({'pos':offset})

            elif self.grabbed_dict['graphics'] == self.golog.camera: 
                        a = self.plane.distToPlane(self.golog.camera.getPos())/(2*self.golog.camera.node().getLens().getNear())# ratio for camera movement
                        self.golog.camera.setPos(self.grabbed_dict['orig_pos']-(a*mpos.getX(),0,a*mpos.getY())+self.grabbed_dict['mpos'])

           
                    


    #send preview of math_data of simplex under the mouse
    def preview(self, mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)

        if node_type == '0':
            simplex =  self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
        elif node_type == '1':
            #? again consider what needs to be shown with 1-simplecies
            simplex =  self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
        else: return

        # set preview up
        if self.has_window:
            if simplex.math_data.type == 'golog':
                self.windict['preview_dr'].setCamera(simplex.math_data()['golog'].camera)
            else:
                self.windict['preview_dr'].setCamera(self.camera2D)
                self.textNP.node().setText("label:\n" +simplex.label+"\n\n math data type:\n" + simplex.math_data.type)
        return

    def pprint(self,mw):
        (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)

        if node_type == '0':
            simplex =  self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
        elif node_type == '1':
            #? again consider what needs to be shown with 1-simplecies
            simplex =  self.golog.Graphics_to_Simplex[self.golog.NP_to_Graphics[entryNP]]
        else: return

        simplex.pprint()


    #tool for selecting multiple simplecies
    def multi_select(self,mw):
        if isinstance(mw, NodePath):
            entryNP = mw
            node_type = entryNP.getTag('level')
        else: return

        #reset select and create
        if node_type in ['0','1']:
            if entryNP in self.drag_dict.keys():
                del self.drag_dict[entryNP]
                entryNP.setColorScale(1,1,1,1)
                self.lowest_level = min([*[int(node.getTag('level')) for node in self.drag_dict.keys()],3])
            else:
                self.drag_dict[entryNP] = self.golog.NP_to_Graphics[entryNP].graphics_kwargs['pos']
                entryNP.setColorScale(.5,.5,0,1)
                self.lowest_level = min(self.lowest_level, int(entryNP.getTag('level')))

    def shift_box(self,mw):
        if None in self.dict['shift_pt']:
            self.dict['shift_pt'] = [None,None]
            return
        pt_1 = self.dict['shift_pt'][0]
        pt_2 = self.dict['shift_pt'][1]
        if sum([x**2 for x in list(pt_2-pt_1)]) <= 1:
            (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
            self.multi_select(entryNP)

        #create vectors
        N = self.planeFromObject.node().getSolid(0).getNormal()
        x = [(pt_2-pt_1).getX(),0,0]
        z = [0,0,(pt_2-pt_1).getZ()]
        campos = list(self.golog.camera.getPos())
        for simplex in self.golog.sSet.rawSimps:
            node = self.golog.Simplex_to_Graphics[simplex].node_list[0]
            P = list(node.getPos())
            if t_int(pt_1,x,z,campos,P): self.multi_select(node)

        self.dict['shift_pt'] = [None,None]


    def consolidate(self, selected = False,sel_simp = None):
        #ask for label, or cancel
        G = self.golog

        # if a collection isn't provided, use the (multi-select) drag dictionary
        if not selected: selected = [G.Graphics_to_Simplex[G.NP_to_Graphics[node]] for node in self.drag_dict.keys()]
        if not selected: return #return if there was nothing passed, and nothing in the drag_dict
        for simp in selected:
            for face in simp.faces:
                if face not in selected: selected.append(face)

        # #? select a simplex to consolidate into
        # sel_simp = None
        # for simp in selected: 
        #     if simp.math_data.type == 'None':
                
        #         sel_simp = simp

        #make a golog from selected
        new_golog = golog.golog(self.base, label ='test')

        def add(simplex):
            for face in simplex.faces:
                add(face)
            new_golog.add(simplex, pos = G.Simplex_to_Graphics[simplex].graphics_kwargs['pos'])
        for simplex in selected: add(simplex)
        

        #consolidate into 1 simplex
        if sel_simp:
            #consolidate into sel_simp
            subgolog_folder_path = os.path.join(self.folder_path,'subgologs')
            unique_path = tk_funcs.unique_path(subgolog_folder_path,[sel_simp.label])
            new_folder_path = ['subgologs', *unique_path]
            
            sel_simp.math_data = hcat.Math_Data(math_data = {'golog':new_golog, 'folder_path':new_folder_path}, type = 'golog')
            
            #? remove simplexes and place at selected simplex location
            return sel_simp


        #create an entirely new simplex to put the golog into
        else:
            #? ask for label / cancel
            label = "test"
            subgolog_folder_path = os.path.join(self.folder_path,'subgologs')
            unique_path = tk_funcs.unique_path(subgolog_folder_path,[label])
            new_folder_path = ['subgologs', *unique_path]

            #create a simplex with average position of things in golog
            avg = LPoint3f(*[sum([G.Simplex_to_Graphics[simplex].graphics_kwargs['pos'][i]/len(new_golog.sSet.simplecies[()])  for simplex in new_golog.sSet.simplecies[()]]) for i in range(3)])
            s = self.golog.add(0, label ='test', math_data = hcat.Math_Data(math_data = {'golog':new_golog, 'folder_path':new_folder_path}, type = 'golog'), pos = LPoint3f(avg))

            return s

    ########## BEGIN DEFINING MODES ##########

    #selection and creation mode
    def selection_and_creation(self, windict):
        def mouse1(mw):
            if not mw: return
            self.bools['shift_clicked'] = False
            self.pickup(mw)

        def shift_mouse1(mw):
            if not mw: return
            #on click, begin a rectagle dragging function
            (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
            self.dict['shift_pt'][0] = entry_pos
            self.bools['shift_clicked'] = True

        def mouse1_up(mw):
            dropped_bool = self.putdown(mw)
            if self.bools['shift_clicked']:
                (entryNP, node_type, entry_pos) = self.get_relevant_entries(mw)
                self.dict['shift_pt'][1] = entry_pos
                self.shift_box(mw)
                self.bools['shift_clicked'] = False

            elif dropped_bool:
                pass
            else:
                self.select_for_creation(mw)




        def space(mw):
            if not mw: return
            self.mouse_open(mw)

        def u(mw):
            if not mw: return
            #?  do a change not just update
            self.mouse_update(mw)

        def c(mw):
            self.consolidate()
        def p(mw):
            if not mw: return
            self.pprint(mw)

        def mouse3(mw):
            if not mw: return
            self.create(mw)

        def backspace(mw):
            if not mw: return
            self.delete(mw)

        def mouse_watch_task(mw,task):
            if not mw: return task.cont
            if not mw.node().hasMouse(): return task.cont
            self.drag(mw)
            self.preview(mw)
            return task.cont

        def wheel_up(mw):
            if not mw:return
            a = self.plane.distToPlane(self.golog.camera.getPos())/(2*self.golog.camera.node().getLens().getNear())# ratio for camera movement
            self.golog.camera.setPos( self.golog.camera.getPos() + (0,10,0) ) #fix for offset by storing a global camera - plane ratio

        def wheel_down(mw):
            if not mw:return
            self.golog.camera.setPos( self.golog.camera.getPos() - (0,10,0) )

        def reset(*args):
            self.buttons = dict()
            self.window_task = dict()
            self.reset = self.basic_reset
        self.reset = reset

        self.buttons = {'mouse1':mouse1, 'mouse1-up':mouse1_up, 'mouse3':mouse3,'c':c,
        'space':space, 'escape':self.reset, 's':self.save, 'u':u,'backspace':backspace,
        'shift-mouse1':shift_mouse1,'p':p,'wheel_up':wheel_up, "wheel_down":wheel_down}
        self.window_tasks = {'mouse_watch_task':mouse_watch_task}
        self.setup_window(windict)
예제 #24
0
class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        # Create a traverser and a handler
        self.cTrav = CollisionTraverser()
        self.cQueue = CollisionHandlerQueue()

        # Create the collision node that will store the collision
        # ray solid
        self.pickerNode = CollisionNode('mouseRay')
        # Set bitmask for efficiency, only hit from objects with same mask
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        # Attach collision node to camera, since that is the source
        self.pickerNP = camera.attachNewNode(self.pickerNode)

        # Add collision solid(ray) to collision node
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        # Add collidable node(pickerNP) to the traverser
        # Collisions detected when traversed will go to cQueue
        self.cTrav.addCollider(self.pickerNP, self.cQueue)

        # Create visible sphere
        self.tmpSphere = self.loader.loadModel("models/misc/sphere")
        self.tmpSphere.reparentTo(self.render)
        self.tmpSphere.setColor(1, 1, 1, 1)
        self.tmpSphere.setPos(0, 100, 0)

        # Create collision sphere and attach to tmpSphere
        cSphere = CollisionSphere(0, 0, 0, 3)
        cnodePath = self.tmpSphere.attachNewNode(CollisionNode('cnode'))
        # Add collision solid(sphere) to collision node
        # Because tmpSphere/cSphere is child of render, which we traverse
        # later, it becomes a from collider automatically, we don't
        # need to addCollider since that is only for from collision nodes
        cnodePath.node().addSolid(cSphere)
        # Set bitmask to match the from collisionnode mask for efficiency
        cnodePath.setCollideMask(BitMask32.bit(1))
        # Show the collision sphere visibly, for debugging.
        cnodePath.show()
        # Set a custom tag on the collision node which becomes available
        # inside the collision event stored in the collision handler
        cnodePath.setTag('someTag', '1')

        # Add task to run every frame - set collision solid(ray)
        # to start at the current camera position,
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')

    def mouseTask(self, task):
        if self.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            # Set collision ray to start at camera lens and endpoint at mouse
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            # Perform the collision traverse - follows the ray and logs
            # all collisions to the handler set earlier
            self.cTrav.traverse(self.render)
            # Get info from entries and use them
            if self.cQueue.getNumEntries() > 0:
                self.cQueue.sortEntries()
                print("Collision!")
                entry = self.cQueue.getEntry(0)
                print(entry)
                someTag = int(entry.getIntoNode().getTag('someTag'))
                print(someTag)
                # Collision detected, mouse must be over sphere
                self.tmpSphere.setColor(0, 1, 0, 1)
            else:
                # No collisions, mouse is not over sphere, unset color
                # Not ideal to "unset" the color each frame
                self.tmpSphere.setColor(1, 1, 1, 1)
        return task.cont
예제 #25
0
class LocalToon(DistributedToon):
    neverDisable = 1

    def __init__(self, cr):
        try:
            self.LocalToon_initialized
            return
        except:
            self.LocalToon_initialized = 1

        DistributedToon.__init__(self, cr)
        self.avatarChoice = cr.localAvChoice
        self.smartCamera = SmartCamera()
        self.chatInput = ChatInput()
        self.moneyGui = MoneyGui()
        self.laffMeter = LaffOMeter()
        self.positionExaminer = PositionExaminer()
        self.friendRequestManager = FriendRequestManager()
        self.friendsList = FriendsList()
        self.panel = ToonPanel()
        friendsgui = loader.loadModel('phase_3.5/models/gui/friendslist_gui.bam')
        self.friendButton = DirectButton(geom=(friendsgui.find('**/FriendsBox_Closed'), friendsgui.find('**/FriendsBox_Rollover'), friendsgui.find('**/FriendsBox_Rollover')), text=('', 'Friends', 'Friends', ''), text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), text_scale=0.065, text_pos=(0, -0.2), relief=None, parent=base.a2dTopRight, pos=(-0.18, 0.0, -0.17), command=self.friendsButtonClicked, scale=0.75)
        friendsgui.removeNode()
        del friendsgui
        self.hideFriendButton()
        self.runSfx = base.loadSfx('phase_3.5/audio/sfx/AV_footstep_runloop.wav')
        self.runSfx.setLoop(True)
        self.walkSfx = base.loadSfx('phase_3.5/audio/sfx/AV_footstep_walkloop.wav')
        self.walkSfx.setLoop(True)
        self.controlManager = ControlManager.ControlManager(True, False)
        self.offset = 3.2375
        self.movementKeymap = {'forward': 0,
         'backward': 0,
         'left': 0,
         'right': 0,
         'jump': 0}
        self.avatarMovementEnabled = False
        self.isMoving_forward = False
        self.isMoving_side = False
        self.isMoving_back = False
        self.isMoving_jump = False
        self.pieThrowBtn = None
        self.myBattle = None
        self.invGui = None
        self.pickerTrav = None
        self.pickerRay = None
        self.pickerRayNode = None
        self.pickerHandler = None
        self.rolledOverTag = None
        self.inTutorial = False
        self.hasDoneJump = False
        self.lastState = None
        self.lastAction = None
        return

    def hasDiscoveredHood(self, zoneId):
        return zoneId in self.hoodsDiscovered

    def hasTeleportAccess(self, zoneId):
        return zoneId in self.teleportAccess

    def tutorialCreated(self, zoneId):
        self.cr.tutorialCreated(zoneId)

    def friendsButtonClicked(self):
        self.hideFriendButton()
        self.friendsList.fsm.request('onlineFriendsList')

    def hideFriendButton(self):
        self.friendButton.hide()

    def showFriendButton(self):
        self.friendButton.show()

    def gotoNode(self, node, eyeHeight = 3):
        possiblePoints = (Point3(3, 6, 0),
         Point3(-3, 6, 0),
         Point3(6, 6, 0),
         Point3(-6, 6, 0),
         Point3(3, 9, 0),
         Point3(-3, 9, 0),
         Point3(6, 9, 0),
         Point3(-6, 9, 0),
         Point3(9, 9, 0),
         Point3(-9, 9, 0),
         Point3(6, 0, 0),
         Point3(-6, 0, 0),
         Point3(6, 3, 0),
         Point3(-6, 3, 0),
         Point3(9, 9, 0),
         Point3(-9, 9, 0),
         Point3(0, 12, 0),
         Point3(3, 12, 0),
         Point3(-3, 12, 0),
         Point3(6, 12, 0),
         Point3(-6, 12, 0),
         Point3(9, 12, 0),
         Point3(-9, 12, 0),
         Point3(0, -6, 0),
         Point3(-3, -6, 0),
         Point3(0, -9, 0),
         Point3(-6, -9, 0))
        for point in possiblePoints:
            pos = self.positionExaminer.consider(node, point, eyeHeight)
            if pos:
                self.setPos(node, pos)
                self.lookAt(node)
                self.setHpr(self.getH() + random.choice((-10, 10)), 0, 0)
                return

        self.setPos(node, 0, 0, 0)

    def setFriendsList(self, friends):
        DistributedToon.setFriendsList(self, friends)
        self.cr.friendsManager.d_requestFriendsList()
        self.panel.maybeUpdateFriendButton()

    def d_requestAddFriend(self, avId):
        self.sendUpdate('requestAddFriend', [avId])

    def setupPicker(self):
        self.pickerTrav = CollisionTraverser('LT.pickerTrav')
        self.pickerRay = CollisionRay()
        rayNode = CollisionNode('LT.pickerNode')
        rayNode.addSolid(self.pickerRay)
        rayNode.setCollideMask(BitMask32(0))
        rayNode.setFromCollideMask(CIGlobals.WallBitmask)
        self.pickerRayNode = base.camera.attachNewNode(rayNode)
        self.pickerHandler = CollisionHandlerQueue()
        self.pickerTrav.addCollider(self.pickerRayNode, self.pickerHandler)

    def enablePicking(self):
        self.accept('mouse1', self.pickedSomething_down)
        self.accept('mouse1-up', self.pickedSomething_up)
        base.taskMgr.add(self.__travMousePicker, 'LT.travMousePicker')

    def disablePicking(self):
        base.taskMgr.remove('LT.travMousePicker')
        self.ignore('mouse1')
        self.ignore('mouse1-up')

    def pickedSomething_down(self):
        if self.rolledOverTag:
            base.playSfx(DGG.getDefaultClickSound())
            avatar = self.cr.doId2do.get(self.rolledOverTag)
            avatar.nameTag.setPickerState('down')

    def pickedSomething_up(self):
        if self.rolledOverTag:
            avatar = self.cr.doId2do.get(self.rolledOverTag)
            avatar.nameTag.setPickerState('up')
            self.panel.makePanel(self.rolledOverTag)

    def __travMousePicker(self, task):
        if not base.mouseWatcherNode.hasMouse():
            return task.cont
        else:
            mpos = base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            self.pickerTrav.traverse(render)
            if self.pickerHandler.getNumEntries() > 0:
                self.pickerHandler.sortEntries()
                pickedObject = self.pickerHandler.getEntry(0).getIntoNodePath()
                avatarId = pickedObject.getParent().getPythonTag('avatar')
                if avatarId != None:
                    for do in self.cr.doId2do.values():
                        if do.__class__.__name__ == 'DistributedToon':
                            if do.doId == avatarId:
                                if do.nameTag.getClickable() == 1:
                                    if do.nameTag.fsm.getCurrentState().getName() != 'rollover' and do.nameTag.fsm.getCurrentState().getName() != 'down':
                                        do.nameTag.setPickerState('rollover')
                                        base.playSfx(DGG.getDefaultRolloverSound())
                                        self.rolledOverTag = avatarId
                                        break
                        elif do.__class__.__name__ == 'DistributedToon':
                            if do.nameTag.fsm.getCurrentState().getName() != 'up':
                                do.nameTag.setPickerState('up')

                elif self.rolledOverTag:
                    avatar = self.cr.doId2do.get(self.rolledOverTag)
                    if avatar:
                        if avatar.nameTag.fsm.getCurrentState().getName() != 'up':
                            avatar.nameTag.setPickerState('up')
                    self.rolledOverTag = None
            return task.cont

    def prepareToSwitchControlType(self):
        inputs = ['run',
         'forward',
         'reverse',
         'turnLeft',
         'turnRight',
         'slideLeft',
         'slideRight',
         'jump']
        for inputName in inputs:
            try:
                inputState.releaseInputs(inputName)
            except:
                pass

    def getBackpack(self):
        return DistributedToon.getBackpack(self)

    def setMyBattle(self, battle):
        self.myBattle = battle

    def getMyBattle(self):
        return self.myBattle

    def ghostOn(self):
        self.getGeomNode().setTransparency(1)
        self.getGeomNode().setColorScale(1, 1, 1, 0.25)

    def ghostOff(self):
        self.getGeomNode().setColorScale(1, 1, 1, 1)
        self.getGeomNode().setTransparency(0)

    def enterReadBook(self, ts = 0, callback = None, extraArgs = []):
        self.stopLookAround()
        self.b_lookAtObject(0, -45, 0)
        DistributedToon.enterReadBook(self, ts, callback, extraArgs)

    def exitReadBook(self):
        DistributedToon.exitReadBook(self)
        self.startLookAround()

    def getAirborneHeight(self):
        return self.offset + 0.025

    def setupControls(self):
        self.walkControls = GravityWalker(legacyLifter=False)
        self.walkControls.setWallBitMask(CIGlobals.WallBitmask)
        self.walkControls.setFloorBitMask(CIGlobals.FloorBitmask)
        self.walkControls.setWalkSpeed(CIGlobals.ToonForwardSpeed, CIGlobals.ToonJumpForce, CIGlobals.ToonReverseSpeed, CIGlobals.ToonRotateSpeed)
        self.walkControls.initializeCollisions(base.cTrav, self, floorOffset=0.025, reach=4.0)
        self.walkControls.setAirborneHeightFunc(self.getAirborneHeight)

    def setWalkSpeedNormal(self):
        self.walkControls.setWalkSpeed(CIGlobals.ToonForwardSpeed, CIGlobals.ToonJumpForce, CIGlobals.ToonReverseSpeed, CIGlobals.ToonRotateSpeed)

    def setWalkSpeedSlow(self):
        self.walkControls.setWalkSpeed(CIGlobals.ToonForwardSlowSpeed, CIGlobals.ToonJumpSlowForce, CIGlobals.ToonReverseSlowSpeed, CIGlobals.ToonRotateSlowSpeed)

    def setupCamera(self):
        base.camLens.setMinFov(CIGlobals.DefaultCameraFov / (4.0 / 3.0))
        base.camLens.setNearFar(CIGlobals.DefaultCameraNear, CIGlobals.DefaultCameraFar)
        camHeight = max(self.getHeight(), 3.0)
        heightScaleFactor = camHeight * 0.3333333333
        defLookAt = Point3(0.0, 1.5, camHeight)
        camPos = (Point3(0.0, -9.0 * heightScaleFactor, camHeight),
         defLookAt,
         Point3(0.0, camHeight, camHeight * 4.0),
         Point3(0.0, camHeight, camHeight * -1.0),
         0)
        self.smartCamera.initializeSmartCamera()
        self.smartCamera.setIdealCameraPos(camPos[0])
        self.smartCamera.setLookAtPoint(defLookAt)

    def setDNAStrand(self, dnaStrand):
        DistributedToon.setDNAStrand(self, dnaStrand)
        self.initCollisions()
        self.setupCamera()

    def setMoney(self, money):
        DistributedToon.setMoney(self, money)
        self.moneyGui.update(money)

    def setupNameTag(self, tempName = None):
        DistributedToon.setupNameTag(self, tempName)
        if self.nameTag:
            self.nameTag.setColorLocal()

    def d_broadcastPositionNow(self):
        self.d_clearSmoothing()
        self.d_broadcastPosHpr()

    def b_setAnimState(self, anim, callback = None, extraArgs = []):
        if self.anim != anim:
            self.d_setAnimState(anim)
            DistributedToon.setAnimState(self, anim, callback=callback, extraArgs=extraArgs)

    def attachCamera(self):
        camera.reparentTo(self)
        camera.setPos(self.smartCamera.getIdealCameraPos())

    def startSmartCamera(self):
        self.smartCamera.startUpdateSmartCamera()

    def resetSmartCamera(self):
        self.stopSmartCamera()
        self.startSmartCamera()

    def stopSmartCamera(self):
        self.smartCamera.stopUpdateSmartCamera()

    def detachCamera(self):
        camera.reparentTo(render)
        camera.setPos(0, 0, 0)
        camera.setHpr(0, 0, 0)

    def handleSuitAttack(self, attack_id, suit_id):
        DistributedToon.handleSuitAttack(self, attack_id, suit_id)
        if not self.isDead() and base.config.GetBool('want-sa-reactions'):
            base.taskMgr.remove('LT.attackReactionDone')
            attack = SuitAttacks.SuitAttackLengths.keys()[attack_id]
            suit = self.cr.doId2do.get(suit_id)
            animToPlay = None
            timeToWait = 3.0
            if attack not in ('pickpocket', 'fountainpen'):
                suitH = suit.getH(render) % 360
                myH = self.getH(render) % 360
                if -90.0 <= suitH - myH <= 90.0:
                    animToPlay = 'fallFWD'
                else:
                    animToPlay = 'fallBCK'
            elif attack in ('pickpocket',):
                animToPlay = 'cringe'
            elif attack in ('fountainpen',):
                animToPlay = 'conked'
                timeToWait = 5.0
            self.cr.playGame.getPlace().fsm.request('stop')
            self.b_setAnimState(animToPlay)
            base.taskMgr.doMethodLater(timeToWait, self.__attackReactionDone, 'LT.attackReactionDone')
        return

    def __attackReactionDone(self, task):
        self.cr.playGame.hood.loader.place.fsm.request('walk')
        self.b_setAnimState('neutral')
        return Task.done

    def enableAvatarControls(self):
        self.walkControls.enableAvatarControls()
        self.accept('control', self.updateMovementKeymap, ['jump', 1])
        self.accept('control-up', self.updateMovementKeymap, ['jump', 0])
        taskMgr.add(self.movementTask, 'avatarMovementTask')
        self.avatarMovementEnabled = True
        self.playMovementSfx(None)
        return

    def disableAvatarControls(self):
        self.walkControls.disableAvatarControls()
        self.ignore('arrow_up')
        self.ignore('arrow_up-up')
        self.ignore('arrow_down')
        self.ignore('arrow_down-up')
        self.ignore('arrow_left')
        self.ignore('arrow_left-up')
        self.ignore('arrow_right')
        self.ignore('arrow_right-up')
        self.ignore('control')
        self.ignore('control-up')
        taskMgr.remove('avatarMovementTask')
        self.isMoving_forward = False
        self.isMoving_side = False
        self.isMoving_back = False
        self.isMoving_jump = False
        self.avatarMovementEnabled = False
        self.playMovementSfx(None)
        for k, _ in self.movementKeymap.items():
            self.updateMovementKeymap(k, 0)

        return

    def updateMovementKeymap(self, key, value):
        self.movementKeymap[key] = value

    def getMovementKeyValue(self, key):
        return self.movementKeymap[key]

    def playMovementSfx(self, movement):
        if movement == 'run':
            self.walkSfx.stop()
            self.runSfx.play()
        elif movement == 'walk':
            self.runSfx.stop()
            self.walkSfx.play()
        else:
            self.runSfx.stop()
            self.walkSfx.stop()

    def __forward(self):
        self.resetHeadHpr()
        self.stopLookAround()
        if self.getHealth() < 1:
            self.playMovementSfx('walk')
            self.setPlayRate(1.2, 'dwalk')
            self.setAnimState('deadWalk')
        else:
            self.playMovementSfx('run')
            self.setAnimState('run')
        self.isMoving_side = False
        self.isMoving_back = False
        self.isMoving_forward = True
        self.isMoving_jump = False

    def __turn(self):
        self.resetHeadHpr()
        self.stopLookAround()
        self.playMovementSfx('walk')
        if self.getHealth() < 1:
            self.setPlayRate(1.2, 'dwalk')
            self.setAnimState('deadWalk')
        else:
            self.setPlayRate(1.0, 'walk')
            self.setAnimState('walk')
        self.isMoving_forward = False
        self.isMoving_back = False
        self.isMoving_side = True
        self.isMoving_jump = False

    def __reverse(self):
        self.resetHeadHpr()
        self.stopLookAround()
        self.playMovementSfx('walk')
        if self.getHealth() < 1:
            self.setPlayRate(-1.0, 'dwalk')
            self.setAnimState('deadWalk')
        else:
            self.setAnimState('walkBack')
        self.isMoving_side = False
        self.isMoving_forward = False
        self.isMoving_back = True
        self.isMoving_jump = False

    def __jump(self):
        self.playMovementSfx(None)
        if base.localAvatar.getHealth() > 0:
            if self.playingAnim == 'run' or self.playingAnim == 'walk':
                self.b_setAnimState('leap')
            else:
                self.b_setAnimState('jump')
        self.isMoving_side = False
        self.isMoving_forward = False
        self.isMoving_back = False
        self.isMoving_jump = True
        return

    def __neutral(self):
        self.resetHeadHpr()
        self.startLookAround()
        self.playMovementSfx(None)
        if base.localAvatar.getHealth() > 0:
            self.setAnimState('neutral')
        else:
            self.setPlayRate(1.0, 'dneutral')
            self.setAnimState('deadNeutral')
        self.isMoving_side = False
        self.isMoving_forward = False
        self.isMoving_back = False
        self.isMoving_jump = False
        return

    def movementTask(self, task):
        if self.getMovementKeyValue('jump') == 1:
            if not self.walkControls.isAirborne:
                if self.walkControls.mayJump:
                    self.__jump()
                    self.hasDoneJump = True
                elif self.hasDoneJump:
                    if self.getHealth() > 0:
                        self.b_setAnimState('Happy')
                    self.hasDoneJump = False
        elif not self.walkControls.isAirborne:
            if self.hasDoneJump:
                if self.getHealth() > 0:
                    self.b_setAnimState('Happy')
                self.hasDoneJump = False
        return task.cont

    def startTrackAnimToSpeed(self):
        base.taskMgr.add(self.trackAnimToSpeed, self.uniqueName('trackAnimToSpeed'))

    def stopTrackAnimToSpeed(self):
        base.taskMgr.remove(self.uniqueName('trackAnimToSpeed'))

    def trackAnimToSpeed(self, task):
        speed, rotSpeed, slideSpeed = self.walkControls.getSpeeds()
        state = None
        if self.getHealth() > 0:
            state = 'Happy'
        else:
            state = 'Sad'
        if state != self.lastState:
            self.lastState = state
            self.b_setAnimState(state)
            if state == 'Sad':
                self.setWalkSpeedSlow()
            else:
                self.setWalkSpeedNormal()
        action = self.setSpeed(speed, rotSpeed)
        if action != self.lastAction:
            self.lastAction = action
            if action == CIGlobals.WALK_INDEX or action == CIGlobals.REVERSE_INDEX:
                self.resetHeadHpr()
                self.stopLookAround()
                self.playMovementSfx('walk')
            elif action == CIGlobals.RUN_INDEX:
                self.resetHeadHpr()
                self.stopLookAround()
                self.playMovementSfx('run')
            else:
                self.resetHeadHpr()
                self.startLookAround()
                self.playMovementSfx(None)
        return task.cont

    def createLaffMeter(self):
        r, g, b, _ = self.getHeadColor()
        animal = self.getAnimal()
        maxHp = self.getMaxHealth()
        hp = self.getHealth()
        self.laffMeter.generate(r, g, b, animal, maxHP=maxHp, initialHP=hp)
        self.laffMeter.start()

    def disableLaffMeter(self):
        self.laffMeter.stop()
        self.laffMeter.disable()

    def deleteLaffMeter(self):
        self.laffMeter.delete()

    def setLoadout(self, gagIds):
        DistributedToon.setLoadout(self, gagIds)
        if base.cr.playGame.getPlace() and base.cr.playGame.getPlace().fsm.getCurrentState().getName() == 'shtickerBook':
            if hasattr(base.cr.playGame.getPlace(), 'shtickerBookStateData'):
                if base.cr.playGame.getPlace().shtickerBookStateData.fsm.getCurrentState().getName() == 'inventoryPage':
                    base.cr.playGame.getPlace().shtickerBookStateData.gui.fsm.request('idle')

    def enablePies(self, andKeys = 0):
        if self.avatarMovementEnabled and andKeys:
            self.enablePieKeys()
        self.backpack = DistributedToon.getBackpack(self)
        self.invGui = InventoryGui()
        self.invGui.createGui()
        self.invGui.setBackpack(self.backpack)
        for gag in self.backpack.getGags():
            gag.setAvatar(self)

        self.backpack.setGagGUI(self.invGui)
        if self.backpack.getCurrentGag():
            self.invGui.setWeapon(self.backpack.getCurrentGag().getName(), playSound=False)

    def enablePieKeys(self):
        if self.pieThrowBtn:
            if not self.backpack:
                self.backpack = DistributedToon.getBackpack(self)
            self.pieThrowBtn.bind(DGG.B1PRESS, self.startGag)
            self.pieThrowBtn.bind(DGG.B1RELEASE, self.throwGag)
        self.accept('delete', self.startGag)
        self.accept('delete-up', self.throwGag)

    def disablePieKeys(self):
        if self.pieThrowBtn:
            self.pieThrowBtn.unbind(DGG.B1PRESS)
            self.pieThrowBtn.unbind(DGG.B1RELEASE)
        self.ignore('delete')
        self.ignore('delete-up')

    def disablePies(self):
        self.disablePieKeys()
        self.invGui.deleteGui()
        if hasattr(self, 'backpack'):
            if self.backpack:
                self.backpack.setCurrentGag(None)
        return

    def setWeaponType(self, weaponType):
        enableKeysAgain = 0
        if weaponType != self.weaponType:
            enableKeysAgain = 1
        self.weaponType = weaponType
        if enableKeysAgain:
            self.disablePieKeys()
            self.enablePieKeys()

    def createMoney(self):
        self.moneyGui.createGui()
        self.moneyGui.update(self.money)

    def handleMoneyChanged(self):
        self.moneyGui.update()

    def disableMoney(self):
        self.moneyGui.deleteGui()

    def resetHeadHpr(self):
        self.b_lookAtObject(0, 0, 0, blink=0)

    def startGag(self, start = True):
        if not self.backpack or not self.backpack.getCurrentGag():
            return
        if self.backpack.getSupply() > 0:
            if self.pieThrowBtn:
                self.pieThrowBtn.unbind(DGG.B1PRESS)
            if self.backpack.getActiveGag():
                if self.backpack.getActiveGag().getState() != GagState.LOADED:
                    return
            self.ignore('delete')
            self.backpack.getCurrentGag().setAvatar(self)
            self.resetHeadHpr()
            self.b_gagStart(self.backpack.getCurrentGag().getID())

    def throwGag(self, start = True):
        if not self.backpack or not self.backpack.getCurrentGag() or not self.backpack.getActiveGag():
            return
        if self.backpack.getSupply() > 0:
            if self.pieThrowBtn:
                self.pieThrowBtn.unbind(DGG.B1RELEASE)
            self.ignore('delete-up')
            if self.backpack.getActiveGag().getType() == GagType.SQUIRT and self.backpack.getActiveGag().getName() == CIGlobals.SeltzerBottle:
                self.b_gagRelease(self.backpack.getActiveGag().getID())
            else:
                self.b_gagThrow(self.backpack.getActiveGag().getID())
            activeGag = self.backpack.getActiveGag()
            if not activeGag:
                activeGag = self.backpack.getCurrentGag()
            if not activeGag.doesAutoRelease():
                Sequence(Wait(0.75), Func(self.releaseGag), Wait(0.3), Func(self.enablePieKeys)).start()

    def releaseGag(self):
        if not self.backpack or not self.backpack.getActiveGag():
            return
        if self.backpack.getSupply() > 0:
            gag = self.backpack.getActiveGag()
            if not gag:
                gag = self.backpack.getCurrentGag()
            if gag.getState() != GagState.RELEASED:
                gagName = gag.getName()
                self.b_gagRelease(GagGlobals.getIDByName(gagName))

    def checkSuitHealth(self, suit):
        pass

    def handleLookSpot(self, hpr):
        h, p, r = hpr
        self.d_lookAtObject(h, p, r, blink=1)

    def showPieButton(self):
        geom = CIGlobals.getDefaultBtnGeom()
        self.pieThrowBtn = DirectButton(geom=geom, geom_scale=(0.75, 1, 1), text='Throw Gag', text_scale=0.05, text_pos=(0, -0.01), relief=None, parent=base.a2dTopCenter, pos=(0, 0, -0.1))
        self.pieThrowBtn.setBin('gui-popup', 60)
        return

    def hidePieButton(self):
        self.pieThrowBtn.removeNode()
        self.pieThrowBtn = None
        return

    def showBookButton(self, inBook = 0):
        self.book_gui = loader.loadModel('phase_3.5/models/gui/sticker_open_close_gui.bam')
        self.book_btn = DirectButton(geom=(self.book_gui.find('**/BookIcon_CLSD'), self.book_gui.find('**/BookIcon_OPEN'), self.book_gui.find('**/BookIcon_RLVR')), relief=None, pos=(-0.175, 0, 0.163), command=self.bookButtonClicked, scale=(0.7, 0.8, 0.8), parent=base.a2dBottomRight)
        self.book_btn.setBin('gui-popup', 60)
        if inBook:
            self.book_btn['geom'] = (self.book_gui.find('**/BookIcon_OPEN'), self.book_gui.find('**/BookIcon_CLSD'), self.book_gui.find('**/BookIcon_RLVR2'))
            self.book_btn['command'] = self.bookButtonClicked
            self.book_btn['extraArgs'] = [0]
        return

    def hideBookButton(self):
        if hasattr(self, 'book_gui'):
            self.book_gui.removeNode()
            del self.book_gui
        if hasattr(self, 'book_btn'):
            self.book_btn.destroy()
            del self.book_btn

    def bookButtonClicked(self, openIt = 1):
        if openIt:
            base.cr.playGame.getPlace().fsm.request('shtickerBook')
        else:
            base.cr.playGame.getPlace().shtickerBookStateData.finished('resume')

    def startMonitoringHP(self):
        taskMgr.add(self.monitorHealth, 'localToon-monitorHealth')

    def monitorHealth(self, task):
        if self.isDead():
            base.taskMgr.remove('LT.attackReactionDone')
            if self.cr.playGame.hood.id != ZoneUtil.getHoodId(self.zoneId):
                self.cr.playGame.getPlace().fsm.request('died', [{}, self.diedStateDone])
            return task.done
        return task.cont

    def stopMonitoringHP(self):
        taskMgr.remove('localToon-monitorHealth')

    def setHealth(self, hp):
        if hp > 0 and self.getHealth() < 1:
            if self.cr.playGame.getPlace():
                if self.cr.playGame.getPlace().fsm.getCurrentState().getName() == 'walk':
                    if self.cr.playGame.getPlace().walkStateData.fsm.getCurrentState().getName() == 'deadWalking':
                        self.cr.playGame.getPlace().walkStateData.fsm.request('walking')
            if self.animFSM.getCurrentState().getName() == 'deadNeutral':
                self.playMovementSfx(None)
                self.b_setAnimState('neutral')
            elif self.animFSM.getCurrentState().getName() == 'deadWalk':
                self.playMovementSfx('run')
                self.b_setAnimState('run')
        DistributedToon.setHealth(self, hp)
        return

    def diedStateDone(self, requestStatus):
        hood = self.cr.playGame.hood.id
        if hood == CIGlobals.BattleTTC:
            hood = CIGlobals.ToontownCentral
        toZone = ZoneUtil.getZoneId(hood)
        if self.zoneId != toZone:
            requestStatus = {'zoneId': toZone,
             'hoodId': hood,
             'where': ZoneUtil.getWhereName(toZone),
             'avId': self.doId,
             'loader': ZoneUtil.getLoaderName(toZone),
             'shardId': None,
             'wantLaffMeter': 1,
             'how': 'teleportIn'}
            self.cr.playGame.getPlace().doneStatus = requestStatus
            messenger.send(self.cr.playGame.getPlace().doneEvent)
        else:
            return
        return

    def teleportToCT(self):
        toZone = CIGlobals.CogTropolisId
        hood = CIGlobals.CogTropolis
        requestStatus = {'zoneId': toZone,
         'hoodId': hood,
         'where': ZoneUtil.getWhereName(toZone),
         'avId': self.doId,
         'loader': ZoneUtil.getLoaderName(toZone),
         'shardId': None,
         'wantLaffMeter': 1,
         'how': 'teleportIn'}
        self.cr.playGame.getPlace().fsm.request('teleportOut', [requestStatus])
        return

    def createChatInput(self):
        self.chatInput.load()
        self.chatInput.enter()

    def disableChatInput(self):
        self.chatInput.exit()
        self.chatInput.unload()

    def collisionsOn(self):
        self.controlManager.collisionsOn()

    def collisionsOff(self):
        self.controlManager.collisionsOff()

    def generate(self):
        DistributedToon.generate(self)

    def delete(self):
        DistributedToon.delete(self)
        self.deleteLaffMeter()

    def disable(self):
        base.camLens.setMinFov(CIGlobals.OriginalCameraFov / (4.0 / 3.0))
        self.friendsList.destroy()
        self.friendsList = None
        self.positionExaminer.delete()
        self.positionExaminer = None
        self.disablePicking()
        self.stopMonitoringHP()
        taskMgr.remove('resetHeadColorAfterFountainPen')
        taskMgr.remove('LT.attackReactionDone')
        self.stopLookAround()
        DistributedToon.disable(self)
        self.disableAvatarControls()
        self.disableLaffMeter()
        self.disablePies()
        self.disableChatInput()
        self.weaponType = None
        self.pieType = None
        self.myBattle = None
        self.ignore('gotLookSpot')
        return

    def announceGenerate(self):
        DistributedToon.announceGenerate(self)
        self.setupPicker()
        self.setupControls()
        self.startLookAround()
        self.friendRequestManager.watch()
        self.accept('gotLookSpot', self.handleLookSpot)

    def printAvPos(self):
        print 'Pos: %s, Hpr: %s' % (self.getPos(), self.getHpr())
예제 #26
0
class Life(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        base.disableMouse()
        base.setFrameRateMeter(True)

        mydir = os.path.abspath(sys.path[0])
        mydir = Filename.fromOsSpecific(mydir).getFullpath()

        self.bgmusic = self.loader.loadMusic(mydir + '/../sounds/bgmusic.ogg')
        self.bgmusic.play()

        # Setup collision for 3d picking
        self.picker = CollisionTraverser()
        self.pq = CollisionHandlerQueue()
        # 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 separate it
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        # Register the ray as something that can cause collisions
        self.picker.addCollider(self.pickerNP, self.pq)
        #self.picker.showCollisions(render)

        # Configure boxes and textures
        self.box = [[None for x in range(CELL_WIDTH)] for x in range(CELL_HEIGHT)]
        self.textureempty = self.loader.loadTexture(mydir + '/../textures/box.png')
        self.texturefull = self.loader.loadTexture(mydir + '/../textures/boxfull.png')

        self.textureempty.setMagfilter(Texture.FTLinear)
        self.textureempty.setMinfilter(Texture.FTLinearMipmapLinear)
        self.texturefull.setMagfilter(Texture.FTLinear)
        self.texturefull.setMinfilter(Texture.FTLinearMipmapLinear)

        self.worldnode = render.attachNewNode('worldnode')
        self.boxnode = self.worldnode.attachNewNode('boxnode')

        self.worldnode.setPos(0, 200, 0)

        for row in range(CELL_HEIGHT):
            for col in range(CELL_WIDTH):
                box = self.loader.loadModel(mydir + '/../models/cube')
                box.reparentTo(self.boxnode)
                box.setPos((CELL_WIDTH * -1) + (col * 2), 0, CELL_HEIGHT - (row * 2))
                box.setTexture(self.textureempty)

                # Cube is the name of the polygon set in blender
                box.find("**/Cube").node().setIntoCollideMask(BitMask32.bit(1))
                box.find("**/Cube").node().setTag('square', str(row) + '-' + str(col))

                self.box[row][col] = box

        # Configure cell data
        self.cells = [[0 for x in range(CELL_WIDTH)] for x in range(CELL_HEIGHT)]
        self.cells[3][6] = 1
        self.cells[4][7] = 1
        self.cells[5][5] = 1
        self.cells[5][6] = 1
        self.cells[5][7] = 1

        self.editmode = False

        taskMgr.add(self.start, 'start')

        # Setup initial event handling
        self.accept('escape', sys.exit)
        self.accept('enter', self.startgame)
        self.accept('mouse1', self.startgame)

        # Prep the main screen
        self.boxnode.setPosHpr(self.worldnode, -5, -160, 0, 60, -25, 0)
        self.readyText = OnscreenText(text='Life', pos=(0.91, 0.7), scale=0.2, fg=(255, 255, 255, 255),
                                      shadow=(0, 0, 0, 100))

    def mouserotation(self, task):
        if not self.editmode and base.mouseWatcherNode.hasMouse():
            self.boxnode.setH(self.worldnode, base.mouseWatcherNode.getMouseX() * 60)
            self.boxnode.setP(self.worldnode, -base.mouseWatcherNode.getMouseY() * 60)

        return task.cont

    def startgame(self):
        # Transition to the game start state
        taskMgr.add(self.transition, 'transition')
        interval = LerpPosHprInterval(self.boxnode, TRANSITIONPERIOD, Point3(0, 0, 0), Point3(0, 0, 0),
                                      other=self.worldnode, blendType='easeInOut')
        interval.start()

    def transition(self, task):
        self.ignore('enter')
        self.ignore('mouse1')
        self.readyText.setFg((255, 255, 255, (max(0, TRANSITIONPERIOD - task.time) / TRANSITIONPERIOD)))
        self.readyText.setShadow((0, 0, 0, (max(0, TRANSITIONPERIOD - task.time) / TRANSITIONPERIOD)))

        if task.time > TRANSITIONPERIOD:
            self.accept('enter', self.handleenter)
            self.accept('mouse1', self.selectpiece)
            taskMgr.add(self.mouserotation, 'mouserotation')
            return task.done
        else:
            return task.cont

    def selectpiece(self):
        if self.editmode:
            mpos = base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())

            #Do the actual collision pass (Do it only on the squares for
            #efficiency purposes)
            self.picker.traverse(self.boxnode)
            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()
                tag = self.pq.getEntry(0).getIntoNode().getTag('square')
                tagsplit = tag.split('-')
                row = int(tagsplit[0])
                col = int(tagsplit[1])

                # Set the highlight on the picked square
                self.cells[row][col] = (0 if self.cells[row][col] == 1 else 1)

    def start(self, task):
        if not self.editmode:
            self.processcells(self.cells)

        for row in range(CELL_HEIGHT):
            for col in range(CELL_WIDTH):
                if self.cells[row][col] == 1:
                    self.box[row][col].setTexture(self.texturefull)
                else:
                    self.box[row][col].setTexture(self.textureempty)

        return task.cont

    def handleenter(self):
        self.editmode = not self.editmode

    @staticmethod
    def countsiblingcells(cells, x, y):
        return cells[y - 1][x - 1] + \
               cells[y][x - 1] + \
               cells[(y + 1) % CELL_HEIGHT][x - 1] + \
               cells[y - 1][x] + \
               cells[(y + 1) % CELL_HEIGHT][x] + \
               cells[y - 1][(x + 1) % CELL_WIDTH] + \
               cells[y][(x + 1) % CELL_WIDTH] + \
               cells[(y + 1) % CELL_HEIGHT][(x + 1) % CELL_WIDTH]

    def processcells(self, cells):
        newcells = copy.deepcopy(cells)

        for row in range(CELL_HEIGHT):
            for col in range(CELL_WIDTH):
                neighbours = self.countsiblingcells(newcells, col, row)

                if newcells[row][col] == 1:
                    if neighbours < 2:
                        cells[row][col] = 0
                    elif 2 <= neighbours <= 3:
                        pass
                    elif neighbours > 3:
                        cells[row][col] = 0
                else:
                    if neighbours == 3:
                        cells[row][col] = 1
예제 #27
0
class MyApp(ShowBase):
    
    def __init__(self):
        ShowBase.__init__(self)

        # Create a traverser and a handler
        self.cTrav = CollisionTraverser()
        self.cQueue = CollisionHandlerQueue()

        # Create the collision node that will store the collision
        # ray solid 
        self.pickerNode = CollisionNode('mouseRay')
        # Set bitmask for efficiency, only hit from objects with same mask
        self.pickerNode.setFromCollideMask(BitMask32.bit(1))
        # Attach collision node to camera, since that is the source
        self.pickerNP = camera.attachNewNode(self.pickerNode)

        # Add collision solid(ray) to collision node
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        # Add collidable node(pickerNP) to the traverser
        # Collisions detected when traversed will go to cQueue
        self.cTrav.addCollider(self.pickerNP, self.cQueue)

        # Create visible sphere
        self.tmpSphere = self.loader.loadModel("models/misc/sphere")
        self.tmpSphere.reparentTo(self.render)
        self.tmpSphere.setColor(1, 1, 1, 1)
        self.tmpSphere.setPos(0, 100, 0)
        
        # Create collision sphere and attach to tmpSphere
        cSphere = CollisionSphere(0, 0, 0, 3)
        cnodePath = self.tmpSphere.attachNewNode(CollisionNode('cnode'))
        # Add collision solid(sphere) to collision node
        # Because tmpSphere/cSphere is child of render, which we traverse
        # later, it becomes a from collider automatically, we don't
        # need to addCollider since that is only for from collision nodes
        cnodePath.node().addSolid(cSphere)
        # Set bitmask to match the from collisionnode mask for efficiency
        cnodePath.setCollideMask(BitMask32.bit(1))
        # Show the collision sphere visibly, for debugging.
        cnodePath.show()
        # Set a custom tag on the collision node which becomes available
        # inside the collision event stored in the collision handler
        cnodePath.setTag('someTag', '1')

        # Add task to run every frame - set collision solid(ray)
        # to start at the current camera position, 
        self.mouseTask = taskMgr.add(self.mouseTask, 'mouseTask')

    def mouseTask(self, task):
        if self.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            # Set collision ray to start at camera lens and endpoint at mouse
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            # Perform the collision traverse - follows the ray and logs
            # all collisions to the handler set earlier
            self.cTrav.traverse(self.render)
            # Get info from entries and use them
            if self.cQueue.getNumEntries() > 0:
                self.cQueue.sortEntries()
                print("Collision!")
                entry = self.cQueue.getEntry(0)
                print(entry)
                someTag = int(entry.getIntoNode().getTag('someTag'))
                print(someTag)
                # Collision detected, mouse must be over sphere
                self.tmpSphere.setColor(0,1,0,1)
            else:
                # No collisions, mouse is not over sphere, unset color
                # Not ideal to "unset" the color each frame
                self.tmpSphere.setColor(1,1,1,1)
        return task.cont
예제 #28
0
class MouseHandler(object):
	def __init__(self,pandaScene):
		self.pandaScene = pandaScene

	def setupMouseCollisionWM(self):
		self.mouseTraverser = CollisionTraverser()
		self.mouseCollisionQueue    = CollisionHandlerQueue()
		self.mouseRay = CollisionRay()
		self.mouseRay.setOrigin(self.pandaScene.worldMapCam.getPos(self.pandaScene.render))
		self.mouseRay.setDirection(self.pandaScene.render.getRelativeVector(self.pandaScene.worldMapCam, Vec3(0,1,0)))
		self.mouseNode = CollisionNode('mouseRay')
		self.mouseNode.addSolid(self.mouseRay)
		self.mouseNodePath = self.pandaScene.worldMapCam.attachNewNode(self.mouseNode)
		self.mouseNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
		self.mouseTraverser.addCollider(self.mouseNodePath, self.mouseCollisionQueue)

		# uncomment to see the collisions
		# self.mouseTraverser.showCollisions(self.pandaScene.render)	


	def selectedObjectIdWM(self):
		if (self.pandaScene.worldMapMouse.hasMouse() == False):
			return 0,None
		mpos = self.pandaScene.worldMapMouse.getMouse()
		self.mouseRay.setFromLens(self.pandaScene.camNode, mpos.getX(), mpos.getY())
		self.mouseTraverser.traverse(self.pandaScene.render)

		if (self.mouseCollisionQueue.getNumEntries() > 0):
			self.mouseCollisionQueue.sortEntries()
			entry     = self.mouseCollisionQueue.getEntry(0);
			selectedObj = entry.getIntoNodePath()
			selectedObj = selectedObj.findNetTag('selectable')
			if not selectedObj.isEmpty():
				return selectedObj.getTag('id'),selectedObj
			else:
				return 0,None
		return 0,None

	def selectedObjectId(self):
		if (self.pandaScene.mouseWatcherNode.hasMouse() == False):
			return 0,None
		mpos = base.mouseWatcherNode.getMouse()
		self.mouseRay.setFromLens(self.pandaScene.camNode, mpos.getX(), mpos.getY())
		self.mouseTraverser.traverse(self.pandaScene.render)

		if (self.mouseCollisionQueue.getNumEntries() > 0):
			self.mouseCollisionQueue.sortEntries()
			entry     = self.mouseCollisionQueue.getEntry(0);
			selectedObj = entry.getIntoNodePath()
			selectedObj = selectedObj.findNetTag('selectable')
			if not selectedObj.isEmpty():
				return selectedObj.getTag('id'),selectedObj
			else:
				return 0,None	
		return 0,None

	def setupMouseCollision(self):
		self.mouseTraverser = CollisionTraverser()
		self.mouseCollisionQueue    = CollisionHandlerQueue()
		self.mouseRay = CollisionRay()
		self.mouseRay.setOrigin(self.pandaScene.camera.getPos(self.pandaScene.render))
		self.mouseRay.setDirection(self.pandaScene.render.getRelativeVector(self.pandaScene.camera, Vec3(0,1,0)))
		self.mouseNode = CollisionNode('mouseRay')
		self.mouseNode.addSolid(self.mouseRay)
		self.mouseNodePath = self.pandaScene.camera.attachNewNode(self.mouseNode)
		self.mouseNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
		self.mouseTraverser.addCollider(self.mouseNodePath, self.mouseCollisionQueue)
예제 #29
0
class World(ShowBase):

	def __init__(self):
		ShowBase.__init__(self)

		#PStatClient.connect()

		#self.lookPoint = NodePath(PandaNode("floater"))
		self.lookPoint = self.loader.loadModel("models/cone")
		self.lookPoint.reparentTo(render)

		self.menu = StartMenu(self)
		#self.bar = Bar()

		#self.messenger.toggleVerbose()


		#sys.exit()
		#pdb.set_trace()

		# Window change event handler
		#self.windowEventSetup()



	def setup(self):

		print("Init Levels...")
		self.initLevels()

		print("Init World...")
		self.initWorld("yard")

		print("Init Items...")
		self.initItems()

		print("Init Actors...")
		self.initActors()

		print("Init GUI ...")
		self.initGui()

		print("Init Lights...")
		self.initLights()

		print("Init Collisions...")
		self.initCollision()

		print("Init Tasks...")
		self.initTasks()

		print("Launching World")

		# Accept the control keys
		#self.accept("h", self.crono.start)

	def initItems(self):

		with open('items/items.json') as items_file:
			self.items = json.load(items_file)

	def initActors(self):

		self.player = Player(self, 20, 10, 10, 10, 10, 10) #app, hp, mana, strength, dexterity, vigor, magic):

		self.enemies = []
		self.npcs = []

		#Creating AI World

		self.AIworld = AIWorld(render)

		"""self.foe1 = Enemy(self, 100, 50, 5, 2, "bug") #(self, app, hp, mana, speed, attackSpeed, name):
		self.nasgul = Enemy(self, 100, 50, 5, 2, "nasgul")

		self.npc1 = Npc(self, 100, 50, 5, 2, "guy2")
		self.npc2 = Npc(self, 100, 50, 5, 2, "ralph")

		self.enemies.append(self.foe1)
		self.enemies.append(self.nasgul)

		self.npcs.append(self.npc1)
		self.npcs.append(self.npc2)"""


	def initGui(self):

		# Load the models.

		self.inventory = Inventory(self)
		self.status = Status(self)
		self.skills = Skills(self)

		#self.statusBar = self.loader.loadModel("models/statusbar")


		##self.statusBar.setDepthTest(True)
		#self.statusBar.setDepthWrite(True)


		# Reparent the model to render2d.
		#self.statusBar.reparentTo(self.render2d)


		#self.statusBar.setScale(0.15, 0.15, 0.15)
		#self.statusBar.setPos(-0.95, 0, 0.65)


		#self.crono = Crono(self)
		##self.cursorpos = CursorPos(self)
		#self.playerpos = PlayerPos(self)

		#self.crono.draw(0.7, -0.85)
		#self.cursorpos.draw(0.0, -0.85)
		#self.playerpos.draw(-0.7, -0.85)


		self.accept("i", self.inventory.toggle)
		self.accept("c", self.status.toggle)
		self.accept("k", self.skills.toggle)

	def initTasks(self):

		#self.taskMgr.add(self.crono.task, "cronoTask")
		#self.taskMgr.add(self.cursorpos.task, "cursorposTask")

		###self.taskMgr.add(self.playerpos.task, "playerposTask")

		self.taskMgr.add(self.checkCollision, "collisionTask")

		#self.taskMgr.add(self.player.update, "updateTask")
		self.taskMgr.add(self.player.move, "moveTask")
		self.taskMgr.add(self.player.updateCamera, "playerCameraTask",priority=1)
		"""
		#self.taskMgr.add(self.foe1.update, "bugTask",priority=1)
		#self.taskMgr.add(self.nasgul.update, "nasgulTask",priority=1)

		#self.taskMgr.add(self.npc1.update, "npc1Task",priority=1)
		#self.taskMgr.add(self.npc2.update, "npc2Task",priority=1)
		"""
		self.taskMgr.add(self.update, 'update')

	def initLights(self):
		# Create some lighting

		#self.environ.ls()

		#print(self.environ.findAllMatches("**/Spot"))

		ambientLight = AmbientLight("ambientLight")
		ambientLight.setColor(Vec4(0.8, 0.8, 0.8, 0.65))

		"""
		directionalLight = DirectionalLight("directionalLight")
		directionalLight.setDirection(Vec3(-10, -10, 5))
		directionalLight.showFrustum()
		directionalLight.setColor(Vec4(1, 1, 1, 1))
		directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
		dirnp = render.attachNewNode(directionalLight)
		dirnp.setPos(10, 0, 6)
		"""

		plight1 = PointLight('plight1')
		plight1.setColor(VBase4(1, 1, 1, 1))
		plight1.showFrustum()
		#plight1.setShadowCaster(True)
		plnp1 = render.attachNewNode(plight1)
		plnp1.setPos(26.71, -33.2, 26)

		plight2 = PointLight('plight2')
		plight2.setColor(VBase4(1, 1, 1, 1))
		plight2.showFrustum()
		plnp2 = render.attachNewNode(plight2)
		plnp2.setPos(-25, 25, 25)

		slight = Spotlight('slight')
		slight.setColor(VBase4(1, 1, 1, 1))
		lens = PerspectiveLens()
		lens.setFilmSize(1, 1)  # Or whatever is appropriate for your scene
		slight.setLens(lens)
		slight.setShadowCaster(True, 512, 512)
		slight.showFrustum()
		slnp = render.attachNewNode(slight)
		slnp.setPos(0, 0, 100)

		slnp.lookAt(Vec3(0,0,0))

		render.setLight(slnp)
		render.setLight(plnp1)
		render.setLight(plnp2)
		#render.setLight(render.attachNewNode(ambientLight))

		#render.setLight(dirnp)

		render.setShaderAuto()

		#render.setLight(render.attachNewNode(directionalLight))

		"""
		self.light = render.attachNewNode(Spotlight("Spot"))
		self.light.node().setScene(render)
		self.light.node().setShadowCaster(True)
		self.light.node().showFrustum()
		self.light.node().getLens().setFov(40)
		self.light.node().getLens().setNearFar(10,100)
		render.setLight(self.light)
		"""

	def initLevels(self):
		with open('levels/levels.json') as levels_file:
			self.levels = json.load(levels_file)

	def initWorld(self, level):

		self.environ = self.loader.loadModel(self.levels["levels"][level]["model"])
		#self.environ.setScale(20, 20, 20)
		#self.environ.setHpr(0, 0, 0)
		self.environ.setPos(0, 0, 0)

		self.playerStartPos = self.environ.find("**/startPos").getPos()

		# Reparent the model to render

		self.environ.reparentTo(render)
		#self.environ.ls()
		self.accept("q", self.changeMap)

	def destroyWorld(self):

		self.environ.detachNode()
		self.environ.removeNode()

	def changeMap(self):#, levelName):
		self.destroyWorld()
		self.initWorld("yard")

	def update(self, task):
		dt = globalClock.getDt()

		self.AIworld.update()
		return task.cont

	def setKey(self, key, value):
		self.keyMap[key] = value

	def windowEventSetup( self ):
		# accept the window event's
		self.accept( 'window-event', self.windowEventHandler)
		# create a window event yourself
		#messenger.send( 'window-event', [self.win] )

	def windowEventHandler( self, window=None ):
		wp = window.getProperties()

		print("Window changed")
		print("X = %s" % wp.getXSize())
		print("Y = %s" % wp.getYSize())
		self.setResolution( wp.getXSize(), wp.getYSize() )

	def setResolution( self, w, h ):
		wp = WindowProperties()
		wp.setSize( w, h )

		if os.name == 'posix':
			self.openMainWindow()
			self.graphicsEngine.openWindows()
		self.win.requestProperties( wp )

	# Define a procedure to move the camera.
	def spinCameraTask(self, task):
		angleDegrees = task.time * 6.0
		angleRadians = angleDegrees * (pi / 180.0)
		self.camera.setPos(40 * sin(angleRadians), -10.0 * cos(angleRadians), 3)
		self.camera.setHpr(angleDegrees, 0, 0)
		return Task.cont

	def initCollision(self):


		self.enemyGroundRay = []
		self.enemyGroundCol = []
		self.enemyGroundColNp = []
		self.enemyGroundHandler = []

		self.npcGroundRay = []
		self.npcGroundCol = []
		self.npcGroundColNp = []
		self.npcGroundHandler = []

		self.cTrav = CollisionTraverser()


		self.playerGroundRay = CollisionRay()
		self.playerGroundRay.setOrigin(0, 0, 9)
		self.playerGroundRay.setDirection(0, 0, -1)
		self.playerGroundCol = CollisionNode('playerRay')
		self.playerGroundCol.addSolid(self.playerGroundRay)
		self.playerGroundCol.setFromCollideMask(CollideMask.bit(0))
		self.playerGroundCol.setIntoCollideMask(CollideMask.allOff())
		self.playerGroundColNp = self.player.moveFloater.attachNewNode(self.playerGroundCol)
		self.playerGroundHandler = CollisionHandlerQueue()
		self.cTrav.addCollider(self.playerGroundColNp, self.playerGroundHandler)

		self.mouseGroundRay = CollisionRay()
		self.mouseGroundRay.setOrigin(0, 0, 9)
		self.mouseGroundRay.setDirection(0, 0, -1)
		self.mouseGroundCol = CollisionNode('mouseRay')
		self.mouseGroundCol.addSolid(self.mouseGroundRay)
		self.mouseGroundCol.setFromCollideMask(CollideMask.bit(0))
		self.mouseGroundCol.setIntoCollideMask(CollideMask.allOff())
		self.mouseGroundColNp = self.camera.attachNewNode(self.mouseGroundCol)
		self.mouseGroundHandler = CollisionHandlerQueue()
		self.cTrav.addCollider(self.mouseGroundColNp, self.mouseGroundHandler)

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

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


		i = 0
		for enemy in self.enemies:

			self.enemyGroundRay.append(CollisionRay())
			self.enemyGroundRay[i].setOrigin(0, 0, 9)
			self.enemyGroundRay[i].setDirection(0, 0, -1)

			self.enemyGroundCol.append(CollisionNode('%sRay' % enemy.name))
			self.enemyGroundCol[i].addSolid(self.enemyGroundRay[i])
			self.enemyGroundCol[i].setFromCollideMask(CollideMask.bit(0))
			self.enemyGroundCol[i].setIntoCollideMask(CollideMask.allOff())

			self.enemyGroundColNp.append(enemy.enemyActor.attachNewNode(self.enemyGroundCol[i]))
			self.enemyGroundHandler.append(CollisionHandlerQueue())
			self.cTrav.addCollider(self.enemyGroundColNp[i], self.enemyGroundHandler[i])

			#self.enemyGroundColNp.show()
			i += 1

		i = 0
		for npc in self.npcs:

			self.npcGroundRay.append(CollisionRay())
			self.npcGroundRay[i].setOrigin(0, 0, 9)
			self.npcGroundRay[i].setDirection(0, 0, -1)

			self.npcGroundCol.append(CollisionNode('%sRay' % npc.name))
			self.npcGroundCol[i].addSolid(self.npcGroundRay[i])
			self.npcGroundCol[i].setFromCollideMask(CollideMask.bit(0))
			self.npcGroundCol[i].setIntoCollideMask(CollideMask.allOff())

			self.npcGroundColNp.append(npc.npcActor.attachNewNode(self.npcGroundCol[i]))
			self.npcGroundHandler.append(CollisionHandlerQueue())
			self.cTrav.addCollider(self.npcGroundColNp[i], self.npcGroundHandler[i])

			#self.npcGroundColNp.show()
			i += 1

	def checkCollision(self, task):

		startpos = self.player.moveFloater.getPos()

		entries = list(self.playerGroundHandler.getEntries())
		entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

		for entry in entries:
			if entry > 0 and entries[0].getIntoNode().getName() == "Ground":
				self.player.moveFloater.setZ(entry.getSurfacePoint(render).getZ())
			else:
				self.player.moveFloater.setPos(startpos)

		if self.mouseWatcherNode.hasMouse():

			mpos = self.mouseWatcherNode.getMouse()

			self.mouseGroundRay.setFromLens(self.camNode, mpos.getX(), mpos.getY())


			nearPoint = render.getRelativePoint(self.camera, self.mouseGroundRay.getOrigin())
			nearVec = render.getRelativeVector(self.camera, self.mouseGroundRay.getDirection())
			try:
				self.lookPoint.setPos(PointAtZ(self.player.moveFloater.getZ(), nearPoint, nearVec))
			except:
				pass

		i = 0

		for enemy in self.enemies:
			startpos = enemy.enemyActor.getPos()

			entries = list(self.enemyGroundHandler[i].getEntries())
			entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

			for entry in entries:
				if entry > 0: # and entries[0].getIntoNode().getName() == "Ground":
					enemy.enemyActor.setZ(entry.getSurfacePoint(render).getZ())
				else:
					enemy.enemyActor.setPos(startpos)
			i += 1


		i = 0
		for npc in self.npcs:
			startpos = npc.npcActor.getPos()

			entries = list(self.npcGroundHandler[i].getEntries())
			entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())

			for entry in entries:
				if entry > 0: # and entries[0].getIntoNode().getName() == "Ground":
					npc.npcActor.setZ(entry.getSurfacePoint(render).getZ())
				else:
					npc.npcActor.setPos(startpos)
			i += 1

		return task.cont
예제 #30
0
class World(DirectObject):
    def __init__(self):

        # The standard camera, light and background initialization
        base.setBackgroundColor(0, 0, 0)
        base.disableMouse()
        self.cam_ctrl = CameraController()
        self.cam_ctrl.reset()
        alight = AmbientLight('alight')
        alight.setColor((0.2, 0.2, 0.2, 1))
        alnp = render.attachNewNode(alight)
        render.setLight(alnp)

        # The global variables we use to control the speed and size of objects
        self.yearscale = 900
        self.dayscale = self.yearscale / 365.0 * 30
        self.yearCounter = 0
        self.dayCounter = 0
        self.money = 2000
        self.system_population = 0
        self.orbitscale = 10
        self.sizescale = 0.6

        # Global game balance variables
        self.population_time_delta = 3
        self.tax_factor = 0.1
        self.salvage_factor = 0.75
        self.food_consuming_factor = 0.75
        self.goods_cap = 1000

        self.PlanetInfoModeOn = False
        self.capitalPlanet = None

        self.galaxy_objects = []
        self.BuildingsDB = {}  # Will contain all buildable structures

        # Everything that's needed to detect selecting objects with mouse
        self.pickerNode = CollisionNode('mouseRay')
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        self.pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        self.collQueue = CollisionHandlerQueue()
        base.cTrav = CollisionTraverser('myTraverser')
        base.cTrav.addCollider(self.pickerNP, self.collQueue)

        # Set up the start screen
        self.create_gui()
        self.NewPlanetInfoView = PlanetInfoView(self)
        self.NewPlanetBuildView = PlanetBuildView(self)

        self.load_planets()
        self.rotate_planets()
        self.BuildingsDB = buildingsDB.loadDB()
        self.set_capital_planet()

        # Add all constantly running checks to the taskmanager
        taskMgr.add(self.redraw_head_gui, "redrawHeadGUITask")
        taskMgr.doMethodLater(self.population_time_delta,
                              self.populate_planet_task,
                              'populatePlanetTask',
                              extraArgs=[self.Earth],
                              appendTask=True)
        taskMgr.doMethodLater(2, self.generate_money_task, 'generateMoneyTask')

        # Open up all listeners for varous mouse and keyboard inputs
        self.accept("escape", sys.exit)
        self.accept('mouse1', self.handle_mouse_click)

    # ****************************************
    #         Main Gameplay Functions        *
    # ****************************************

    # Camera, controle and main GUI functions
    # ----------------------------------------

    def handle_mouse_click(self):
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
            base.cTrav.traverse(render)
            if self.collQueue.getNumEntries() > 0:
                self.collQueue.sortEntries()
                pickedObj = self.collQueue.getEntry(0).getIntoNodePath()
                pickedObj = pickedObj.findNetTag('clickable')
                if not pickedObj.isEmpty() and not self.PlanetInfoModeOn:
                    instance = pickedObj.getPythonTag('instance')
                    self.toggle_planet_info_mode(True, instance)

    def redraw_head_gui(self, task):
        self.HeadGUIText['text'] = ('Year ' + str(self.yearCounter) + ', '
                                    'Day ' + str(self.dayCounter) + ', '
                                    'Money: ' + str(self.money) + ', '
                                    'Population: ' +
                                    str(self.system_population))
        return task.cont

    # Smaller single line functions
    # -----------------------------

    def incYear(self):
        self.yearCounter += 1

    def incDay(self):
        self.dayCounter += 1

    # Functions to interact with the planet info view
    # ------------------------------------------------

    def toggle_planet_info_mode(self, mode=False, obj=None):

        if mode:
            self.MapViewPanel.hide()
            self.PlanetInfoModeOn = True

            self.NewPlanetInfoView.reset(obj)
            zoomInterval = Sequence(Func(self.cam_ctrl.info_view_to, obj),
                                    Wait(0.2),
                                    Func(self.NewPlanetInfoView.show))
            zoomInterval.start()
        else:
            self.PlanetInfoModeOn = False
            self.cam_ctrl.reset()
            taskMgr.remove('updatePlanetInfoTask')
            self.NewPlanetInfoView.hide()

    # Global general purpose functions and tasks
    # ---------------------------------------------------

    def populate_planet_task(self, planet, task):
        habProblem = planet.habitation_cap <= planet.population
        foodProblem = (not ('Vegetable crates' in planet.goods)
                       or planet.goods['Vegetable crates'] < planet.population)
        nutrition_decrease = round(planet.population *
                                   self.food_consuming_factor)

        if foodProblem:
            d = random.randint(-1, 2)
            if planet.population - d <= 0:
                planet.population = 0
            else:
                planet.population -= d
        elif habProblem:
            pass
            planet.goods['Vegetable crates'] -= nutrition_decrease
        else:
            planet.population += random.randint(1, 3)
            planet.goods['Vegetable crates'] -= nutrition_decrease
        return task.again

    def count_system_population(self):
        wholePop = 0
        for obj in self.galaxy_objects:
            if type(obj) != Star:
                wholePop += obj.population
        self.system_population = wholePop

    def generate_money_task(self, task):
        self.count_system_population()
        self.money += round(self.system_population * self.tax_factor)
        return task.again

    def add_message(self, planet, id, mType, text, value):
        planet.messages.update(
            {id: {
                'type': mType,
                'text': text,
                'value': value
            }})

    def remove_message(self, planet, id):
        if id in planet.messages:
            planet.messages.pop(id)

    def calc_distance_between_planets(self, planet1, planet2):
        pos1 = planet1.getPos()
        pos2 = planet2.getPos()
        diffX = abs(pos1[0] - pos2[0])
        diffY = abs(pos1[1] - pos2[1])
        dist = math.sqrt(diffX**2 + diffY**2)
        return dist

    def create_dialog(self,
                      problemText,
                      form='ok',
                      function=lambda: None,
                      args=[]):
        if form == 'ok':
            self.ProblemDialog = OkDialog(dialogName="OkDialog",
                                          text=problemText,
                                          text_pos=(0, 0.07),
                                          command=self.cleanup_dialog,
                                          midPad=(-0.15),
                                          frameColor=(0, 0, 0, 0),
                                          text_fg=(1, 1, 1, 1),
                                          text_align=TextNode.ACenter,
                                          geom=self.dialog_map,
                                          extraArgs=[function, args])
        elif form == 'yesNo':
            self.ProblemDialog = YesNoDialog(dialogName="OkDialog",
                                             text=problemText,
                                             text_pos=(0, 0.07),
                                             command=self.cleanup_dialog,
                                             midPad=(-0.15),
                                             frameColor=(0, 0, 0, 0),
                                             text_fg=(1, 1, 1, 1),
                                             text_align=TextNode.ACenter,
                                             geom=self.dialog_map,
                                             extraArgs=[function, args])

    def cleanup_dialog(self, value, function, args):
        self.ProblemDialog.cleanup()
        if value:
            function(*args)

    # ****************************************
    #        Initialisation Functions        *
    # ****************************************

    def load_planets(self):
        self.orbit_root_mercury = render.attachNewNode('orbit_root_mercury')
        self.orbit_root_venus = render.attachNewNode('orbit_root_venus')
        self.orbit_root_mars = render.attachNewNode('orbit_root_mars')
        self.orbit_root_earth = render.attachNewNode('orbit_root_earth')

        self.orbit_root_moon = (
            self.orbit_root_earth.attachNewNode('orbit_root_moon'))

        self.sky = loader.loadModel("models/sky_dome.blend")

        self.sky_tex = loader.loadTexture("models/sky_tex2_cut.jpg")
        self.sky_tex.setWrapU(Texture.WM_clamp)
        self.sky.setTexture(self.sky_tex, 1)
        self.sky.reparentTo(render)
        self.sky.setScale(300)
        self.sky.setHpr(270, 0, 0)

        self.Sun = Star(self, 'Sun', 'models/planet_sphere',
                        'models/sun_1k_tex.jpg', 2)

        self.Mercury = Planet(self, 'Mercury', 'models/planet_sphere',
                              'models/mercury_1k_tex.jpg',
                              self.orbit_root_mercury, 0.385, 0.38, False, 1, {
                                  'Coal': 'Common',
                                  'Iron': 'Common'
                              })

        self.Venus = Planet(self, 'Venus', 'models/planet_sphere',
                            'models/venus_1k_tex.jpg', self.orbit_root_venus,
                            0.923, 0.72, False, 2, {
                                'Coal': 'Common',
                                'Uranium': 'Normal'
                            })

        self.Mars = Planet(self, 'Mars', 'models/planet_sphere',
                           'models/mars_1k_tex.jpg', self.orbit_root_mars,
                           0.512, 1.52, False, 1, {
                               'Gemstone': 'Rare',
                               'Iron': 'Rare'
                           })
        self.Mars.probed = True

        self.Earth = Planet(self, 'Earth', 'models/planet_sphere',
                            'models/earth_1k_tex.jpg', self.orbit_root_earth,
                            1, 1, True, 1, {
                                'Iron': 'Normal',
                                'Coal': 'Common'
                            })

        self.orbit_root_moon.setPos(self.orbitscale, 0, 0)

        self.Earth_Moon = Moon(self, 'Moon', 'models/planet_sphere',
                               'models/moon_1k_tex.jpg', self.orbit_root_moon,
                               0.1, 0.1, False, 0, {
                                   'Cheese': 'Rare',
                                   'Coal': 'Common'
                               })

    def rotate_planets(self):
        self.day_period_sun = self.Sun.model.hprInterval(20, (360, 0, 0))

        self.orbit_period_mercury = self.orbit_root_mercury.hprInterval(
            (0.241 * self.yearscale), (360, 0, 0))
        self.day_period_mercury = self.Mercury.model.hprInterval(
            (59 * self.dayscale), (360, 0, 0))

        self.orbit_period_venus = self.orbit_root_venus.hprInterval(
            (0.615 * self.yearscale), (360, 0, 0))
        self.day_period_venus = self.Venus.model.hprInterval(
            (243 * self.dayscale), (360, 0, 0))

        self.orbit_period_earth = Sequence(
            self.orbit_root_earth.hprInterval(self.yearscale, (360, 0, 0)),
            Func(self.incYear))
        self.day_period_earth = Sequence(
            self.Earth.model.hprInterval(self.dayscale, (360, 0, 0)),
            Func(self.incDay))

        self.orbit_period_moon = self.orbit_root_moon.hprInterval(
            (.0749 * self.yearscale), (360, 0, 0))
        self.day_period_moon = self.Earth_Moon.model.hprInterval(
            (.0749 * self.yearscale), (360, 0, 0))

        self.orbit_period_mars = self.orbit_root_mars.hprInterval(
            (1.881 * self.yearscale), (360, 0, 0))
        self.day_period_mars = self.Mars.model.hprInterval(
            (1.03 * self.dayscale), (360, 0, 0))

        self.day_period_sun.loop()
        self.orbit_period_mercury.loop()
        self.day_period_mercury.loop()
        self.orbit_period_venus.loop()
        self.day_period_venus.loop()
        self.orbit_period_earth.loop()
        self.day_period_earth.loop()
        self.orbit_period_moon.loop()
        self.day_period_moon.loop()
        self.orbit_period_mars.loop()
        self.day_period_mars.loop()

    def set_capital_planet(self):
        self.capitalPlanet = self.Earth
        self.Earth.probed = True
        self.Earth.colonised = True
        self.Earth.population = 100
        self.Earth.habitation_cap = 100

    def create_gui(self):
        self.buttonModel = loader.loadModel(
            'models/gui/buttons/simple_button_maps.egg')
        self.buttonMaps = (self.buttonModel.find('**/normal'),
                           self.buttonModel.find('**/active'),
                           self.buttonModel.find('**/normal'),
                           self.buttonModel.find('**/disabled'))

        self.dialog_model = loader.loadModel(
            'models/gui/panels/infodialogpanel_maps.egg')
        self.dialog_map = self.dialog_model.find('**/infodialogpanel')

        self.HeadGUIPanel = DirectFrame(frameColor=(0.2, 0.2, 0.22, 0.9),
                                        frameSize=(0, 1.55, -0.13, 0),
                                        pos=(-1.8, 0, 1))

        self.HeadGUIText = DirectLabel(
            text=('Year ' + str(self.yearCounter) + ', '
                  'Day ' + str(self.dayCounter) + ', '
                  'Money: ' + str(self.money) + ', '
                  'Population: ' + str(self.system_population)),
            pos=(0.1, 0, -0.085),
            text_fg=(1, 1, 1, 1),
            frameColor=(0, 0, 0, 0),
            parent=self.HeadGUIPanel,
            text_align=TextNode.ALeft,
            text_scale=.07)

        self.MapViewPanel = DirectFrame(frameColor=(0.2, 0.2, 0.22, 0.9),
                                        frameSize=(0, 0.5, -1.25, 0),
                                        pos=(-1.75, 0, 0.6))

        self.trading_button = DirectButton(text='Trading',
                                           pos=(0.25, 0, -0.12),
                                           scale=0.5,
                                           pad=(-0.1, -0.09),
                                           frameColor=(0, 0, 0, 0),
                                           parent=self.MapViewPanel,
                                           geom=(self.buttonMaps),
                                           geom_scale=(0.7, 0, 1),
                                           text_scale=0.15,
                                           text_pos=(0, -0.03),
                                           text_fg=(0.5, 0.5, 0.5, 1),
                                           state=DGG.DISABLED)

        self.research_button = DirectButton(text='Research',
                                            pos=(0.25, 0, -0.32),
                                            scale=0.5,
                                            pad=(-0.1, -0.09),
                                            frameColor=(0, 0, 0, 0),
                                            parent=self.MapViewPanel,
                                            geom=(self.buttonMaps),
                                            geom_scale=(0.7, 0, 1),
                                            text_scale=0.15,
                                            text_pos=(0, -0.03),
                                            text_fg=(0.5, 0.5, 0.5, 1),
                                            state=DGG.DISABLED)

        self.diplomacy_button = DirectButton(text='Diplomacy',
                                             pos=(0.25, 0, -0.52),
                                             scale=0.5,
                                             pad=(-0.1, -0.09),
                                             frameColor=(0, 0, 0, 0),
                                             parent=self.MapViewPanel,
                                             geom=(self.buttonMaps),
                                             geom_scale=(0.7, 0, 1),
                                             text_scale=0.14,
                                             text_pos=(0, -0.03),
                                             text_fg=(0.5, 0.5, 0.5, 1),
                                             state=DGG.DISABLED)

        self.military_button = DirectButton(text='Military',
                                            pos=(0.25, 0, -0.72),
                                            scale=0.5,
                                            pad=(-0.1, -0.09),
                                            frameColor=(0, 0, 0, 0),
                                            parent=self.MapViewPanel,
                                            geom=(self.buttonMaps),
                                            geom_scale=(0.7, 0, 1),
                                            text_scale=0.15,
                                            text_pos=(0, -0.03),
                                            text_fg=(0.5, 0.5, 0.5, 1),
                                            state=DGG.DISABLED)

        self.galacy_map_button = DirectButton(text='Galaxy Map',
                                              pos=(0.25, 0, -0.92),
                                              scale=0.5,
                                              pad=(-0.1, -0.09),
                                              frameColor=(0, 0, 0, 0),
                                              parent=self.MapViewPanel,
                                              geom=(self.buttonMaps),
                                              geom_scale=(0.7, 0, 1),
                                              text_scale=0.14,
                                              text_pos=(0, -0.03),
                                              text_fg=(0.5, 0.5, 0.5, 1),
                                              state=DGG.DISABLED)

        self.statistics_button = DirectButton(text='Statistics',
                                              pos=(0.25, 0, -1.12),
                                              scale=0.5,
                                              pad=(-0.1, -0.09),
                                              frameColor=(0, 0, 0, 0),
                                              parent=self.MapViewPanel,
                                              geom=(self.buttonMaps),
                                              geom_scale=(0.7, 0, 1),
                                              text_scale=0.14,
                                              text_pos=(0, -0.03),
                                              text_fg=(0.5, 0.5, 0.5, 1),
                                              state=DGG.DISABLED)

    # ****************************************
    #        Debug / Testing Functions       *
    # ****************************************

    def reset_game(self):
        self.NewPlanetInfoView.hide()
        self.NewPlanetBuildView.hide()
        self.PlanetInfoModeOn = False

        taskMgr.remove('quickinfoTask')
        taskMgr.remove('buildcamTask')
        taskMgr.remove('infocamTask')

        self.yearCounter = 0
        self.dayCounter = 0
        self.money = 2000
        self.system_population = 0

        for planet in self.galaxy_objects:
            planet.reset()

        self.set_capital_planet()
예제 #31
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 ) )
예제 #32
0
class Mouse(object):
    def __init__(self, base, oid_texture):
        self.base = base
        self.picking_texture = oid_texture
        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)
        if settings.mouse_over:
            taskMgr.add(self.mouse_task, 'mouse-task')
        self.over = None

    def find_over_ray(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 find_over_color(self):
        over = None
        if self.base.mouseWatcherNode.hasMouse():
            mpos = self.base.mouseWatcherNode.getMouse()
            self.base.graphicsEngine.extract_texture_data(
                self.picking_texture, self.base.win.gsg)
            texture_peeker = self.picking_texture.peek()
            if texture_peeker is not None:
                x = (mpos.get_x() + 1) / 2
                y = (mpos.get_y() + 1) / 2
                value = LColor()
                texture_peeker.lookup(value, x, y)
                oid = color_to_int(value)
                if oid != 0:
                    over = objectsDB.get_oid(oid)
                    if over is None:
                        print("Unknown oid", oid, value)
        return over

    def find_over(self):
        if settings.color_picking:
            over_color = self.find_over_color()
        else:
            over_color = None
        over_ray = self.find_over_ray()
        over = over_color
        if over_ray is not None:
            if over is None or over.distance_to_obs > over_ray.distance_to_obs:
                over = over_ray
        if hasattr(over, "primary") and over.primary is not None:
            over = over.primary
        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.base.mouseWatcherNode.hasMouse():
            self.over = self.find_over()
        return Task.cont
예제 #33
0
class Hero(DirectObject, MovableObject):
    def __init__(self, pos=(0, 0, 0), scale=1, parent=None):
        DirectObject.__init__(self)
        MovableObject.__init__(self)

        # 英雄属性
        self._maxHP = defaultHeroHP
        self._HP = defaultHeroHP
        self._attackPower = defaultHeroAttackPower
        self._attackSpeed = defaultHeroAttackSpeed
        self.isMoving = False
        self._moveSpeed = defaultHeroMoveSpeed
        self.mousePos = (0, 0, 0)
        self.leapAttackTime = -1
        #英雄被击闪烁
        self.invincible = False  #是否无敌
        self.changeTime = -1  #下次变换形态时间
        self.recoveryTime = -1  #恢复正常的时间
        self.isHide = False

        ########## set model size hero
        self.bullet = SphereBullet(
        )  #(intoMask = CollideMask.bit(DefaultMonsterMaskVal))
        if not self.bullet.model.isEmpty():
            self.bullet.model.removeNode()
        self.attackMode = "Common"

        self.lastAttackTime = 0  # to enable shoutting at the beginning
        self.position = pos

        self.initAttackMethod = self.attack

        #'model_dierguanBOSS',{ #
        # 英雄模型和相应动画
        self.model = Actor(
            HeroModelPath + "model_mainChara",
            {
                "Walk": HeroModelPath + "anim_mainChara_running_attack",
                #"Attack": HeroModelPath + "anim_mainChara_standing",
                "Hit": HeroModelPath + "anim_mainChara_standing",
                "Die": HeroModelPath + "anim_mainChara_standing"
            })
        if parent == None:
            self.model.reparentTo(base.render)
        else:
            self.model.reparentTo(parent)
        self.model.setPos(self.position)
        self.lastPos = self.position
        self.scale = scale
        self.model.setScale(scale)
        self.model.hide()
        # 设置碰撞检测
        self.colliderName = "hero"
        characterSphere = CollisionSphere(0, 0, 2, 1)
        characterColNode = CollisionNode(self.colliderName)
        characterColNode.addSolid(characterSphere)
        characterColNode.setFromCollideMask(
            CollideMask.bit(DefaultHeroMaskVal)
            ^ CollideMask.bit(defaultHeroInMonsterMaskVal))

        # print characterColNode.getFromCollideMask()
        self.colliderNodePath = self.model.attachNewNode(characterColNode)
        #self.colliderNodePath.show()
        #将对象添加到nodepath中  用于在碰撞事件处理中获取对象
        self.colliderNodePath.setPythonTag("Hero", self)
        base.cTrav.addCollider(self.colliderNodePath, base.cHandler)
        #用于处理英雄与墙壁的碰撞
        characterSphere2 = CollisionSphere(0, 0, 2, 1)
        characterColNode2 = CollisionNode(self.colliderName)
        characterColNode2.addSolid(characterSphere2)
        self.colliderNodePath2 = self.model.attachNewNode(characterColNode2)
        self.modelGroundHandler = CollisionHandlerQueue()
        base.cTrav.addCollider(self.colliderNodePath2, self.modelGroundHandler)
        # #用于支持英雄与怪物的物理碰撞
        characterSphere3 = CollisionSphere(0, 0, 2, 1)
        characterColNode3 = CollisionNode(self.colliderName)
        characterColNode3.addSolid(characterSphere3)

        self.colliderNodePath3 = self.model.attachNewNode(characterColNode3)
        base.cPusher.addCollider(self.colliderNodePath3, self.model)
        #用于支持鼠标控制英雄的朝向----------------
        self.angle = 0
        self.pickerName = 'mouseRay'
        self.pickerNode = CollisionNode(self.pickerName)
        self.pickerNP = camera.attachNewNode(self.pickerNode)
        self.pickerNode.setFromCollideMask(CollideMask.bit(5))
        self.pickerNode.setIntoCollideMask(CollideMask.allOff())

        self.pickerRay = CollisionRay()
        self.pickerNode.addSolid(self.pickerRay)
        #self.pickerNP.show()
        base.cTrav.addCollider(self.pickerNP, base.cHandler)

        self.pickedName = 'mousePlane'
        self.pickedNode = CollisionNode(self.pickedName)
        self.pickedNP = render.attachNewNode(self.pickedNode)
        self.pickedNode.setFromCollideMask(CollideMask.allOff())
        self.pickedNode.setIntoCollideMask(CollideMask.bit(5))

        self.pickedPlane = CollisionPlane(
            LPlane(LVector3f(0, 0, 1), LPoint3f(0, 0, 2)))
        self.pickedNode.addSolid(self.pickedPlane)
        #self.pickedNP.show()

        #------------------------------------

        #加载英雄的各种音效
        self.sounds["GetItem"] = loader.loadSfx(HeroSoundPath + "getItem.wav")
        self.sounds["Die"] = loader.loadSfx(HeroSoundPath + "robot_death.wav")
        self.sounds["Attack"] = loader.loadSfx(HeroSoundPath +
                                               "bullet_shooting.wav")

        #键位字典
        self.keyMap = {
            "left": 0,
            "right": 0,
            "forward": 0,
            "back": 0,
            "fire": 0
        }

        self._initAccept()

    def _initAccept(self):
        againEvent = '{}-again-{}'
        self.accept(againEvent.format(self.pickerName, self.pickedName),
                    self._accept_ray_into_plane)

    def _accept_ray_into_plane(self, entry):
        pos = entry.getSurfacePoint(render)
        self.mousePos = LPoint3(pos[0], pos[1], pos[2])
        x, y = pos.get_x() - self.model.getPos().get_x(), pos.get_y(
        ) - self.model.getPos().get_y()
        angle = math.atan2(y, x)
        angle = angle * 180 / math.pi + 90
        self.angle = angle

    # maxHP
    @property
    def maxHP(self):
        return self._maxHP

    @maxHP.setter
    def maxHP(self, value):
        if value > defaultHeroMaxHPMax:
            value = defaultHeroMaxHPMax
        self._maxHP = value

    # HP
    @property
    def HP(self):
        return self._HP

    @HP.setter
    def HP(self, value):
        if value > self._maxHP:
            value = self._maxHP
        self._HP = value

    # attackPower
    @property
    def attackPower(self):
        return self._attackPower

    @attackPower.setter
    def attackPower(self, value):
        if value > defaultHeroAttackPowerMax:
            value = defaultHeroAttackPowerMax
        self._attackPower = value

    # attackSpeed
    @property
    def attackSpeed(self):
        return self._attackSpeed

    @attackSpeed.setter
    def attackSpeed(self, value):
        if value > defaultHeroAttackSpeedMax:
            value = defaultHeroAttackSpeedMax
        self._attackSpeed = value

    # moveSpeed
    @property
    def moveSpeed(self):
        return self._moveSpeed

    @moveSpeed.setter
    def moveSpeed(self, value):
        if value > defaultHeroMoveSpeedMax:
            value = defaultHeroMoveSpeedMax
        self._moveSpeed = value

    def setPos(self, pos):
        self.position = pos
        self.model.setPos(pos)

    def setScale(self, scale):
        self.scale = scale
        self.model.setScale(scale)

    def setEnemy(self, enemy):
        if isinstance(enemy, Monster):
            #inEvent = "{}-into-{}".format(enemy.colliderName,self.colliderName )
            inEvent = "{}-into-{}".format(self.colliderName,
                                          enemy.colliderName)
            self.accept(inEvent, self.underAttack)
        if isinstance(enemy, Bullet):
            inEvent = "{}-into-{}".format(self.colliderName,
                                          enemy.colliderName)
            base.cHandler.addInPattern(inEvent)
            enemy.accept(inEvent, enemy.action)

    def move(self):
        dt = base.globalClock.getDt()

        x = self.model.getX()
        y = self.model.getY()
        dis = self._moveSpeed * dt
        #控制移动
        if self.keyMap['forward']:
            y += dis
        if self.keyMap['back']:
            y -= dis
        if self.keyMap['left']:
            x -= dis
        if self.keyMap['right']:
            x += dis
        if x == self.model.getX() and y == self.model.getY():
            if self.isMoving:
                self.model.stop()
                self.model.pose("walk", 0)
                self.isMoving = False
        elif not self.isMoving:
            self.model.loop('Walk')
            self.isMoving = True

        self.model.setX(x)
        self.model.setY(y)

        # 控制面朝向
        self.updateDirection()

        #是否与房间(墙壁)碰撞
        base.cTrav.traverse(base.render)
        entries = list(self.modelGroundHandler.getEntries())
        entries.sort(key=lambda x: x.getSurfacePoint(base.render).getZ())

        backup = False
        for entry in entries:
            if entry.getIntoNode().getName() == "room":
                backup = True
                break

        if backup:
            self.model.setPos(self.lastPos)
        else:
            self.lastPos = self.model.getPos()

        #base.camera.setPos(self.model.getX(), self.model.getY()+20, 20)
        #base.camera.lookAt(self.model)

    def updateDirection(self):
        self.model.setH(self.angle)

    def updateRay(self):
        '''
        在主循环中更新 人物朝向控制射线的方向
        '''
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())

    def attack(self, taskTime):
        '''
        taskTime 无效参数,可以重新赋值
        '''
        angle = self.angle
        # 是否过了攻击冷却期
        currTime = time.time()
        split = currTime - self.lastAttackTime
        if standarHitRate * 1.0 / self.attackSpeed > split:
            return

        # 更新上一次攻击的时间
        self.lastAttackTime = currTime

        # 播放攻击动画
        self.model.play("Attack")
        # 播放攻击音效
        self.sounds["Attack"].play()

        # 子弹位置
        pos = self.model.getPos()
        bullet = self.bullet.copy()  #SphereBullet()#copy.deepcopy(self.bullet)
        bullet.model.reparentTo(render)
        bullet.setPos(pos)
        bullet.setZ(2)  # bullet.getZ() +

        # 子弹生命周期(消亡的时间)
        bullet.setExpires(currTime + bullet.bulletLife)  #bullet.bulletLife
        # 子弹飞行方向

        bullet.setAngle(angle)

        # 子弹伤害值 ( 子弹本身伤害值 + 英雄攻击力 )
        bullet.damage += self.attackPower
        bullet.model.show()
        # 注册子弹
        base.messenger.send("bullet-create", [bullet])

    def leapAttack(self, pos, size, speed):
        if self.leapAttackTime > time.time():
            return
        self.leapAttackTime = time.time() + 2
        bullet = LeapBullet(pos, DefaultMonsterMaskVal, size, speed)
        base.messenger.send("bullet-create", [bullet])

    def update(self):
        self.updateInvincible()
        self.updateRay()
        self.move()
        self.updateDirection()

        if self.keyMap["fire"]:
            self.attack(time.time)
            self.keyMap["fire"] = False

    def updateInvincible(self):  #处理无敌状态
        if self.recoveryTime > time.time():
            self.invincible = True
            if self.changeTime < time.time():
                if self.isHide:
                    self.isHide = False
                    self.model.show()
                    self.changeTime = time.time() + 0.2
                else:
                    self.isHide = True
                    self.model.hide()
                    self.changeTime = time.time() + 0.2
        else:
            self.model.show()
            self.invincible = False

    def underAttack(self, val=defaultHeroHitByMonsterDamageVal):
        if self.invincible == True:
            return
        self.model.play("Hit")
        self.decreaseHP(val)
        self.recoveryTime = time.time() + 1.5

    def decreaseHP(self, val):

        self.HP -= val
        if self.HP < 0:
            self.HP = 0
        base.messenger.send("hero-HPChange", [self.HP])
        if self.HP == 0:
            if Debug:
                return
            self.die()

    def increaseHP(self, val):
        self.HP += val
        if self.HP > self.maxHP:
            self.HP = self.maxHP
        base.messenger.send("hero-HPChange", [self.HP])

    def increaseMaxHP(self, val):
        self.maxHP += val
        base.messenger.send("hero-maxHPChange", [self.maxHP])

    def die(self):
        self.doMethodLater(self.model.getDuration("Die"), self.destroy,
                           "hero-die")
        self.model.play("Die")
        self.sounds["Die"].play()
        # 防止继续移动 旋转
        self.ignoreAll()
        base.taskMgr.remove("hero-Loop")

    def destroy(self, task):
        base.messenger.send("hero-die")

    @staticmethod
    def ToDict(hero):
        dict = {}
        dict["maxHP"] = hero.maxHP
        dict["HP"] = hero.HP
        dict["attackPower"] = hero.attackPower
        dict["attackSpeed"] = hero.attackSpeed
        dict["moveSpeed"] = hero._moveSpeed
        dict["bullet"] = hero.bullet.ToDict(hero.bullet)
        dict["pos"] = [hero.position[0], hero.position[1], hero.position[2]]
        dict["scale"] = hero.scale
        dict["attackMode"] = hero.attackMode
        return dict

    @staticmethod
    def ToHero(dict):
        hero = Hero()
        hero.maxHP = dict["maxHP"]
        hero.HP = dict["HP"]
        hero.attackPower = dict["attackPower"]
        hero.attackSpeed = dict["attackSpeed"]
        hero.setPos(LVecBase3f(dict["pos"][0], dict['pos'][1], dict['pos'][2]))
        hero.setScale(dict["scale"])
        hero._moveSpeed = dict["moveSpeed"]
        hero.attackMode = dict["attackMode"]
        hero.bullet = BulletFactory.getBullet(dict["bullet"], hero)

        return hero

    def reInit(self, dict, renew=False):
        self.maxHP = dict["maxHP"]
        self.HP = dict["HP"]
        self.attackPower = dict["attackPower"]
        self.attackSpeed = dict["attackSpeed"]
        self._moveSpeed = dict["moveSpeed"]
        self.attackMode = dict["attackMode"]
        self.bullet = BulletFactory.getBullet(dict["bullet"], self)
        self.setPos(LVecBase3f(dict["pos"][0], dict['pos'][1], dict['pos'][2]))
        self.setScale(dict["scale"])
        if renew:
            self.attack = self.initAttackMethod
        self._initAccept()
예제 #34
0
class InputManager(DirectObject):
    def __init__(self, base, lookatpos, pggen, togglerotcenter=False):
        self.base = base
        self.originallookatpos = lookatpos  # for backup
        self.lookatpos_pdv3 = Vec3(lookatpos[0], lookatpos[1], lookatpos[2])
        self.camdist = (self.base.cam.getPos() - self.lookatpos_pdv3).length()
        self.pggen = pggen
        self.initviewdist = (self.base.cam.getPos() -
                             self.lookatpos_pdv3).length()
        self.wheelscale_distance = 150
        self.lastm1pos = None
        self.lastm2pos = None
        # toggle on the following part to explicitly show the rotation center
        self.togglerotcenter = togglerotcenter
        if self.togglerotcenter:
            self.rotatecenternp = self.base.p3dh.gensphere(
                pos=self.originallookatpos,
                radius=5,
                rgba=np.array([1, 1, 0, 1]))
            self.rotatecenternp.reparentTo(self.base.render)
        # for resetting
        self.original_cam_pdmat4 = Mat4(self.base.cam.getMat())
        self.keymap = {
            "mouse1": False,
            "mouse2": False,
            "mouse3": False,
            "wheel_up": False,
            "wheel_down": False,
            "space": False,
            "w": False,
            "s": False,
            "a": False,
            "d": False,
            "g": False,
            "r": False
        }
        self.accept("mouse1", self.__setkeys, ["mouse1", True])
        self.accept("mouse1-up", self.__setkeys, ["mouse1", False])
        self.accept("mouse2", self.__setkeys, ["mouse2", True])
        self.accept("mouse2-up", self.__setkeys, ["mouse2", False])
        self.accept("mouse3", self.__setkeys, ["mouse3", True])
        self.accept("mouse3-up", self.__setkeys, ["mouse3", False])
        self.accept("wheel_up", self.__setkeys, ["wheel_up", True])
        self.accept("wheel_down", self.__setkeys, ["wheel_down", True])
        self.accept("space", self.__setkeys, ["space", True])
        self.accept("space-up", self.__setkeys, ["space", False])
        self.accept("w", self.__setkeys, ["w", True])
        self.accept("w-up", self.__setkeys, ["w", False])
        self.accept("s", self.__setkeys, ["s", True])
        self.accept("s-up", self.__setkeys, ["s", False])
        self.accept("a", self.__setkeys, ["a", True])
        self.accept("a-up", self.__setkeys, ["a", False])
        self.accept("d", self.__setkeys, ["d", True])
        self.accept("d-up", self.__setkeys, ["d", False])
        self.accept("g", self.__setkeys, ["g", True])
        self.accept("g-up", self.__setkeys, ["g", False])
        self.accept("r", self.__setkeys, ["r", True])
        self.accept("r-up", self.__setkeys, ["r", False])
        self.setup_interactiongeometries()

    def __setkeys(self, key, value):
        self.keymap[key] = value
        return

    def setup_interactiongeometries(self):
        """
        set up collision rays, spheres, and planes for mouse manipulation

        :return: None

        author: weiwei
        date: 20161110
        """

        # create a trackball ray and set its bitmask to 8
        # the trackball ray must be a subnode of cam since we will
        # transform the clicked point (in the view of the cam) to the world coordinate system
        # using the ray
        self.tracker_cn = CollisionNode("tracker")
        self.tracker_ray = CollisionRay()
        self.tracker_cn.addSolid(self.tracker_ray)
        self.tracker_cn.setFromCollideMask(BitMask32.bit(8))
        self.tracker_cn.setIntoCollideMask(BitMask32.allOff())
        self.tracker_np = self.base.cam.attachNewNode(self.tracker_cn)

        # create an inverted collision sphere and puts it into a collision node
        # its bitmask is set to 8, and it will be the only collidable object at bit 8
        self.trackball_cn = CollisionNode("trackball")
        self.trackball_cn.addSolid(
            CollisionSphere(self.lookatpos_pdv3[0], self.lookatpos_pdv3[1],
                            self.lookatpos_pdv3[2], self.camdist))
        self.trackball_cn.setFromCollideMask(BitMask32.allOff())
        self.trackball_cn.setIntoCollideMask(BitMask32.bit(8))
        self.trackball_np = self.base.render.attachNewNode(self.trackball_cn)
        # self.trackball_np.show()

        # This creates a collision plane for mouse track
        self.trackplane_cn = CollisionNode("trackplane")
        # self.aimPlaneCN.addSolid(CollisionPlane(Plane(Vec3(0, 0, 1), self.lookatpos_pdv3)))
        # self.trackplane_cn.addSolid(CollisionBox(Point3(self.lookatpos_pdv3[0], self.lookatpos_pdv3[1], 0.1), 1e6, 1e6, 1e-6))
        self.trackplane_cn.addSolid(
            CollisionPlane(
                Plane(
                    Point3(self.base.cam.getMat().getRow3(2) -
                           self.base.cam.getMat().getRow3(1)),
                    Point3(self.lookatpos_pdv3[0], self.lookatpos_pdv3[1],
                           0.1))))
        self.trackplane_cn.setFromCollideMask(BitMask32.allOff())
        self.trackplane_cn.setIntoCollideMask(BitMask32.bit(8))
        self.trackplane_np = self.base.render.attachNewNode(self.trackplane_cn)
        # self.trackplane_np.show()

        # creates a traverser to do collision testing
        self.ctrav = CollisionTraverser()
        # creates a queue type handler to receive the collision event info
        self.chandler = CollisionHandlerQueue()

        # register the ray as a collider with the traverser,
        # and register the handler queue as the handler to be used for the collisions.
        self.ctrav.addCollider(self.tracker_np, self.chandler)

        # create a pickerray
        self.picker_cn = CollisionNode('picker')
        self.picker_ray = CollisionRay()
        self.picker_cn.addSolid(self.picker_ray)
        self.picker_cn.setFromCollideMask(BitMask32.bit(7))
        self.picker_cn.setIntoCollideMask(BitMask32.allOff())
        self.picker_np = self.base.cam.attachNewNode(self.picker_cn)
        self.ctrav.addCollider(self.picker_np, self.chandler)

    def shift_trackballsphere(self, center=np.array([0, 0, 0])):
        self.camdist = (self.base.cam.getPos() - self.lookatpos_pdv3).length()
        self.trackball_cn.setSolid(
            0, CollisionSphere(center[0], center[1], center[2], self.camdist))

    def shift_trackplane(self):
        self.trackplane_cn.setSolid(
            0,
            CollisionPlane(
                Plane(
                    Point3(self.base.cam.getMat().getRow3(2) -
                           self.base.cam.getMat().getRow3(1)),
                    Point3(self.lookatpos_pdv3[0], self.lookatpos_pdv3[1],
                           0.1))))

    def get_world_mouse1(self):
        """
       给et the position of mouse1 (clicked) using collision detection between a sphere and a ray

        :return: Vec3 or None

        author: weiwei
        date: 20161110
        """
        if self.base.mouseWatcherNode.hasMouse():
            if self.keymap['mouse1']:
                # get the mouse position in the window
                mpos = self.base.mouseWatcherNode.getMouse()
                # sets the ray's origin at the camera and directs it to shoot through the mouse cursor
                self.tracker_ray.setFromLens(self.base.cam.node(), mpos.getX(),
                                             mpos.getY())
                # performs the collision checking pass
                self.ctrav.traverse(self.trackball_np)
                if (self.chandler.getNumEntries() > 0):
                    # Sort the handler entries from nearest to farthest
                    self.chandler.sortEntries()
                    entry = self.chandler.getEntry(0)
                    colPoint = entry.getSurfacePoint(self.base.render)
                    return colPoint
        return None

    def check_mouse1drag(self):
        """
        this function uses a collision sphere to track the rotational mouse motion

        :return:

        author: weiwei
        date: 20200315
        """

        curm1pos = self.get_world_mouse1()
        if curm1pos is None:
            if self.lastm1pos is not None:
                self.lastm1pos = None
            return
        if self.lastm1pos is None:
            # first time click
            self.lastm1pos = curm1pos
            return
        curm1vec = Vec3(curm1pos - self.lookatpos_pdv3)
        lastm1vec = Vec3(self.lastm1pos - self.lookatpos_pdv3)
        curm1vec.normalize()
        lastm1vec.normalize()
        rotatevec = curm1vec.cross(lastm1vec)
        if rotatevec.length() > 1e-10:  # avoid zero length
            rotateangle = curm1vec.signedAngleDeg(lastm1vec, rotatevec)
            rotateangle = rotateangle * self.camdist * 5
            if rotateangle > .02 or rotateangle < -.02:
                rotmat = Mat4(self.base.cam.getMat())
                posvec = Vec3(self.base.cam.getPos())
                rotmat.setRow(3, Vec3(0, 0, 0))
                self.base.cam.setMat(rotmat *
                                     Mat4.rotateMat(rotateangle, rotatevec))
                self.base.cam.setPos(Mat3.rotateMat(rotateangle, rotatevec). \
                                     xform(posvec - self.lookatpos_pdv3) + self.lookatpos_pdv3)
                self.lastm1pos = self.get_world_mouse1()
                self.shift_trackplane()

    def get_world_mouse2(self):
        if self.base.mouseWatcherNode.hasMouse():
            if self.keymap['mouse2']:
                mpos = self.base.mouseWatcherNode.getMouse()
                self.tracker_ray.setFromLens(self.base.cam.node(), mpos.getX(),
                                             mpos.getY())
                self.ctrav.traverse(self.trackplane_np)
                self.chandler.sortEntries()
                if (self.chandler.getNumEntries() > 0):
                    entry = self.chandler.getEntry(0)
                    colPoint = entry.getSurfacePoint(self.base.render)
                    return colPoint
        return None

    def check_mouse2drag(self):
        """

        :return:

        author: weiwei
        date: 20200313
        """

        curm2pos = self.get_world_mouse2()
        if curm2pos is None:
            if self.lastm2pos is not None:
                self.lastm2pos = None
            return
        if self.lastm2pos is None:
            # first time click
            self.lastm2pos = curm2pos
            return
        relm2vec = curm2pos - self.lastm2pos
        if relm2vec.length() > 1:
            self.base.cam.setPos(self.base.cam.getPos() - relm2vec)
            self.lookatpos_pdv3 = Vec3(self.lookatpos_pdv3 - relm2vec)
            newlookatpos = self.base.p3dh.pdv3_to_npv3(self.lookatpos_pdv3)
            if self.togglerotcenter:
                self.rotatecenternp.detachNode()
                self.rotatecenternp = self.base.p3dh.gensphere(
                    pos=newlookatpos, radius=5, rgba=np.array([1, 1, 0, 1]))
                self.rotatecenternp.reparentTo(self.base.render)
            self.shift_trackballsphere(self.lookatpos_pdv3)
            self.last2mpos = curm2pos

    def get_world_mouse3(self):
        """
        picker ray

        :return:

        author: weiwei
        date: 20200316
        """

        if self.base.mouseWatcherNode.hasMouse():
            if self.keymap['mouse3']:
                mpos = self.base.mouseWatcherNode.getMouse()
                self.picker_ray.setFromLens(self.base.cam.node(), mpos.getX(),
                                            mpos.getY())
                self.ctrav.traverse(self.base.render)
                if (self.chandler.getNumEntries() > 0):
                    self.chandler.sortEntries()
                    entry = self.chandler.getEntry(0)
                    colPoint = entry.getSurfacePoint(self.base.render)
                    return colPoint
        return None

    def check_mouse3click(self):
        """

        :return:

        author: weiwei
        date: 20200316
        """

        curm3pos = self.get_world_mouse3()
        if curm3pos is None:
            return
        else:
            print(curm3pos)

    def check_mousewheel(self):
        """
        zoom up or down the 3d view considering mouse action

        author: weiwei
        date: 2016, 20200313
        :return:
        """

        if self.keymap["wheel_up"] is True:
            self.keymap["wheel_up"] = False
            backward = self.base.cam.getPos() - self.lookatpos_pdv3
            backward.normalize()
            newpos = self.base.cam.getPos(
            ) + backward * self.wheelscale_distance
            if newpos.length() < self.initviewdist * 20:
                self.base.cam.setPos(newpos[0], newpos[1], newpos[2])
                self.shift_trackballsphere(
                    self.trackball_cn.getSolid(0).getCenter())
        if self.keymap["wheel_down"] is True:
            self.keymap["wheel_down"] = False
            forward = self.lookatpos_pdv3 - self.base.cam.getPos()
            if forward.length() < self.wheelscale_distance:
                return
            forward.normalize()
            newpos = self.base.cam.getPos(
            ) + forward * self.wheelscale_distance
            if newpos.length() > self.initviewdist * .05:
                self.base.cam.setPos(newpos[0], newpos[1], newpos[2])
                self.shift_trackballsphere(
                    self.trackball_cn.getSolid(0).getCenter())

    def check_mouse1drag_trackball(self):
        """
        This function uses the stereographic projection
        introduced in https://en.wikipedia.org/wiki/Stereographic_projection to track the rotational mouse motion
        Equations:
        [e, f] -> [x, y, z] = [2e/(1+e^2+f^2), 2f/(1+e^2+f^2), (-1+e^2+f^2)/(2+2e^2+2f^2)]

        :return:

        author: weiwei
        date: 20200315
        """
        def cvtvirtualtrackball(screenx, screeny, psec_squared=1 / 4):
            """
            convert a screen point to virtual trackball coordinate
            psec indicates the size of the spherical section to be mapped to
            default radius = 1

            :param screenx:
            :param screeny:
            :param psec_squared:
            :return:

            author: weiwei
            date: 20200315
            """

            screenpoint_squaredsum = screenx**2 + screeny**2
            trackballx = 2 * psec_squared * screenx / (psec_squared +
                                                       screenpoint_squaredsum)
            trackballz = 2 * psec_squared * screeny / (psec_squared +
                                                       screenpoint_squaredsum)
            trackbally = -math.sqrt(1 - trackballx**2 - trackballz**2)
            returnvec = Vec3(trackballx, trackbally, trackballz)
            returnvec.normalize()
            return returnvec

        currentmouse = self.base.mouseWatcherNode.getMouse()
        curm1pos = [currentmouse.getX(), currentmouse.getY()]
        if curm1pos is None:
            if self.lastm1pos is not None:
                self.lastm1pos = None
            return
        if self.lastm1pos is None:
            # first time click
            self.lastm1pos = curm1pos
            return
        curm1vec_pdv3 = cvtvirtualtrackball(curm1pos[0], curm1pos[1])
        lastm1vec_pdv3 = cvtvirtualtrackball(self.lastm1pos[0],
                                             self.lastm1pos[1])
        rotatevec_pdv3 = curm1vec_pdv3.cross(lastm1vec_pdv3)
        rotateangle = curm1vec_pdv3.signedAngleDeg(lastm1vec_pdv3,
                                                   rotatevec_pdv3)
        if rotateangle > .02 or rotateangle < -.02:
            rotateangle = rotateangle * 5
            camrotmat_pd = self.base.cam.getMat().getUpper3()
            calibrated_camrotmat_pd = Mat3.rotateMat(
                rotateangle, camrotmat_pd.xformVec(rotatevec_pdv3))
            posvec_pd = self.base.cam.getPos()
            self.base.cam.setMat(Mat4.identMat())
            self.base.cam.setMat(camrotmat_pd * calibrated_camrotmat_pd)
            self.base.cam.setPos(
                calibrated_camrotmat_pd.xform(posvec_pd -
                                              self.lookatpos_pdv3) +
                self.lookatpos_pdv3)
            self.lastm1pos = curm1pos[:]

    def check_resetcamera(self):
        """
        reset the rendering window to its initial viewpoint

        :return:

        author: weiwei
        date: 20200316
        """

        if self.keymap["r"] is True:
            self.keymap["r"] = False
            self.base.cam.setMat(self.original_cam_pdmat4)
            self.lookatpos_pdv3 = self.base.p3dh.npv3_to_pdv3(
                self.originallookatpos)
            # toggle on the following part to explicitly show the rotation center
            if self.togglerotcenter:
                self.rotatecenternp.detachNode()
                self.rotatecenternp = self.base.p3dh.gensphere(
                    pos=self.originallookatpos,
                    radius=5,
                    rgba=np.array([1, 1, 0, 1]))
                self.rotatecenternp.reparentTo(self.base.render)
예제 #35
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
예제 #36
0
class World(DirectObject):
	def __init__(self, mode, ip=None):
		
		if mode==CLIENT and not ip:
			#Don't let this happen.
			print "WTF programmer"
			sys.exit()
		
		#current dialog box
		self.d = None
		
		#top-left of screen; contains instructions on how to exit the game.
		self.quitInstructions = OnscreenText(text='Press ESC to exit.', pos=(-1, 0.95), scale=0.05, fg=(1,1,1,1), bg=(0,0,0,0), mayChange=False)
		
		#bottom of screen
		self.turnIndicator = OnscreenText(text='', pos=(0,-0.8), scale=0.1, fg=(1,1,1,1), bg=(0,0,0,0), mayChange=True)
		
		#Saving some values, some default values
		self.mode = mode
		self.player = {SERVER: PIECEWHITE, CLIENT: PIECEBLACK}[self.mode]
		self.ip = ip
		
		#Panda3D, by default, allows for camera control with the mouse.
		base.disableMouse()
		
		self.setupMouse()
		self.setupBoard()
		self.setupCamera()
		self.setupPieces()
		self.setupNetwork()
		self.setupLights()
		
		#some internal state for making clicky moves
		self.hiSq = None
		self.dragOrigin = None
		
		#keyboard, mouse
		self.mouseTask = taskMgr.add(self.tskMouse, 'mouseTask')
		self.accept('mouse1', self.handleClick)
		self.accept('f2', lambda: base.setFrameRateMeter(True))
		self.accept('f3', lambda: base.setFrameRateMeter(False))
		self.accept('escape', sys.exit)
		
		
		#first turn
		self.turn = PIECEWHITE
	
	#### INITIALIZATION ####
	
	def setupBoard(self):
		#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 = dict(((i,j), None) for i in range(8) for j in range(8))
		for place in self.squares:
			#Load, parent, color, and position the model (a single square polygon)
			self.squares[place] = loader.loadModel("models/square")
			self.squares[place].reparentTo(self.squareRoot)
			self.squares[place].setPos(SquarePos(place))
			self.squares[place].setColor(SquareColor(place))
			#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[place].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[place].find("**/polygon").node().setTag('square', ' '.join(map(str,place)))
			self.squares[place].setTransparency(TransparencyAttrib.MAlpha)

	def setupPieces(self):
		#Default dictionaries work decently well as an easy two-dimensional array.
		self.pieces = defaultdict(lambda: None)
		
		#The order of pieces on a chessboard from white's perspective
		pieceOrder = [Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook]
		
		for i in xrange(8):
			#load white pawns
			self.pieces[i, 1] = Pawn((i,1), PIECEWHITE)
			
			#load black pawns
			self.pieces[i, 6] = Pawn((i, 6), PIECEBLACK)
			
			#load white specials
			self.pieces[i, 0] = pieceOrder[i]((i,0), PIECEWHITE)
			
			#load black specials
			self.pieces[i, 7] = pieceOrder[i]((i,7), PIECEBLACK)
		for p in self.pieces.values():
			p.obj.setTransparency(TransparencyAttrib.MAlpha)
	
	# TODO: Notice when the other side disconnects
	def setupNetwork(self):
		if self.mode == CLIENT:
			self.setupClient(self.ip)
		else:
			self.setupServer()
	
	# A lot of the below two methods is boilerplate straight from Panda3D documentation.
	def setupServer(self):
		self.cManager = QueuedConnectionManager()
		self.cListener = QueuedConnectionListener(self.cManager, 0)
		self.cReader = QueuedConnectionReader(self.cManager, 0)
		self.cWriter = ConnectionWriter(self.cManager,0)
		
		self.oppConnection = None
		port = 15905 # Chosen by fair dice roll.
		             # Guaranteed to be random.
		backlog = 1000
		tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog)
		
		self.cListener.addConnection(tcpSocket)
		
		def tskListenerPoll(task):
			if self.cListener.newConnectionAvailable() and not self.oppConnection:
				rendezvous = PointerToConnection()
				addr = NetAddress()
				newCon = PointerToConnection()
				
				if self.cListener.getNewConnection(rendezvous, addr, newCon):
					newConnection = newCon.p()
					print "Received connection from %s" % newConnection.getAddress()
					self.oppConnection = newConnection
					self.cReader.addConnection(newConnection)
					
					#server starts the game
					self.turnIndicator['text'] = 'Your turn!'
					self.showVisibleSquares()
					
					#remove the dialog node from below
					if self.d: self.d.removeNode()
					
					return Task.done
			if not self.d: self.d = DirectDialog(text="Waiting for client to connect...", buttonTextList=[], buttonValueList=[])
			return Task.cont
			
		taskMgr.add(tskListenerPoll, "Poll the connection listener")
		taskMgr.add(self.tskReaderPoll, "Poll the connection reader")
	
	def setupClient(self, ip):
		self.cManager = QueuedConnectionManager()
		self.cReader = QueuedConnectionReader(self.cManager, 0)
		self.cWriter = ConnectionWriter(self.cManager,0)
		
		self.oppConnection = None
		
		port = 15905
		timeout = 3000
		myConnection = self.cManager.openTCPClientConnection(ip, port, timeout)
		if myConnection:
			self.cReader.addConnection(myConnection)
			self.oppConnection = myConnection
			
			taskMgr.add(self.tskReaderPoll, "Poll the connection reader")
			self.showVisibleSquares()
		else:
			self.d = OkDialog(text="Could not connect to server at '%s'" % ip, command=sys.exit)
	
	# Makes sure player gets a decent view of the game board, and *not* of the hidden pieces below the board. Shhhh...
	def setupCamera(self):
		if self.player == PIECEWHITE:
			camera.setPos(0, -13.75, 8)
			camera.lookAt(self.squareRoot)
			camera.setH(0)
		else:
			camera.setPos(0, 13.75, 8)
			camera.lookAt(self.squareRoot)
			camera.setH(180)
	
	# Adds some ambient lights and a directional light
	def setupLights(self):
		#This is one area I know hardly anything about. I really don't know how to get this to behave nicely.
		#The black pieces are hardly distinguishable.
		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 ) )
	
	# Sets up collision detection for the mouse cursor.
	def setupMouse(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 = 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)
	
	#### TASKS ####
	
	# Checks for incoming data on the connection
	def tskReaderPoll(self, task):
		if self.cReader.dataAvailable():
			datagram = NetDatagram()
			if self.cReader.getData(datagram):
				self.receiveData(datagram)
		return Task.cont
	
	# Runs every frame, checks whether the mouse is highlighting something or another
	def tskMouse(self, task):
		#This task deals with the highlighting and dragging based on the mouse
		
		#First, clear the current highlight
		if self.hiSq:
			self.squares[self.hiSq].setColor(SquareColor(self.hiSq))
			self.hiSq = None
			
		#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.dragOrigin:
				#camera, relative instead to render
				#Gets the point described by pickerRay.getOrigin(), which is relative to
				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.dragOrigin].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()
				p = tuple(map(int, (self.pq.getEntry(0).getIntoNode().getTag('square')).split()))
				
				if self.pieces[p] and self.pieces[p].color == self.turn == self.player and not self.dragOrigin or self.dragOrigin and self.pieces[self.dragOrigin].isValidMove(p, self.pieces):
					#Set the highlight on the picked square
					self.hiSq = p
					self.squares[self.hiSq].setColor(HIGHLIGHT)
			    
		return Task.cont		
	
	def handleClick(self):
		# Disabled when a dialog box is on-screen. Pay attention to what I'm telling you, user!
		if not self.d:
			if self.dragOrigin:
				self.releasePiece()
			else:
				self.grabPiece()
	
	# Comes from handleClick
	def grabPiece(self):
		#If a square is highlighted and it has a piece, set it to dragging mode
		if self.hiSq and self.pieces[self.hiSq] and self.pieces[self.hiSq].color == self.turn:
			self.dragOrigin = self.hiSq
			self.hiSq = None
	
	def releasePiece(self):
		#Letting go of a piece. If we are not on a square, return it to its original
		#position.
		if self.dragOrigin:   #Make sure we really are dragging something
			if self.hiSq and self.hiSq != self.dragOrigin and self.pieces[self.dragOrigin].isValidMove(self.hiSq, self.pieces):
				
				# Verify that this doesn't put the king in check
				# Make backup of the pieces dictionary
				oldPieces = self.pieces.copy()
				
				self.pieces[self.hiSq] = self.pieces[self.dragOrigin]
				self.pieces[self.dragOrigin] = None
				
				if self.inCheck(self.turn):
					self.pieces = oldPieces
					self.pieces[self.dragOrigin].obj.setPos(SquarePos(self.dragOrigin))
					print "Invalid move -- King is in check"
					
					def closeDialog():
						self.d.removeNode()
					self.d = OkDialog(text="That move would put your King in check!", command=closeDialog)
				else:
					self.pieces = oldPieces
					
					self.makeMove(self.dragOrigin, self.hiSq, dt=0, callback=self.showVisibleSquares).start()
					self.sendMove(self.dragOrigin, self.hiSq)
					self.squares[self.dragOrigin].setColor(SquareColor(self.dragOrigin))
					
					#no longer our turn
					self.turnIndicator['text'] = ''
			else:
				self.pieces[self.dragOrigin].obj.setPos(SquarePos(self.dragOrigin))
				print "Invalid move"
			  
		#We are no longer dragging anything
		self.dragOrigin = False
	
	#### CHESS UPDATES ####
	
	# Moves a piece from one space to another.
	# This should be called to update internal state, whether the piece is already in the correct location or not.
	# Also handles captures.
	def makeMove(self, fr, to, dt=1, callback=None):
		print "Making move %s -> %s" % (str(fr), str(to))
		frP = self.pieces[fr]
		toP = self.pieces[to]
		
		if not frP:
			return False
		if toP and frP.color == toP.color:
			return False
		if not frP.isValidMove(to, self.pieces):
			return False
		
		# Callback function for the movement.
		# Updates pieces' internal state, as well as the true state of the board (self.pieces)
		def updateState():
			self.destroy(toP)
			frP.square = to
			frP.haveMoved = True
			self.pieces[fr] = None
			self.pieces[to] = frP
			self.turn = flip[self.turn]
			
			if self.inCheck(self.player):
				def dismiss(val):
					self.d.removeNode()
				self.d = OkDialog(text="You are in check!", command=dismiss)

		s = Sequence(
			frP.obj.posInterval(dt, self.squares[to].getPos()),
			Func(updateState)
		)
		if callback: s.append(Func(callback))
		return s
	
	# Removes the piece. This method is passed a Piece object, not a location!
	# Possible improvements: Particle effects! :D
	def destroy(self, piece):
		if piece:
			piece.obj.removeNode()
		
	# Determines whether the player specified by "color" is in check at the current time
	# Future improvements: Calculate the same thing for possible future moves (i.e. if I move here am I therefore in check?)
	def inCheck(self, color):
		#find the king
		kingPlace = [p for p in self.pieces if self.pieces[p] and self.pieces[p].color == color and self.pieces[p].model == "models/king"][0]
		for p in self.pieces:
			if self.pieces[p] and self.pieces[p].color != color and self.pieces[p].isValidMove(kingPlace, self.pieces):
				return True
		return False

	# Currently unused, but could be useful in an (extremely primitive) AI in the future.
	# I ran out of time to put it in this version.
	def makeRandomMove(self):
		move = None
		while not move:
			chosenPiece = random.choice([(x,y) for (x,y) in self.pieces if 0 <= x < 8 and 0 <= y < 8 and self.pieces[x,y] and self.pieces[x,y].color == self.turn])
			if not self.pieces[chosenPiece].validMoves(self.pieces):
				continue
			destSquare = random.choice([s for s in self.pieces[chosenPiece].validMoves(self.pieces)])
			move = (chosenPiece, destSquare)
		self.makeMove(*move).start()
	
	#### VISIBILITY UPDATES ####
	
	def isVisible(self, sq):
		return self.squares[sq].getColorScale()[3] == 1.0
		
	# The next two methods deal with hiding and showing the squares of the board.
	def hideSquare(self, sq, dt="default", callback=None):
			
		if self.squares[sq] and self.isVisible(sq):
			if dt == "default": dt = 1.0
			
			par = Parallel(
				LerpFunctionInterval(self.squares[sq].setAlphaScale, toData=0.0, fromData=1.0, duration=dt),
			)
			if self.pieces[sq]:
				par.append(LerpFunctionInterval(self.pieces[sq].obj.setAlphaScale, toData=0.0, fromData=1.0, duration=dt))
			s = Sequence(par)
			if callback: s.append(Func(callback))
			return s
		else:
			s = Sequence()
			if callback: s.append(Func(callback))
			return s
	
	def showSquare(self, sq, dt="default", callback=None):
			
		if self.squares[sq] and not self.isVisible(sq):
			if dt == "default": dt = 1.0
			
			par = Parallel(
				LerpFunctionInterval(self.squares[sq].setAlphaScale, toData=1.0, fromData=0.0, duration=dt),
			)
			if self.pieces[sq]:
				par.append(LerpFunctionInterval(self.pieces[sq].obj.setAlphaScale, toData=1.0, fromData=0.0, duration=dt))
			s = Sequence(par)
			if callback: s.append(Func(callback))
			return s
		else:
			s = Sequence()
			if callback: s.append(Func(callback))
			return s

	# Shows the path that a piece takes on its way IF any part of it is visible to the current player
	def showPathIfVisible(self, fr, to):
		if self.pieces[fr]:
			path = set()
			showSquareSequences = Parallel()
			if self.pieces[fr]:
				path.update(self.pieces[fr].path(to))
			if any(self.isVisible(sq) for sq in path):
				for sq in path:
					showSquareSequences.append(self.showSquare(sq))
			return showSquareSequences
		else:
			return Parallel()
	# Shows the path that a piece takes on its path from its origin to its destination
	def showPath(self, fr, to):
		path = set()
		showSquareSequences = Parallel()
		if self.pieces[fr]:
			path.update(self.pieces[fr].path(to))
		for sq in path:
			showSquareSequences.append(self.showSquare(sq))
		return showSquareSequences
	
	# Updates the board to show only the squares that are visible at the current time.
	def showVisibleSquares(self, dt="default"):
		visibles = defaultdict(lambda: False)
		for p in [(x,y) for (x,y) in self.pieces if 0 <= x < 8 and 0 <= y < 8]:
			if self.pieces[p]:
				if self.pieces[p].color == self.player:
					for s in self.pieces[p].visibleSquares(self.pieces):
						visibles[s] = True

		par = Parallel()
		for s in self.squares:
			if visibles[s]:
				par.append(self.showSquare(s, dt))
			else:
				par.append(self.hideSquare(s, dt))
		par.start()
		return par
	
	#### NETWORK I/O ####
	def sendMove(self, fr, to):
		dg = PyDatagram()
		dg.addUint8(fr[0])
		dg.addUint8(fr[1])
		dg.addUint8(to[0])
		dg.addUint8(to[1])
		
		print "Sent move (%d, %d) -> (%d, %d)" % (fr[0], fr[1], to[0], to[1])
		self.cWriter.send(dg, self.oppConnection)
	
	def receiveData(self, dg):
		dg = PyDatagramIterator(dg)
		fr = (dg.getUint8(), dg.getUint8())
		to = (dg.getUint8(), dg.getUint8())
		print "Received move %s -> %s" % (fr, to)

		def indicate():
			self.turnIndicator['text'] = 'Your turn!'
			self.sfx = loader.loadSfx('audio/ding.wav')
			self.sfx.play()

		seq = Sequence()
		seq.append(self.showPathIfVisible(fr, to))
		seq.append(self.makeMove(fr, to))
		seq.append(Func(indicate))
		seq.append(Func(self.showVisibleSquares))

		seq.start()
예제 #37
0
class FlyThroughAir(ShowBase):
    # method completely taken from RoamingRalph demo:
    def addInstructions(self, pos, msg):
        return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1), scale=.05,
                            shadow=(0, 0, 0, 1), parent=base.a2dTopLeft,
                            pos=(0.08, -pos - 0.04), align=TextNode.ALeft)

    def setUpFlyingInstructions(self):
        self.inst[0] = self.addInstructions(.06, "Arrow Keys to move around")
        self.inst[1] = self.addInstructions(.12, "w and s to control pitch")
        self.inst[2] = self.addInstructions(.18, "a and d to control yaw")
        self.inst[3] = self.addInstructions(.24, "h to switch to driving mode")
        self.inst[4] = self.addInstructions(.3, "mouse click to add object")

    def destroyInstructions(self):
        # got way to destroy text from:
        # https://www.panda3d.org/manual/index.php/OnscreenText
        for element in self.inst:
            element.destroy()

    def setUpTreeButton(self):
        pass

    def setUpDrivingInstructions(self):
        self.inst[0] = self.addInstructions(.06, "Right arrow and left arrow to turn")
        self.inst[1] = self.addInstructions(.12, "Forward and Backward arrow to go forward and backward")
        self.inst[2] = self.addInstructions(.18, "h to switch to add object mode")

    def __init__(self):
        # Set up the window, camera, etc.
        ShowBase.__init__(self)

        # Set the background color to black
        self.win.setClearColor((0, 1, 1, 1))

        # This is used to store which keys are currently pressed.
        self.keyMap = {
            "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0,
            "backward": 0, "cam-up": 0, "cam-down": 0, "add-car": 0,
            "switch-mode":0, "mouse-click":0}

        # this is the egg that came with the module
        # environ = loader.loadModel("models/world")
        # this is the one I created using mountainMaker.py
        self.environ = loader.loadModel("TestMountain1")
        self.environ.reparentTo(render)

        self.car = loader.loadModel("TestCar")
        #self.car = loader.loadModel("testModel/ball")
        self.car.reparentTo(render)

        #instructions
        self.inst = [""]*5
        self.setUpFlyingInstructions()

        # for adjusting so that the position is the center of the car
        self.adjustedXForCenter = 10/2
        self.adjustedYForCenter = 20/2

        # important for setting the size relative to everything else
        # found it here : https://www.panda3d.org/manual/index.php/Common_State_Changes
        # set the mode that the player is currently in
        self.mode = 0
        self.modeFly = 0
        self.modeRace = 1

        # to ensure that when pressing h it only switches once each press
        self.hasSwitched = False

        self.carPositionX = 10
        self.carPositionY = 10
        self.carPositionZ = 100
        # note for rotating camera: from this website: 
        # https://www.panda3d.org/manual/index.php/Common_State_Changes
        # setHpr(Yaw, Pitch, Roll)

        # setting up initial conditions for which way camera is rotated
        self.carYaw = 0
        self.carPitch = 0

        self.setUpCarCollider()
        self.setUpMouseCollider()

        # make the rocks and other stuff that will show up
        self.objects = []

        # Accept the control keys for movement and rotation

        #setting up keys for movement
        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", True])
        self.accept("arrow_right", self.setKey, ["right", True])
        self.accept("arrow_up", self.setKey, ["forward", True])
        self.accept("arrow_down", self.setKey, ["backward", True])
        self.accept("arrow_left-up", self.setKey, ["left", False])
        self.accept("arrow_right-up", self.setKey, ["right", False])
        self.accept("arrow_up-up", self.setKey, ["forward", False])
        self.accept("arrow_down-up", self.setKey, ["backward", False])

        # adding car
        self.accept("mouse1", self.setKey, ["mouse-click", True])
        self.accept("mouse1-up", self.setKey, ["mouse-click", False])

        # setting up orientation of the camera
        self.accept("a", self.setKey, ["cam-left", True])
        self.accept("s", self.setKey, ["cam-down", True])
        self.accept("a-up", self.setKey, ["cam-left", False])
        self.accept("s-up", self.setKey, ["cam-down", False])
        self.accept("d", self.setKey, ["cam-right", True])
        self.accept("d-up", self.setKey, ["cam-right", False])
        self.accept("w", self.setKey, ["cam-up", True])
        self.accept("w-up", self.setKey, ["cam-up", False])


        # to switch between tasks
        self.accept("h", self.setKey, ["switch-mode", True])
        self.accept("h-up", self.setKey, ["switch-mode", False])

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

        # Game state variables
        self.isMoving = False

        self.cameraPositionX = 0
        self.cameraPositionY = 0
        self.cameraPositionZ = 0
        # note for rotating camera: from this website: 
        # https://www.panda3d.org/manual/index.php/Common_State_Changes
        # setHpr(Yaw, Pitch, Roll)
        
        # setting up initial conditions for which way camera is rotated
        self.cameraYaw = 0
        self.cameraPitch = 0
        
        # Set up the camera
        self.disableMouse()
        
        # should probably clean up these magic numbers
        self.camera.setPos(20, 20, 20)


        # Create some lighting
        # this is a part that is completely unchanged from demo
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor((.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection((-5, -5, -5))
        directionalLight.setColor((1, 1, 1, 1))
        directionalLight.setSpecularColor((1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def setUpCarCollider(self):
        self.carCollideTrav = CollisionTraverser()
        base.cTrav = self.carCollideTrav
        self.handler = CollisionHandlerQueue()
        self.carRay = CollisionRay(self.carPositionX, self.carPositionY, 
                                   self.carPositionZ, 0, 0, -1)
        self.carCollision = CollisionNode("groundCollision")
        self.carCollision.addSolid(self.carRay)
        # add to .egg <Scalar> collide-mask { 0x0 }
        #self.carCollision.setFromCollideMask(CollideMask.bit(0))
        #self.carCollision.setIntoCollideMask(CollideMask.allOff())
        self.carCollisionNode = self.car.attachNewNode(self.carCollision)
        self.carCollideTrav.addCollider(self.carCollisionNode, self.handler)
        self.carCollisionNode.show()

    def setUpMouseCollider(self):
        # clicking on objects stuff came from here:
        # https://www.panda3d.org/manual/index.php/Collision_Traversers
        # https://www.panda3d.org/manual/index.php/Collision_Handlers
        # will not use the traverser set up by car because slow
        # instead we will render each time clicked
        self.mouseCollideTrav = CollisionTraverser("mouseTraverse")
        self.mousehandler = CollisionHandlerQueue()
        # edit this so that from Object is the camera
        # self.mouseCollideTrav.addCollider(fromObject, queue)
        # self.mouseCollideTrav.traverse(render)
        # this next part came from:
        # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
        pickerNode = CollisionNode("mouseRay")
        pickerNp = camera.attachNewNode(pickerNode)
        pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.pickerRay = CollisionRay()
        pickerNode.addSolid(self.pickerRay)
        self.mouseCollideTrav.addCollider(pickerNp, self.mousehandler)
        

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

    def move(self, task):
        if(self.mode==self.modeFly):
            # Get the time that elapsed since last frame.  We multiply this with
            # the desired speed in order to find out with which distance to move
            # in order to achieve that desired speed.
            dt = globalClock.getDt()

            if self.keyMap["switch-mode"] and not self.hasSwitched:
                self.mode = (self.mode+1)%2
                self.destroyInstructions()
                self.setUpDrivingInstructions()
                self.hasSwitched = True
            elif not self.keyMap["switch-mode"]:
                self.hasSwitched = False

            # the angle is in degrees with 360 equal to full rotation
            angleAdjustment = 100
            if self.keyMap["cam-left"]:
                self.cameraYaw += angleAdjustment*dt
            if self.keyMap["cam-right"]:
                self.cameraYaw -= angleAdjustment*dt
            if self.keyMap["cam-up"]:
                self.cameraPitch += angleAdjustment*dt
            if self.keyMap["cam-down"]:
                self.cameraPitch -= angleAdjustment*dt

            positionAdjustment = 500
            # should switch rad and Deg in variable name
            radToDeg = math.pi/180
            # the x and y component of left and right moves, do not need to 
            # compensate in z axis because not doing any roll, so there should be 
            # no zComponent
            xComponent = math.cos(self.cameraYaw*radToDeg)
            yComponent = math.sin(self.cameraYaw*radToDeg)
    
            if self.keyMap["left"]:
                self.cameraPositionX -= positionAdjustment * dt *xComponent
                self.cameraPositionY -= positionAdjustment * dt *yComponent
            if self.keyMap["right"]:
                self.cameraPositionX += positionAdjustment * dt*xComponent
                self.cameraPositionY += positionAdjustment * dt*yComponent
    
            # for going forward, the orientation is rotated 90 degrees so need to 
            # change components
            xComponent = math.cos(self.cameraYaw*radToDeg+math.pi/2)*math.cos(
                                                        self.cameraPitch*radToDeg)
            yComponent = math.sin(self.cameraYaw*radToDeg+math.pi/2)*math.cos(
                                                        self.cameraPitch*radToDeg)
            zComponent = math.sin(self.cameraPitch*radToDeg)

            if self.keyMap["forward"]:
                self.cameraPositionX += positionAdjustment * dt*xComponent
                self.cameraPositionY += positionAdjustment * dt*yComponent
                self.cameraPositionZ += positionAdjustment * dt*zComponent
            if self.keyMap["backward"]:
                self.cameraPositionX -= positionAdjustment * dt*xComponent
                self.cameraPositionY -= positionAdjustment * dt*yComponent
                self.cameraPositionZ -= positionAdjustment * dt*zComponent

            self.camera.setX(self.cameraPositionX)
            self.camera.setY(self.cameraPositionY)
            self.camera.setZ(self.cameraPositionZ)
            self.camera.setHpr(self.cameraYaw, self.cameraPitch, 0)

            # when implementing the use of the mouse look here:
            # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects

    
            # clicking on 3D objects comes from here:
            # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
            # checks if it needs to add any objects:
            if(self.keyMap["mouse-click"]):
                # found way to speed this up by only doing collision check
                # when mouse clicked by not using cTrav like in this method
                # the way I did it I found here:
                # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
                self.mouseCollideTrav.traverse(render)
                if(base.mouseWatcherNode.hasMouse()):
                    mousePos = base.mouseWatcherNode.getMouse()
                    self.pickerRay.setFromLens(base.camNode, mousePos.getX(), mousePos.getY())
                    if(self.mousehandler.getNumEntries()>0):
                        entries = list(self.mousehandler.getEntries())
                        # pathagorean formula for sorting
                        entries.sort(key=lambda x: ((x.getSurfacePoint(render).getX(
                                    )-self.cameraPositionX)**2 + 
                                    (x.getSurfacePoint(render).getY()-
                                    self.cameraPositionY)**2)**.5)
                        newX = entries[0].getSurfacePoint(render).getX()
                        newY = entries[0].getSurfacePoint(render).getY()
                        newZ = entries[0].getSurfacePoint(render).getZ()
                        self.objects.append(loader.loadModel("TestCar.egg"))
                        self.objects[len(self.objects)-1].reparentTo(render)
                        self.objects[len(self.objects)-1].setPos(newX, newY, newZ)
            return task.cont
        elif(self.mode == self.modeRace):
            # Get the time that elapsed since last frame.  We multiply this with
            # the desired speed in order to find out with which distance to move
            # in order to achieve that desired speed.
            dt = globalClock.getDt()

            degreeAdjustment = 60
            positionAdjustment = 100
            # should switch rad and Deg in variable name
            radToDeg = math.pi/180
            # the x and y component of left and right moves, do not need to 
            # compensate in z axis because not doing any roll, so there should be 
            # no zComponent

            xComponent = math.sin(self.carYaw*radToDeg)
            yComponent = math.cos(self.carYaw*radToDeg)

            if self.keyMap["switch-mode"] and not self.hasSwitched:
                self.mode = (self.mode+1)%2
                self.destroyInstructions()
                self.setUpFlyingInstructions()
                self.hasSwitched = True
            elif not self.keyMap["switch-mode"]:
                self.hasSwitched = False

            if self.keyMap["left"]:
                self.carYaw += degreeAdjustment * dt
            if self.keyMap["right"]:
                self.carYaw -= degreeAdjustment * dt
            if self.keyMap["forward"]:
                self.carPositionX -= positionAdjustment * dt*xComponent
                self.carPositionY += positionAdjustment * dt*yComponent
            if self.keyMap["backward"]:
                self.carPositionX += positionAdjustment * dt*xComponent
                self.carPositionY -= positionAdjustment * dt*yComponent

            # need to consider both the x and y component of offset for both
            # because x slowly changes to y as it turns

            actualXPos = (self.carPositionX+self.adjustedXForCenter*
                          math.cos(radToDeg*self.carYaw)+self.adjustedYForCenter
                          *math.sin(radToDeg*self.carYaw))
            actualYPos = (self.carPositionY+self.adjustedYForCenter*
                          math.cos(radToDeg*self.carYaw)+self.adjustedXForCenter
                          *math.sin(radToDeg*self.carYaw))
            self.car.setX(actualXPos)
            self.car.setY(actualYPos)
            self.car.setZ(self.carPositionZ)
            self.car.setHpr(self.carYaw, self.carPitch, 0)

            # when implementing the use of the mouse look here:
            # https://www.panda3d.org/manual/index.php/Clicking_on_3D_Objects
            
            # almost directly taken from ralph example
            entries = list(self.handler.getEntries())
            entries.sort(key=lambda x: x.getSurfacePoint(render).getZ())
            # worry about which thing it collides with later
            if (len(entries) > 0):
                # and entries[0].getIntoNode().getName() == "mountainCollide":
                self.carPositionZ = (entries[0].getSurfacePoint(render).getZ())
            else:
                # because at 100 everything should be below car and do not want
                # to continually go up or else it may go up forever. 
                self.car.setZ(100)
                print("less")
            
            # Modify view of camera so that it is behind car
            distanceBehind = 40
            distanceAbove = 20
            self.camera.setHpr(self.carYaw, -.5, 0)
            camX = actualXPos + distanceBehind * math.sin(radToDeg*self.carYaw)
            camY = actualYPos - distanceBehind * math.cos(radToDeg*self.carYaw)
            camZ = self.carPositionZ + distanceAbove
            self.camera.setPos(camX, camY, camZ)
            return task.cont
예제 #38
0
class MouseHandler (DirectObject):
    def __init__(self):
        self.accept('mouse1', self.onMouse1Down, [])  # Left click
        self.accept('mouse1-up', self.onMouse1Up, [])
        self.accept('mouse3', self.onMouse3Down, [])  # Right click

        self.showCollisions = False

        pickerNode = CollisionNode('mouseRay')
        pickerNP = camera.attachNewNode(pickerNode)
        pickerNode.setFromCollideMask(cardBuilder.cardCollisionMask)
        self.pickerRay = CollisionRay()
        pickerNode.addSolid(self.pickerRay)
        base.cTrav.addCollider(pickerNP, base.handler)
        if self.showCollisions:
            base.cTrav.showCollisions(render)
        base.disableMouse()

        self.activeCard = None
        self._targeting = False

        self._dragging = None

        # Counts down between clicks to detect double click
        self.doubleClickTimer = -1.0
        self.doubleClickInterval = 1.0

        self.line = attackLine.Line()

    @property
    def targeting(self):
        return self._targeting

    @targeting.setter
    def targeting(self, value):
        self._targeting = value
        if self._targeting:
            base.guiScene.showTargeting()
        else:
            base.guiScene.hideTargeting()

    def startTargeting(self, targetDesc, callback=None):
        base.targetDesc = targetDesc
        self.targeting = True
        if callback is not None:
            base.targetCallback = callback

    def getObjectClickedOn(self):
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())

            base.cTrav.traverse(render)
            if (base.handler.getNumEntries() > 0):
                base.handler.sortEntries()
                pickedObj = base.handler.getEntry(0).getIntoNodePath()
                pickedObj = pickedObj.findNetPythonTag('zone')
                if pickedObj == self.dragging and base.handler.getNumEntries() > 1:
                    for entry in base.handler.getEntries():
                        n = entry.getIntoNodePath().findNetPythonTag('zone')
                        if n != self.dragging and n.parent != self.dragging:
                            return n

                    # If we don't find another object, do nothing
                    # TODO: Every object should only have 1 collider to make this easier

                return pickedObj

    def doClick(self):
        pickedObj = self.getObjectClickedOn()

        if self.dragging:
            return

        if self.targeting and pickedObj is not None:
            base.targetCallback(pickedObj)
        elif pickedObj and not pickedObj.isEmpty():
            zone = pickedObj.getPythonTag('zone')
            if zone is base.player.hand and not base.gameState.hasMulliganed:
                c = pickedObj.getPythonTag('card')
                if c in base.toMulligan:
                    base.toMulligan.remove(c)
                    base.audioMaster.mulliganSelectSound.play()
                else:
                    base.toMulligan.append(c)
                    base.audioMaster.mulliganDeselectSound.play()
                base.zoneMaker.makeMulliganHand()
            elif zone is base.player.hand:
                self.dragging = pickedObj
            elif zone is base.player.facedowns:
                c = pickedObj.getPythonTag('card')
                if self.activeCard:
                    self.activeCard = None
                elif c.requiresTarget:
                    self.startTargeting(c.targetDesc)
                    def callback(target):
                        base.revealFacedown(pickedObj, target)
                        base.finishTargeting()
                    base.targetCallback = callback
                else:
                    base.revealFacedown(pickedObj)
            elif zone is base.player.faceups:
                c = pickedObj.getPythonTag('card')
                if not c.hasAttacked:
                    self.activeCard = pickedObj
            elif zone is base.enemy.facedowns and self.activeCard:
                base.attack(self.activeCard, pickedObj)
                self.activeCard = None
            elif zone == base.enemy.faceups and self.activeCard:
                base.attack(self.activeCard, pickedObj)
                self.activeCard = None
            elif zone is base.enemy.face and self.activeCard:
                base.attack(self.activeCard, pickedObj)
                self.activeCard = None
        else:
            self.activeCard = None

    @property
    def dragging(self):
        return self._dragging

    @dragging.setter
    def dragging(self, obj):
        if obj is None:
            self._dragging.removeNode()
            base.zoneMaker.makePlayerHand()  # Put the card back
        else:
            obj.reparentTo(base.zoneMaker.scene)
            obj.setHpr(0, -90, 0)

        self._dragging = obj

    def stopDragging(self):
        """
        Stop dragging the card and play it if it's in the drop zone
        """
        # Borders of the drop zone
        # If you drop the card outside the drop zone,
        # the action is cancelled
        pos = self._dragging.getPos()
        if inDropZone(pos):
            try:
                target = None
                c = self.dragging.getPythonTag('card')
                if c.fast:
                    pickedObj = self.getObjectClickedOn()
                    if pickedObj is not None and pickedObj != self.dragging:
                        target = pickedObj
                    elif c.requiresTarget:
                        # don't fizzle if no valid target
                        self.dragging = None
                        return

                base.playCard(self._dragging, target)
            except IllegalMoveError as e:
                print(e)
        self.dragging = None

    def onMouse1Down(self):
        if self._dragging is not None:
            self.stopDragging()
            self.doubleClickTimer = -1
        elif self.doubleClickTimer <= 0:
            self.doubleClickTimer = 0.2
            try:
                self.doClick()
            except IllegalMoveError as e:
                print(e)

    def onMouse1Up(self):
        if self._dragging and self.doubleClickTimer <= 0:
            self.stopDragging()

    def onMouse3Down(self):
        if self.targeting:
            base.targetCallback(None)

        if self.dragging:
            self.dragging = None

    def mouseToXYPlane(self):
        mpos = base.mouseWatcherNode.getMouse()
        # See the Panda3d chess example
        self.pickerRay.setFromLens(
            base.camNode, mpos.getX(), mpos.getY())
        # Get a vector relative to the camera position
        nearPoint = render.getRelativePoint(
            camera, self.pickerRay.getOrigin())
        nearVec = render.getRelativeVector(
            camera, self.pickerRay.getDirection())

        return PointAtZ(.5, nearPoint, nearVec)

    def mouseOverTask(self):
        if base.mouseWatcherNode.hasMouse():
            if self.doubleClickTimer > 0:
                # Count down based on how long it took to draw the last frame
                self.doubleClickTimer -= globalClock.getDt()

            if hasattr(self, '_activeObj') and self._activeObj is not None:
                zone = self._activeObj.getPythonTag('card').zone
                if zone is base.player.facedowns or zone is base.enemy.facedowns:
                    zoneMaker.hideCard(self._activeObj)

                base.zoneMaker.unfocusCard()
                self._activeObj = None

            if self.dragging is not None:
                # Drag the card in the XY plane
                self.dragging.setPos(self.mouseToXYPlane())
            elif base.gameState.hasMulliganed:
                pickedObj = self.getObjectClickedOn()
                if pickedObj:
                    card = pickedObj.getPythonTag('card')
                    if card is not None and not pickedObj.getPythonTag('disableFocus'):
                        self._activeObj = pickedObj
                        if card.zone in (
                                base.enemy.hand,
                                base.player.facedowns,
                                base.enemy.facedowns):
                            zoneMaker.showCard(pickedObj)
                        base.zoneMaker.focusCard(pickedObj)

                if self.activeCard:
                    basePos = (pickedObj.getPos(base.render)
                        if pickedObj is not None and not pickedObj.isEmpty()
                        else self.mouseToXYPlane()),
                    self.line.draw(
                        start=self.activeCard.getPos(base.render),
                        end=basePos)
                else:
                    self.line.clear()
예제 #39
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
예제 #40
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)
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 ) )
예제 #42
0
class MyApp(ShowBase, DirectObject.DirectObject):
	def __init__(self):
		ShowBase.__init__(self)

		# generate a new game
		game = Game()
		game.create_player('Player One')
		game.create_player('Player Two')
		game.create_player('Player Three')

		game.initialize_board()

		# place some random cities
		for player in game.players.values():
			# give the player some random resources
			for resource in player.resources:
				player.resources[resource] = random.randint(0,8)
			while True:
				n = random.choice(game.board.network.nodes())
				if game.board.node_available(n):
					game.board.update_building(n, player, 'city')

					# place a random road
					m = random.choice(game.board.network.neighbors(n))
					game.board.network.edge[n][m]['road'] = True
					game.board.network.edge[n][m]['player'] = player
					break

		self.board_renderer = BoardRenderer(self, game.board)
		self.hand_renderer = HandRenderer(self, game.players.values()[0])

		# setup some 3-point lighting for the whole board
		lKey = DirectionalLight('lKey')
		lKey.setColor(VBase4(0.9,0.9,0.9,1))
		lKeyNode = render.attachNewNode(lKey)
		lKeyNode.setH(-63)
		lKeyNode.setP(-60)
		lKeyNode.setR(-30)
		render.setLight(lKeyNode)

		lFill = DirectionalLight('lFill')
		lFill.setColor(VBase4(0.4,0.4,0.4,1))
		lFillNode = render.attachNewNode(lFill)
		lFillNode.setH(27)
		lFillNode.setP(-15)
		lFillNode.setR(-30)
		render.setLight(lFillNode)

		lBack = DirectionalLight('lBack')
		lBack.setColor(VBase4(0.3,0.3,0.3,1))
		lBackNode = render.attachNewNode(lBack)
		lBackNode.setH(177)
		lBackNode.setP(-20)
		lBackNode.setR(0)
		render.setLight(lBackNode)

		lBelow = DirectionalLight('lBelow')
		lBelow.setColor(VBase4(0.4,0.4,0.4,1))
		lBelowNode = render.attachNewNode(lBelow)
		lBelowNode.setH(0)
		lBelowNode.setP(90)
		lBelowNode.setR(0)
		render.setLight(lBelowNode)

		self.accept('a', self.on_toggle_anti_alias)
		self.mouse_controlled = True
		self.on_toggle_mouse_control()
		self.accept('m', self.on_toggle_mouse_control)
		self.accept('q', self.on_quit)

		# onto-board selection collision test
		select_mask = BitMask32(0x100)
		self.select_ray = CollisionRay()
		select_node = CollisionNode('mouseToSurfaceRay')
		select_node.setFromCollideMask(select_mask)
		select_node.addSolid(self.select_ray)
		select_np = self.camera.attachNewNode(select_node)

		self.select_queue = CollisionHandlerQueue()
		self.select_traverser = CollisionTraverser()
		self.select_traverser.addCollider(select_np, self.select_queue)

		# create a plane that only collides with the mouse ray
		select_plane = CollisionPlane(Plane(Vec3(0,0,1), Point3(0,0,0)))

		# add plane to render
		self.select_node = CollisionNode('boardCollisionPlane')
		self.select_node.setCollideMask(select_mask)
		self.select_node.addSolid(select_plane)
		self.select_plane_np = self.render.attachNewNode(self.select_node)

		self.debug_select = draw_debugging_arrow(self, Vec3(0,0,0), Vec3(0,1,0))

		self.taskMgr.add(self.update_mouse_target, "mouseTarget")
		self.taskMgr.add(self.update_debug_arrow, "updateDebugArrow")

	def on_toggle_anti_alias(self):
		if AntialiasAttrib.MNone != render.getAntialias():
			render.setAntialias(AntialiasAttrib.MNone)
			print "anti-aliasing disabled"
		else:
			render.setAntialias(AntialiasAttrib.MAuto)
			print "anti-aliasing enabled"

	def on_toggle_mouse_control(self):
		if self.mouse_controlled:
			self.disableMouse()
			self.taskMgr.add(self.spin_camera_task, "spinCameraTask")
		else: self.enableMouse()

		self.mouse_controlled = not self.mouse_controlled

	def spin_camera_task(self, task):
		height = 9
		distance = 15
		speed = 1./16
		angle = (task.time*speed) * 2 * pi

		self.camera.setPos(distance*cos(angle), distance*-sin(angle), height)
		self.camera.lookAt(0,0,0)

		if self.mouse_controlled: return Task.done
		return Task.cont

	def update_mouse_target(self, task):
		if not base.mouseWatcherNode.hasMouse():
			self.mouse_target = None
			return Task.cont

		# setup ray through camera position and mouse position (on camera plane)
		mouse_pos = base.mouseWatcherNode.getMouse()
		self.select_ray.setFromLens(self.board_renderer.base.camNode, mouse_pos.getX(), mouse_pos.getY())

		self.select_traverser.traverse(self.board_renderer.base.render)

		# abort if there's no collision
		if not self.select_queue.getNumEntries(): return Task.cont

		collision = self.select_queue.getEntry(0)
		self.mouse_board_collision = collision.getSurfacePoint(collision.getIntoNodePath())
		self.mouse_target = 'board'

		return Task.cont

	def update_debug_arrow(self, task):
		if self.mouse_target:
			self.debug_select.setPos(self.mouse_board_collision)
		return Task.cont

	def on_pick(self):
		if not self._update_pick_ray(): return

		# traverse scene graph and determine nearest selection (if pickable)
		self.pick_traverser.traverse(self.board_renderer.base.render)
		self.pick_queue.sortEntries()
		if not self.pick_queue.getNumEntries(): return
		node = self.pick_queue.getEntry(0).getIntoNodePath().findNetTag('pickable')
		if node.isEmpty() or node.getTag('pickable') == 'False': return

		# add some color
		ts = TextureStage('ts')
		ts.setMode(TextureStage.MModulate)
		colors = list(Game.player_colors)
		colors.remove('white')
		node.setTexture(ts, self.board_renderer.tileset.load_texture('textures/player%s.png' % random.choice(colors).capitalize()))

	def on_quit(self):
		sys.exit(0)
예제 #43
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)
예제 #44
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))
예제 #45
0
class Picker(Viewer):
    """ View and click objects in a scene."""
    def __init__(self):
        # Parent init.
        super(Picker, self).__init__()
        self.disableMouse()
        # Picker stuff.
        self.contact_margin = Vec3(0.01, 0.01, 0.01)
        self.parser = None
        self.marked = None
        self.attached_pairs = set()
        self.contacts = None
        self.contact_points = None
        self.contact_bottoms = None
        self.compound_components = []
        self.compound_objects = []
        self.joints = JointManager()
        self.wire_attrib = RenderModeAttrib.make(RenderModeAttrib.MWireframe,
                                                 4.)
        self.attachment_colors = (Vec4(0.1, 0.1, 1.,
                                       1.), Vec4(0.1, 0.8, 0.1,
                                                 1.), Vec4(1., 0.1, 1., 1.),
                                  Vec4(1., 0.5, 0.1, 1.), Vec4(1., 1., 1., 1.))
        self.max_attach = 999
        self.permanent_events += ["mouse1"]
        # Make cursor dot.
        self.cursor = self._build_cursor("cross")
        s = 0.08
        self.cursor.setScale(s, s, s)
        self.cursor.setColor(1, 1, 1, 1)
        self.cursor.reparentTo(self.aspect2d)
        self.taskMgr.add(self.draw_cursor2d, "draw_cursor2d")
        self.permanent_tasks.append("draw_cursor2d")

    def init_ssos(self, *args, **kwargs):
        super(Picker, self).init_ssos(*args, **kwargs)

    def init_physics(self, *args, **kwargs):
        super(Picker, self).init_physics(*args, **kwargs)
        self.joints.bbase = self.bbase

    def init_picker(self):
        # Collision traverser
        self.traverser = CollisionTraverser("traverser")
        # Collision handler
        self.handler = CollisionHandlerQueue()
        # Initialize and set up picker ray node and NodePath
        self.picker = CollisionNode("mouse_ray")
        self.pickerNP = self.camera.attachNewNode(self.picker)
        self.picker.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.picker_ray = CollisionRay()
        self.picker.addSolid(self.picker_ray)
        self.traverser.addCollider(self.pickerNP, self.handler)
        mark_color = (1, 1, 1, 0.3)
        self.base_mark = self.create_mark(color=mark_color)
        connector_color = (1, 1, 1, 1)
        self.base_connector = self.create_connector(color=connector_color)

    def _build_cursor(self, shape="sphere"):
        if shape == "sphere":
            cursor = self._load("sphere.bam")
        elif shape == "cross":
            cursor = LineNodePath()
            lines = [[Point3(-0.5, 0, 0),
                      Point3(0.5, 0, 0)],
                     [Point3(0, 0, -0.5),
                      Point3(0, 0, 0.5)]]
            cursor.drawLines(lines)
            cursor.setThickness(1)
            cursor.create()
            # cursor = NodePath("cross")
            # S = {"cylinderX.bam": ((0., 0., 0.), (1., 0.1, 0.1)),
            #      "cylinderY.bam": ((0., 0., 0.), (0.1, 1., 0.1)),
            #      "cylinderZ.bam": ((0., 0., 0.), (0.1, 0.1, 1.))}
            # for k, v in S.iteritems():
            #     m = self._load(k)
            #     m.setName(k)
            #     m.setPos(*v[0])
            #     m.setScale(*v[1])
            #     m.reparentTo(cursor)
        #BP()
        return cursor

    def create_mark(self, color):
        """ Makes a graphical mark object."""
        # Make a graphical box.
        props = dict(name="mark", color=color, model="box-round.egg")
        obj = GSO(props=props)
        return obj

    def create_connector(self, color):
        """ Makes a graphical connector object."""
        # Make a graphical box.
        props = dict(name="connector", color=color, model="connector.egg")
        obj = GSO(props=props)
        return obj

    def start_picker(self, pickables):
        # Set pickable objs.
        for i, obj in enumerate(pickables):
            obj.setTag("pickable", str(i))
        # Add mouse events.
        self.accept("mouse1", self.clicked, extraArgs=[1])
        # Start contact detector.
        detector = ContactDetector(self.bbase.world,
                                   self.scene,
                                   margin=self.contact_margin)
        self.contacts = detector.contacts
        self.contact_bodies = detector.bodies
        self.contact_points = detector.points
        parser = Parser(self.contacts, self.contact_bodies)
        self.contact_bottoms = parser.bottom_bodies
        self.connectors = {}

    def stop_picker(self):
        self.removeTask("mouse1")

    def goto_sso(self, *args, **kwargs):
        self.clear_attachments()
        self.stop_picker()
        super(Picker, self).goto_sso(*args, **kwargs)
        self.remove_physics()
        # Start picker.
        pickables = self.sso.descendants(type_=PSO)
        self.start_picker(pickables)
        self.attach_physics()

    def get_picked_obj(self):
        mpos = self.mouseWatcherNode.getMouse()
        self.picker_ray.setFromLens(self.cam.node(), mpos.getX(), mpos.getY())
        self.traverser.traverse(self.render)
        if self.handler.getNumEntries() > 0:
            # This is so we get the closest object
            self.handler.sortEntries()
            entries = self.handler.getEntries()
            for entry in entries:
                picked_obj = entry.getIntoNodePath().findNetTag("pickable")
                if not picked_obj.isEmpty():
                    break
            if picked_obj.isEmpty():
                picked_obj = None
        else:
            picked_obj = None
        return picked_obj

    def clicked(self, button):
        """ Mouse click handler."""
        if self.mouseWatcherNode.hasMouse():
            # Get picked object
            picked_obj = self.get_picked_obj()
            if picked_obj is not None:
                if self.marked is None:
                    # New mark activated.
                    self.marked = picked_obj
                    self.show_marked(picked_obj, True)
                    event = "mark"
                elif picked_obj == self.marked:
                    # Existing mark deactivated.
                    self.show_marked(picked_obj, False)
                    self.marked = None
                    event = "unmark"
                else:
                    # New attachment or detachment.
                    pair = tuple(sorted((self.marked, picked_obj)))
                    ij = tuple(
                        sorted((self.contact_bodies.index(pair[0]),
                                self.contact_bodies.index(pair[1]))))
                    if ij in self.contacts:
                        f_add = (ij, pair) not in self.attached_pairs
                        if (not f_add
                                or len(self.attached_pairs) < self.max_attach):
                            self.store_attachment(ij, pair, f_add)
                            self.show_marked(self.marked, False)
                            self.marked = None
                            event = "attach" if f_add else "detach"
                        else:
                            print("Max attachments already reached.")
                            event = "max-attach"
                    else:
                        event = "non-contact"
            else:
                event = "non-pick"
            return picked_obj, event

    def store_attachment(self, ij, pair, f_add):
        """ Stores the attached objects, and draws them."""
        if f_add:
            self.attached_pairs.add((ij, pair))
            self.show_attachment(ij, True)
            self.attach_pair(pair, True)
        else:
            try:
                self.attached_pairs.remove((ij, pair))
            except KeyError:
                pass
            else:
                self.attach_pair(pair, False)
                self.show_attachment(ij, False)

    def clear_attachments(self):
        """ Clear all attachments."""
        if self.marked:
            self.show_marked(self.marked, False)
            self.marked = None
            self.mark = None
        for ij, pair in self.attached_pairs:
            self.attach_pair(pair, False)
            self.show_attachment(ij, False)
        self.attached_pairs = set()
        #
        self.reset_compounds()
        self.contacts = None
        self.contact_bodies = None
        self.contact_points = None
        self.contact_bottoms = None

    def _make_mark(self, node, extent, name):
        """ Makes a mark GSO."""
        mark = self.base_mark.copy()
        mat = node.getMat(self.scene)
        mark.apply_prop(dict(name=name), other=self.scene)
        mark.setMat(self.scene, mat)
        mark.setScale(self.scene, mark.getScale(self.scene) + extent)
        mark.wrtReparentTo(node)
        return mark

    def show_marked(self, node, f_on):
        """ Turns on/off marked graphic."""
        if f_on:
            extent = Vec3(0.15, 0.15, 0.15)
            name = "mark"
            self.mark = self._make_mark(node, extent, name)
            self.mark.init_tree(tags=("model", ))
            # Exclude object from casting shadows
            self.mark.hide(self.shadow_mask)
            self.mark.setTransparency(TransparencyAttrib.MAlpha)
            self.mark.setDepthWrite(False)
            self.mark.setBin("fixed", 0, priority=5)
        else:
            self.mark.removeNode()

    def _make_connector(self, parent, points, extent, name):
        """ Makes connector object."""
        connector = self.base_connector.copy()
        scale = Vec3(*(np.ptp(points, axis=0)))
        scale_extended = scale + extent
        pos = Point3(*(np.min(points, axis=0) + scale / 2.))
        connector.apply_prop(dict(name=name, scale=scale_extended, pos=pos),
                             other=self.scene)
        connector.wrtReparentTo(parent)
        return connector

    def show_attachment(self, ij, f_on):
        """ Turns on/off attachment graphic."""
        if f_on:
            parent = self.contact_bottoms[ij]
            points = self.contact_points[ij]
            extent = Vec3(0.15, 0.15, 0.15)
            name = "connector_%d-%d" % ij
            self.connectors[ij] = self._make_connector(parent, points, extent,
                                                       name)
            self.connectors[ij].init_tree(tags=("model", ))
        else:
            self.connectors.pop(ij).removeNode()

    # def attach_pair(self, pair, f_on):
    #     """ Adds/removes physical attachment between a pair of nodes."""
    #     key = tuple(sorted(p.node() for p in pair))
    #     # key = frozenset(pair)
    #     if f_on:
    #         # Create the joint and add it.
    #         self.joints[key] = self.joints.make_fixed(*pair)
    #     else:
    #         # Remove it.
    #         del self.joints[key]

    def attach_physics(self):
        # Attach `self.scene` to the physics world.
        try:
            exclude = zip(*self.compound_components)[0]
        except IndexError:
            exclude = []
        bnodes = [
            bnode for bnode in self.scene.descendants(type_=PSO)
            if bnode not in exclude
        ]
        for bnode in bnodes:
            bnode.init_resources(tags=("shape", ))
            bnode.setCollideMask(BitMask32.allOn())
            bnode.node().setDeactivationEnabled(False)
        self.bbase.attach(bnodes)

    def reset_compounds(self):
        for n, p in self.compound_components:
            n.wrtReparentTo(p)
        self.compound_components = []
        for cnode in self.compound_objects:
            cnode.destroy_resources()
            cnode.removeNode()
        self.compound_objects = []

    def make_attachment_graph(self):
        if not self.contact_bodies:
            return None
        n = len(self.contact_bodies)
        mtx = np.zeros((n, n), dtype="i")
        for (i, j), _ in self.attached_pairs:
            # i = self.contact_bodies.index(pair[0])
            # j = self.contact_bodies.index(pair[1])
            mtx[i, j] = 1
            # mtx[j, i] = 1
        graph = nx.from_numpy_matrix(mtx)
        return graph

    def attach_pair(self, pair, f_on):
        """ Adds/removes physical attachment between a pair of nodes."""
        # Get the connected subgroups.
        graph = self.make_attachment_graph()
        sgs = [sg for sg in nx.connected_components(graph) if len(sg) > 1]
        self.reset_compounds()
        # Iterate over subgroups, creating compound shapes.
        for sg in sgs:
            nodes = [self.contact_bodies[i] for i in sg]
            parents = [c.getParent() for c in nodes]
            self.compound_components.extend(zip(nodes, parents))
            cname = "+".join([str(i) for i in sorted(sg)])
            cnode = CPSO(cname)
            cnode.reparentTo(self.scene)
            cnode.add(nodes)
            cnode.init_tree(tags=("shape", ))
            cnode.destroy_component_shapes()
            self.compound_objects.append(cnode)
예제 #46
0
class CameraControl(DirectObject):
    def __init__(self, panda3d):
        # Inicialización de variables
        self.winsize = [0, 0]
        self.panda3d = panda3d
        self.panda3d.mouse_on_workspace = False

        # Desabilita el comportamiento por defecto de la camara
        self.panda3d.disable_mouse()

        # Llama a la función self.window_rezise_event cuando la ventana cambia de tamaño
        self.accept('window-event', self.window_rezise_event)
        # self.panda3d.accept('aspectRatioChanged', lambda: print("ss"))
        # Creamos el punto donde se centrará la cámara
        target_pos = Point3(0., 0., 0.)

        self.panda3d.cam_target = self.panda3d.render.attach_new_node("camera_target")
        self.panda3d.cam_target.set_pos(target_pos)
        self.panda3d.camera.reparent_to(self.panda3d.cam_target)
        self.panda3d.camera.set_y(-50.)
        
        # Definimos la cambinación de teclas para el control de la camara
        self.camera_active = False

        self.orbit_mouse_btn = "mouse2"
        self.orbit_keyboard_btn = "shift"
        self.orbit_mouse_reference = None
        self.orbit_camera_reference = None

        self.pan_mouse_btn = "mouse2"
        self.pan_keyboard_btn = "mouse2"
        self.pan_mouse_reference = None
        self.pan_camera_reference = None

        self.zoom_mouse_btn = "mouse2"
        self.zoom_keyboard_btn = "control"
        self.zoom_mouse_reference = None
        self.zoom_camera_reference = None

        # Establecemos los valores máximos y minimos para el zoom
        
        self.max_zoom = 10
        self.min_zoom = 0.1
        
        # Creamos la tarea de control de la camara
        self.panda3d.task_mgr.add(self.camera_control_task, "camera_control")

        # El movimiento de la rueda del mouse controla el zoom
        self.panda3d.accept("wheel_up", self.zoom_in)
        self.panda3d.accept("wheel_down", self.zoom_out)

        # Una fución de prueba para comprobar la posición del mouse en el modelo 3d
        # self.panda3d.accept("mouse1", self.entity_select)

        # Se establece la lente ortografica en lugar de la perspectiva
        self.lens_type = "OrthographicLens"
        self.set_lens(self.lens_type)

        # Agrega un indicador de ejes en la esquina inferior izquierda
        self.corner = self.panda3d.camera.attachNewNode("corner of screen")
        # self.axis = self.panda3d.loader.loadModel("data/geom/custom-axis")
        # self.axis = self.panda3d.loader.loadModel("data/geom/view_gizmo_F")
        self.view_gizmo = list()
        self.view_gizmo.append(self.panda3d.loader.loadModel("data/geom/view_gizmo_compass"))

        # self.view_gizmo.append(self.panda3d.loader.loadModel("data/geom/view_gizmo_L"))
        # self.view_cube = ViewGizmoZone()
        # self.view_cube.set_geom(self.axis)

        for gizmo_geom in self.view_gizmo:
            gizmo_geom.setLightOff(1)
            # gizmo_geom.setColorScale(1,1,1,1)
            gizmo_geom.setShaderInput("colorborders", LVecBase4(0, 0, 0, 0.25))

            gizmo = ViewGizmoZone()
            gizmo.set_geom(gizmo_geom)
            gizmo_geom.node().setBounds(BoundingSphere(Point3(0, 0, 0), 10))
            gizmo_geom.node().setFinal(True)

            #gizmo_geom.showTightBounds()
            # gizmo_geom.showBounds()



        self.show_view_gizmo()

        # Agregamos una luz puntual en la ubicación de la camara
        plight = DirectionalLight("camera_light")
        plight.setColor((1, 1, 1, 1))
        #plight.setAttenuation((1, 0, 0))
        #print("getMaxDistance {}".format(plight.getMaxDistance()))
        self.panda3d.plight_node = self.panda3d.render.attach_new_node(plight)
        self.panda3d.plight_node.setPos(0, -50, 0)
        self.panda3d.render.setLight(self.panda3d.plight_node)
        self.panda3d.plight_node.reparentTo(self.panda3d.camera)



        # Agregamos luz ambiental que disminuya las zonas oscuras
        alight = AmbientLight('alight')
        alight.setColor((0.3, 0.3, 0.3, 1))

        alnp = self.panda3d.render.attachNewNode(alight)
        self.panda3d.render.setLight(alnp)

        #def init_select_detection(self):
        self.traverser = CollisionTraverser("")
        # self.traverser.show_collisions(self.panda3d.render)
        self.picker_ray = CollisionRay()
        self.handler = CollisionHandlerQueue()

        self.picker_node = CollisionNode('mouseRay')
        self.picker_np = self.panda3d.camera.attachNewNode(self.picker_node)
        self.picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.picker_ray = CollisionRay()
        self.picker_node.addSolid(self.picker_ray)
        self.traverser.addCollider(self.picker_np, self.handler)

    def set_lens(self, lens_type="OrthographicLens"):
        """
        Permite cambiar la lente de la camara

        :param lens_type: El tipo de lente a utilizar: OrthographicLens/PerspectiveLens
        :return: None
        """

        self.lens_type = lens_type
        width = self.panda3d.win.getXSize()
        height = self.panda3d.win.getYSize()

        if lens_type is "OrthographicLens":
            lens = OrthographicLens()
            lens.setFilmSize(width, height )
        if lens_type is "PerspectiveLens":
            lens = PerspectiveLens()
            lens.setFilmSize(width , height )
        else:
            # Default value
            lens = OrthographicLens()
            lens.setFilmSize(width / 100, height / 100)

        print("new lens {}: {} {}".format(lens_type, width / 100, height / 100))
        print(lens)
        self.panda3d.cam.node().setLens(lens)

        shader_control = self.panda3d.shader_control
        if shader_control is not None:
            shader_control.update_camera_lens(lens)

    def window_rezise_event(self, window=None):
        """
        Se activa con cualquier evento de la ventana de windows, en caso de que haya
        cambiado de tamaño la ventana regenera la lente

        :param window: Información del evento
        :return: None
        """
        if window is not None:  # Window será igual a None si la aplicación panda3d no se inició
            wp = window.getProperties()
            newsize = [wp.getXSize(), wp.getYSize()]
            if self.winsize != newsize:
                self.winsize = newsize
                self.set_lens()
                self.show_view_gizmo()

    def mouse_is_over_workspace(self):
        """
        Detecta si el mouse se encuentra dentro del area de trabajo del modelo 3d

        :return: True/False
        """
        gui_objects = app.gui_objects
        is_over_workspace = False

        if self.panda3d.mouseWatcherNode.has_mouse() and app.workspace_active:
            is_over_workspace = True
            mouse_data = self.panda3d.win.getPointer(0)
            mouse_x, mouse_y = mouse_data.getX(), mouse_data.getY()

            for name, gui_obj in gui_objects.items():

                if gui_obj.isHidden():
                    continue

                pos = gui_obj.getPos(pixel2d)
                frame_size = list(gui_obj["frameSize"])

                x0 = pos[0] + frame_size[0]
                x1 = pos[0] + frame_size[1]
                y0 = -pos[2] - frame_size[2]
                y1 = -pos[2] - frame_size[3]

                x_left = min(x0, x1)
                x_right = max(x0, x1)
                y_top = min(y0, y1)
                y_bottom = max(y0, y1)

                #if name is "status_bar":
                #print(pos)
                #print("{} {} / {} {}".format(x_left, x_right, y_top, y_bottom))

                overmouse_x = (x_left <= mouse_x <= x_right)
                overmouse_y = (y_top <= mouse_y <= y_bottom)

                # Revisa si el mouse se encuentra sobre un elemento de interfaz
                if overmouse_x and overmouse_y:

                    # print("mouse is over {}".format(name))
                    is_over_workspace = False
                    break

        app.mouse_on_workspace = is_over_workspace
        if is_over_workspace:
            get_mouse_3d_coords_task()

        return is_over_workspace

    def camera_control_task(self, task):
        """
        Se ejecuta constantemente y realiza las tareas de movimiento de la camara según las teclas presionadas
        """

        # El codigo se ejecuta si el mouse está dentro del espacio de trabajo o si ya se está realizando alguna acción
        if self.mouse_is_over_workspace() or self.camera_active:
            # Desactivamos el espacio de trabajo
            app.workspace_active = False

            # El nodo mouseWatcherNode permite recibir la entrada de mouse y teclado
            btn = self.panda3d.mouseWatcherNode

            # Obtenemos la posición del cursor
            mouse_data = self.panda3d.win.getPointer(0)
            mouse_pos = mouse_data.getX(), mouse_data.getY()

            # En función de la combinación de teclas se ejecuta una acción
            cam_task = 0
            if btn.isButtonDown(self.orbit_mouse_btn) and btn.isButtonDown(self.orbit_keyboard_btn):
                cam_task = 1
            elif btn.isButtonDown(self.zoom_mouse_btn) and btn.isButtonDown(self.zoom_keyboard_btn):
                cam_task = 2
            elif btn.isButtonDown(self.pan_mouse_btn) and btn.isButtonDown(self.pan_keyboard_btn):
                cam_task = 3

            # Orbit
            if cam_task is 1:
                self.camera_orbit(mouse_pos)
                self.camera_active = True
            else:
                self.orbit_mouse_reference = None

            # Zoom
            if cam_task is 2:
                self.camera_zoom(mouse_pos)
                self.camera_active = True
            else:
                self.zoom_mouse_reference = None

            # Pan
            if cam_task is 3:
                self.camera_pan(mouse_pos)
                self.camera_active = True
            else:
                self.pan_mouse_reference = None

            # Si la combinación de teclas no coincide con niguna acción se establece la camara como inactiva
            if cam_task is 0:
                self.camera_active = False
                # Se reactiva el espacio de trabajo
                app.workspace_active = True
                self.entity_select()
            else:
                pass
                # Actualizamos la posición de la luz puntual
                #cam = self.panda3d.camera
                #self.panda3d.plight_node.setPos(cam.get_pos(self.panda3d.render))

            # Ejecutar  solo en windows
            """if os.name == 'nt':
                # Se coloca la camra en determinadas vistas (frontal, lateral, superior, etc) al apretar el
                # teclado numérico

                # Lista de teclas http://www.kbdedit.com/manual/low_level_vk_list.html

                target = self.panda3d.cam_target
                if win32api.GetAsyncKeyState(win32con.VK_NUMPAD1):
                    target.set_hpr(0, 0, 0.)
                elif win32api.GetAsyncKeyState(win32con.VK_NUMPAD3):
                    target.set_hpr(90, 0, 0.)
                elif win32api.GetAsyncKeyState(win32con.VK_NUMPAD7):
                    target.set_hpr(0, -90, 0.)"""

        return task.cont

    def camera_orbit(self, mouse_pos):

        """
        Orbita la camara alrededor del objetivo de ésta, según la posición del mouse
        respecto del punto donde se hizo click
        """

        target = self.panda3d.cam_target

        if self.orbit_mouse_reference is None:
            self.orbit_mouse_reference = mouse_pos
            self.orbit_camera_reference = target.get_hpr()

        x_diff = self.orbit_mouse_reference[0] - mouse_pos[0]
        y_diff = self.orbit_mouse_reference[1] - mouse_pos[1]

        new_h = self.orbit_camera_reference[0] + x_diff / 4
        new_p = self.orbit_camera_reference[1] + y_diff / 4

        target.set_hpr(new_h, new_p, 0.)

    def camera_pan(self, mouse_pos):
        """
        Panea la camara alrededor del objetivo de ésta, según la posición del mouse
        respecto del punto donde se hizo click
        """
        target = self.panda3d.camera

        if self.pan_mouse_reference is None:
            self.pan_mouse_reference = mouse_pos
            self.pan_camera_reference = target.get_pos()

        x_diff = self.pan_mouse_reference[0] - mouse_pos[0]
        y_diff = self.pan_mouse_reference[1] - mouse_pos[1]

        new_x = self.pan_camera_reference[0] + x_diff / 100
        new_y = self.pan_camera_reference[1]
        new_z = self.pan_camera_reference[2] - y_diff / 100

        target.set_pos(new_x, new_y, new_z)

    def camera_zoom(self, mouse_pos):

        """
        Orbita la camara alrededor del objetivo de ésta, según la posición del mouse
        respecto del punto donde se hizo click
        """

        target = self.panda3d.cam_target

        if self.zoom_mouse_reference is None:
            self.zoom_mouse_reference = mouse_pos
            self.zoom_camera_reference = target.getScale()[0]

        y_diff = self.zoom_mouse_reference[1] - mouse_pos[1]

        new_scale = self.zoom_camera_reference * math.exp(y_diff/100)

        new_scale = max(new_scale, 0.1)
        new_scale = min(new_scale, 10)

        target.setScale(new_scale, new_scale, new_scale)

    def zoom_in(self):
        if self.mouse_is_over_workspace():
            target = self.panda3d.cam_target
            old_scale = target.getScale()[0]
            new_scale = old_scale - 0.1 * old_scale
            new_scale = max(new_scale, self.min_zoom)
            target.setScale(new_scale, new_scale, new_scale)

    def zoom_out(self):
        if self.mouse_is_over_workspace():
            target = self.panda3d.cam_target
            old_scale = target.getScale()[0]
            new_scale = old_scale + 0.1 * old_scale
            new_scale = min(new_scale, self.max_zoom)
            target.setScale(new_scale, new_scale, new_scale)

    def show_view_gizmo(self):
        """
        Agrega un indicador de ejes en la esquina inferior izquierda
        """
        scale = 0.075
        width = self.panda3d.win.getXSize()/100
        height = self.panda3d.win.getYSize()/100

        #self.corner.setPos(width / 2 - 10 * scale, 5, height / 2 - 28 * scale)
        self.corner.setPos(width / 2-1, 5, height / 2 - 2.4)

        print("DEBUG SHOW VIEW CUBE")
        print(height)
        print(height / 2 - 28 * scale)

        # Dibujar por encima de todos los objetos

        for gizmo_geom in self.view_gizmo:
            gizmo_geom.setLightOff(1)
            # gizmo_geom.setBin("fixed", 0)

            # gizmo_geom.set_two_sided(True)

            """
            Tarea pendiente:
            
            Hay que corregir un error por el cual el indicador de ejes no se dubuja por encima de todos los objetos
            pudiendo intersectarse cona las geometrías del modelo
            
            Simplemente es un error visual, no afecta al funcionamiento
            
            axis.setDepthTest(False)
            
            https://discourse.panda3d.org/t/model-always-on-screen/8135/5
            """

            gizmo_geom.setScale(scale)
            # axis.setScale(1)
            gizmo_geom.reparentTo(self.corner)
            #
            gizmo_geom.setPos(0, 0, 0)
            gizmo_geom.setCompass()
            separation = 1
            # gizmo_geom.setShaderInput("showborders", LVecBase4(0))
            # gizmo_geom.setShaderInput("colorborders", LVecBase4(0, 0, 0, 0))
            # gizmo_geom.setShaderInput("separation", LVecBase4(separation, 0, separation, 0))

    def add_cube(self):
        """
        Función de prueba, coloca cubos en la ubicación del cursor
        """
        if self.panda3d.mouse_on_workspace:
            print("add_cube")
            pos = self.panda3d.work_plane_mouse
            cube = self.panda3d.loader.loadModel("models/box")
            # Reparent the model to render.
            cube.reparentTo(self.panda3d.render)
            # Apply scale and position transforms on the model.
            cube.setScale(0.25, 0.25, 0.25)
            cube.setPos(pos[0], pos[1], pos[2])



    def entity_select(self):
        if self.panda3d.mouseWatcherNode.hasMouse():
            """traverser = CollisionTraverser("")
            #traverser.show_collisions(render)
            picker_ray = CollisionRay()
            handler = CollisionHandlerQueue()

            picker_node = CollisionNode('mouseRay')
            picker_np = self.panda3d.camera.attachNewNode(picker_node)
            picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask())
            picker_ray = CollisionRay()
            picker_node.addSolid(picker_ray)
            traverser.addCollider(picker_np, handler)

            picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask())
            mpos = self.panda3d.mouseWatcherNode.getMouse()
            picker_ray.setFromLens(self.panda3d.camNode, mpos.getX(), mpos.getY())
            traverser.traverse(self.panda3d.render)"""


            self.picker_node.setFromCollideMask(GeomNode.getDefaultCollideMask())
            mpos = self.panda3d.mouseWatcherNode.getMouse()
            self.picker_ray.setFromLens(self.panda3d.camNode, mpos.getX(), mpos.getY())
            self.traverser.traverse(self.panda3d.render)
            handler = self.handler

            # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue.
            btn = self.panda3d.mouseWatcherNode

            if handler.getNumEntries() > 0:
                # This is so we get the closest object.
                handler.sortEntries()

                entity = handler.getEntry(0).getIntoNodePath()
                entity = entity.findNetTag('entity_id')
                if not entity.isEmpty():

                    #print("entity selected: {}".format(entity.getTag("entity_id")))

                    entity_id = entity.getTag("entity_id")
                    entity_type = entity.getTag("entity_type")
                    #print(entity_type)
                    model = app.model_reg

                    category_type = model.get(entity_type, dict())
                    entity = category_type.get(entity_id, None)


                    #print(entity)
                    if btn.isButtonDown("mouse1"):
                        entity.on_click()
                        if entity.is_editable:
                            prop_editor = app.main_ui.prop_editor
                            prop_editor.entity_read(entity)
                    elif entity.is_selectable:
                        status_bar = app.main_ui.status_bar
                        status_bar.entity_read(entity)

                else:
                    print("Hay {} entidades bajo el mouse".format(handler.getNumEntries()))
            else:
                if btn.isButtonDown("mouse1"):
                    entities = app.model_reg.get("View", {})

                    if entities is None or len(entities) is 0:
                        View()

                    entities = app.model_reg.get("View")
                    entity = list(entities.values())[0]
                    prop_editor = app.main_ui.prop_editor

                    prop_editor.entity_read(entity)
                else:
                    status_bar = app.main_ui.status_bar
                    status_bar.entity_read()
예제 #47
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;
예제 #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 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])
예제 #50
0
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.mp3'
        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()
        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():

            def PointAtZ(z, point, vec):
                if vec.getZ() != 0:
                    return point + vec * ((z - point.getZ()) / vec.getZ())
                else:
                    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 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)

    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 getLocation(self):
        if self.dropShadow:
            return self.dropShadow.getPos(render)
        return self.avatar.getPos(render)

    def getLocationSelectedName(self):
        return self.locationSelectedName

    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
            del self.shadowScale
        return
예제 #51
0
class Viewport(QtWidgets.QWidget, DirectObject):

    ClearColor = LEGlobals.vec3GammaToLinear(Vec4(0.361, 0.361, 0.361, 1.0))

    def __init__(self, vpType, window, doc):
        DirectObject.__init__(self)
        QtWidgets.QWidget.__init__(self, window)
        self.doc = doc
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.setMouseTracking(True)

        self.qtWindow = None
        self.qtWidget = None

        self.window = window
        self.type = vpType

        self.spec = VIEWPORT_SPECS[self.type]

        self.lens = None
        self.camNode = None
        self.camera = None
        self.cam = None
        self.win = None
        self.displayRegion = None
        self.mouseWatcher = None
        self.mouseWatcherNp = None
        self.buttonThrower = None
        self.clickRay = None
        self.clickNode = None
        self.clickNp = None
        self.clickQueue = None
        self.tickTask = None
        self.zoom = 1.0
        self.gizmo = None
        self.inputDevice = None
        self.mouseAndKeyboard = None
        self.lastRenderTime = 0.0
        self.enabled = False
        self.needsUpdate = True

        # 2D stuff copied from ShowBase :(
        self.camera2d = None
        self.cam2d = None
        self.render2d = None
        self.aspect2d = None
        self.a2dBackground = None
        self.a2dTop = None
        self.a2dBottom = None
        self.a2dLeft = None
        self.a2dRight = None
        self.a2dTopCenter = None
        self.a2dTopCenterNs = None
        self.a2dBottomCenter = None
        self.a2dBottomCenterNs = None
        self.a2dRightCenter = None
        self.a2dRightCenterNs = None
        self.a2dTopLeft = None
        self.a2dTopLeftNs = None
        self.a2dTopRight = None
        self.a2dTopRightNs = None
        self.a2dBottomLeft = None
        self.a2dBottomLeftNs = None
        self.a2dBottomRight = None
        self.a2dBottomRightNs = None
        self.__oldAspectRatio = None

        self.gridRoot = self.doc.render.attachNewNode("gridRoot")
        self.gridRoot.setLightOff(1)
        #self.gridRoot.setBSPMaterial("phase_14/materials/unlit.mat")
        #self.gridRoot.setDepthWrite(False)
        self.gridRoot.setBin("background", 0)
        self.gridRoot.hide(~self.getViewportMask())

        self.grid = None

    def updateView(self, now=False):
        if now:
            self.renderView()
        else:
            self.needsUpdate = True

    def getGizmoAxes(self):
        raise NotImplementedError

    def getMouseRay(self, collRay=False):
        ray = CollisionRay()
        ray.setFromLens(self.camNode, self.getMouse())
        if collRay:
            return ray
        else:
            return Ray(ray.getOrigin(), ray.getDirection())

    def hasMouse(self):
        return self.mouseWatcher.hasMouse()

    def getMouse(self):
        if self.mouseWatcher.hasMouse():
            return self.mouseWatcher.getMouse()
        return Point2(0, 0)

    def is3D(self):
        return self.type == VIEWPORT_3D

    def is2D(self):
        return self.type != VIEWPORT_3D

    def makeGrid(self):
        raise NotImplementedError

    def getViewportMask(self):
        return BitMask32.bit(self.type)

    def getViewportFullMask(self):
        return self.getViewportMask()

    def makeLens(self):
        raise NotImplementedError

    def getGridAxes(self):
        raise NotImplementedError

    def expand(self, point):
        return point

    def initialize(self):
        self.lens = self.makeLens()
        self.camera = self.doc.render.attachNewNode(
            ModelNode("viewportCameraParent"))
        self.camNode = Camera("viewportCamera")
        self.camNode.setLens(self.lens)
        self.camNode.setCameraMask(self.getViewportMask())
        self.cam = self.camera.attachNewNode(self.camNode)

        winprops = WindowProperties.getDefault()
        winprops.setParentWindow(int(self.winId()))
        winprops.setForeground(False)
        winprops.setUndecorated(True)

        gsg = self.doc.gsg

        output = base.graphicsEngine.makeOutput(
            base.pipe, "viewportOutput", 0, FrameBufferProperties.getDefault(),
            winprops,
            (GraphicsPipe.BFFbPropsOptional | GraphicsPipe.BFRequireWindow),
            gsg)

        self.qtWindow = QtGui.QWindow.fromWinId(
            output.getWindowHandle().getIntHandle())
        self.qtWidget = QtWidgets.QWidget.createWindowContainer(
            self.qtWindow, self, QtCore.Qt.WindowDoesNotAcceptFocus
            | QtCore.Qt.WindowTransparentForInput
            | QtCore.Qt.WindowStaysOnBottomHint
            | QtCore.Qt.BypassWindowManagerHint | QtCore.Qt.SubWindow)  #,
        #(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowDoesNotAcceptFocus
        #| QtCore.Qt.WindowTransparentForInput | QtCore.Qt.BypassWindowManagerHint
        #| QtCore.Qt.SubWindow | QtCore.Qt.WindowStaysOnBottomHint))
        self.qtWidget.setFocusPolicy(QtCore.Qt.NoFocus)

        self.inputDevice = output.getInputDevice(0)

        assert output is not None, "Unable to create viewport output!"

        dr = output.makeDisplayRegion()
        dr.disableClears()
        dr.setCamera(self.cam)
        self.displayRegion = dr

        output.disableClears()
        output.setClearColor(Viewport.ClearColor)
        output.setClearColorActive(True)
        output.setClearDepthActive(True)
        output.setActive(True)

        self.win = output

        # keep track of the mouse in this viewport
        mak = MouseAndKeyboard(self.win, 0, "mouse")
        mouse = base.dataRoot.attachNewNode(mak)
        self.mouseAndKeyboard = mouse
        self.mouseWatcher = MouseWatcher()
        self.mouseWatcher.setDisplayRegion(self.displayRegion)
        mw = mouse.attachNewNode(self.mouseWatcher)
        self.mouseWatcherNp = mw

        # listen for keyboard and mouse events in this viewport
        bt = ButtonThrower("kbEvents")
        bt.setButtonDownEvent("btndown")
        bt.setButtonUpEvent("btnup")
        mods = ModifierButtons()
        mods.addButton(KeyboardButton.shift())
        mods.addButton(KeyboardButton.control())
        mods.addButton(KeyboardButton.alt())
        mods.addButton(KeyboardButton.meta())
        bt.setModifierButtons(mods)
        self.buttonThrower = mouse.attachNewNode(bt)

        # collision objects for clicking on objects from this viewport
        self.clickRay = CollisionRay()
        self.clickNode = CollisionNode("viewportClickRay")
        self.clickNode.addSolid(self.clickRay)
        self.clickNp = NodePath(self.clickNode)
        self.clickQueue = CollisionHandlerQueue()

        self.setupRender2d()
        self.setupCamera2d()

        self.gizmo = ViewportGizmo(self)

        self.doc.viewportMgr.addViewport(self)

        self.makeGrid()

    def cleanup(self):
        self.grid.cleanup()
        self.grid = None
        self.gridRoot.removeNode()
        self.gridRoot = None

        self.lens = None
        self.camNode = None
        self.cam.removeNode()
        self.cam = None
        self.camera.removeNode()
        self.camera = None
        self.spec = None
        self.doc = None
        self.type = None
        self.window = None
        self.zoom = None
        self.gizmo.cleanup()
        self.gizmo = None
        self.clickNp.removeNode()
        self.clickNp = None
        self.clickQueue.clearEntries()
        self.clickQueue = None
        self.clickNode = None
        self.clickRay = None
        self.buttonThrower.removeNode()
        self.buttonThrower = None
        self.inputDevice = None
        self.mouseWatcherNp.removeNode()
        self.mouseWatcherNp = None
        self.mouseWatcher = None
        self.mouseAndKeyboard.removeNode()
        self.mouseAndKeyboard = None
        self.win.removeAllDisplayRegions()
        self.displayRegion = None
        base.graphicsEngine.removeWindow(self.win)
        self.win = None

        self.camera2d.removeNode()
        self.camera2d = None
        self.cam2d = None

        self.render2d.removeNode()
        self.render2d = None

        self.a2dBackground = None
        self.a2dTop = None
        self.a2dBottom = None
        self.a2dLeft = None
        self.a2dRight = None
        self.aspect2d = None
        self.a2dTopCenter = None
        self.a2dTopCenterNs = None
        self.a2dBottomCenter = None
        self.a2dBottomCenterNs = None
        self.a2dLeftCenter = None
        self.a2dLeftCenterNs = None
        self.a2dRightCenter = None
        self.a2dRightCenterNs = None

        self.a2dTopLeft = None
        self.a2dTopLeftNs = None
        self.a2dTopRight = None
        self.a2dTopRightNs = None
        self.a2dBottomLeft = None
        self.a2dBottomLeftNs = None
        self.a2dBottomRight = None
        self.a2dBottomRightNs = None
        self.__oldAspectRatio = None

        self.qtWindow.deleteLater()
        self.qtWidget.deleteLater()
        self.qtWindow = None
        self.qtWidget = None

        self.deleteLater()

    def keyPressEvent(self, event):
        button = LEUtils.keyboardButtonFromQtKey(event.key())
        if button:
            self.inputDevice.buttonDown(button)

    def keyReleaseEvent(self, event):
        button = LEUtils.keyboardButtonFromQtKey(event.key())
        if button:
            self.inputDevice.buttonUp(button)

    def enterEvent(self, event):
        # Give ourselves focus.
        self.setFocus()
        QtWidgets.QWidget.enterEvent(self, event)

    def mouseMoveEvent(self, event):
        self.inputDevice.setPointerInWindow(event.pos().x(), event.pos().y())
        QtWidgets.QWidget.mouseMoveEvent(self, event)

    def leaveEvent(self, event):
        self.clearFocus()
        self.inputDevice.setPointerOutOfWindow()
        self.inputDevice.focusLost()
        QtWidgets.QWidget.leaveEvent(self, event)

    def mousePressEvent(self, event):
        btn = event.button()
        if btn == QtCore.Qt.LeftButton:
            self.inputDevice.buttonDown(MouseButton.one())
        elif btn == QtCore.Qt.MiddleButton:
            self.inputDevice.buttonDown(MouseButton.two())
        elif btn == QtCore.Qt.RightButton:
            self.inputDevice.buttonDown(MouseButton.three())
        QtWidgets.QWidget.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        btn = event.button()
        if btn == QtCore.Qt.LeftButton:
            self.inputDevice.buttonUp(MouseButton.one())
        elif btn == QtCore.Qt.MiddleButton:
            self.inputDevice.buttonUp(MouseButton.two())
        elif btn == QtCore.Qt.RightButton:
            self.inputDevice.buttonUp(MouseButton.three())
        QtWidgets.QWidget.mouseReleaseEvent(self, event)

    def wheelEvent(self, event):
        ang = event.angleDelta().y()
        if ang > 0:
            self.inputDevice.buttonDown(MouseButton.wheelUp())
            self.inputDevice.buttonUp(MouseButton.wheelUp())
        else:
            self.inputDevice.buttonDown(MouseButton.wheelDown())
            self.inputDevice.buttonUp(MouseButton.wheelDown())
        QtWidgets.QWidget.wheelEvent(self, event)

    def getAspectRatio(self):
        return self.win.getXSize() / self.win.getYSize()

    def setupRender2d(self):
        ## This is the root of the 2-D scene graph.
        self.render2d = NodePath("viewport-render2d")

        # Set up some overrides to turn off certain properties which
        # we probably won't need for 2-d objects.

        # It's probably important to turn off the depth test, since
        # many 2-d objects will be drawn over each other without
        # regard to depth position.

        # We used to avoid clearing the depth buffer before drawing
        # render2d, but nowadays we clear it anyway, since we
        # occasionally want to put 3-d geometry under render2d, and
        # it's simplest (and seems to be easier on graphics drivers)
        # if the 2-d scene has been cleared first.

        self.render2d.setDepthTest(0)
        self.render2d.setDepthWrite(0)
        self.render2d.setMaterialOff(1)
        self.render2d.setTwoSided(1)

        self.aspect2d = self.render2d.attachNewNode("viewport-aspect2d")

        aspectRatio = self.getAspectRatio()
        self.aspect2d.setScale(1.0 / aspectRatio, 1.0, 1.0)

        self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")

        ## The Z position of the top border of the aspect2d screen.
        self.a2dTop = 1.0
        ## The Z position of the bottom border of the aspect2d screen.
        self.a2dBottom = -1.0
        ## The X position of the left border of the aspect2d screen.
        self.a2dLeft = -aspectRatio
        ## The X position of the right border of the aspect2d screen.
        self.a2dRight = aspectRatio

        self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
        self.a2dTopCenterNs = self.aspect2d.attachNewNode("a2dTopCenterNS")
        self.a2dBottomCenter = self.aspect2d.attachNewNode("a2dBottomCenter")
        self.a2dBottomCenterNs = self.aspect2d.attachNewNode(
            "a2dBottomCenterNS")
        self.a2dLeftCenter = self.aspect2d.attachNewNode("a2dLeftCenter")
        self.a2dLeftCenterNs = self.aspect2d.attachNewNode("a2dLeftCenterNS")
        self.a2dRightCenter = self.aspect2d.attachNewNode("a2dRightCenter")
        self.a2dRightCenterNs = self.aspect2d.attachNewNode("a2dRightCenterNS")

        self.a2dTopLeft = self.aspect2d.attachNewNode("a2dTopLeft")
        self.a2dTopLeftNs = self.aspect2d.attachNewNode("a2dTopLeftNS")
        self.a2dTopRight = self.aspect2d.attachNewNode("a2dTopRight")
        self.a2dTopRightNs = self.aspect2d.attachNewNode("a2dTopRightNS")
        self.a2dBottomLeft = self.aspect2d.attachNewNode("a2dBottomLeft")
        self.a2dBottomLeftNs = self.aspect2d.attachNewNode("a2dBottomLeftNS")
        self.a2dBottomRight = self.aspect2d.attachNewNode("a2dBottomRight")
        self.a2dBottomRightNs = self.aspect2d.attachNewNode("a2dBottomRightNS")

        # Put the nodes in their places
        self.a2dTopCenter.setPos(0, 0, self.a2dTop)
        self.a2dTopCenterNs.setPos(0, 0, self.a2dTop)
        self.a2dBottomCenter.setPos(0, 0, self.a2dBottom)
        self.a2dBottomCenterNs.setPos(0, 0, self.a2dBottom)
        self.a2dLeftCenter.setPos(self.a2dLeft, 0, 0)
        self.a2dLeftCenterNs.setPos(self.a2dLeft, 0, 0)
        self.a2dRightCenter.setPos(self.a2dRight, 0, 0)
        self.a2dRightCenterNs.setPos(self.a2dRight, 0, 0)

        self.a2dTopLeft.setPos(self.a2dLeft, 0, self.a2dTop)
        self.a2dTopLeftNs.setPos(self.a2dLeft, 0, self.a2dTop)
        self.a2dTopRight.setPos(self.a2dRight, 0, self.a2dTop)
        self.a2dTopRightNs.setPos(self.a2dRight, 0, self.a2dTop)
        self.a2dBottomLeft.setPos(self.a2dLeft, 0, self.a2dBottom)
        self.a2dBottomLeftNs.setPos(self.a2dLeft, 0, self.a2dBottom)
        self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
        self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)

    def setupCamera2d(self,
                      sort=10,
                      displayRegion=(0, 1, 0, 1),
                      coords=(-1, 1, -1, 1)):
        dr = self.win.makeMonoDisplayRegion(*displayRegion)
        dr.setSort(10)

        # Enable clearing of the depth buffer on this new display
        # region (see the comment in setupRender2d, above).
        dr.setClearDepthActive(1)

        # Make any texture reloads on the gui come up immediately.
        dr.setIncompleteRender(False)

        left, right, bottom, top = coords

        # Now make a new Camera node.
        cam2dNode = Camera('cam2d')

        lens = OrthographicLens()
        lens.setFilmSize(right - left, top - bottom)
        lens.setFilmOffset((right + left) * 0.5, (top + bottom) * 0.5)
        lens.setNearFar(-1000, 1000)
        cam2dNode.setLens(lens)

        # self.camera2d is the analog of self.camera, although it's
        # not as clear how useful it is.
        self.camera2d = self.render2d.attachNewNode('camera2d')

        camera2d = self.camera2d.attachNewNode(cam2dNode)
        dr.setCamera(camera2d)

        self.cam2d = camera2d

        return camera2d

    def mouse1Up(self):
        pass

    def mouse1Down(self):
        pass

    def mouse2Up(self):
        pass

    def mouse2Down(self):
        pass

    def mouse3Up(self):
        pass

    def mouse3Down(self):
        pass

    def mouseEnter(self):
        self.updateView()

    def mouseExit(self):
        pass

    def mouseMove(self):
        pass

    def wheelUp(self):
        pass

    def wheelDown(self):
        pass

    def shouldRender(self):
        if not self.enabled:
            return False

        now = globalClock.getRealTime()
        if self.lastRenderTime != 0:
            elapsed = now - self.lastRenderTime
            if elapsed <= 0:
                return False

            frameRate = 1 / elapsed
            if frameRate > 100.0:
                # Never render faster than 100Hz
                return False

        return self.needsUpdate

    def renderView(self):
        self.lastRenderTime = globalClock.getRealTime()
        self.needsUpdate = False
        #self.win.setActive(1)
        base.requestRender()

    def tick(self):
        if self.shouldRender():
            self.renderView()
        else:
            pass
            #self.win.setActive(0)

    def getViewportName(self):
        return self.spec.name

    def getViewportCenterPixels(self):
        return LPoint2i(self.win.getXSize() // 2, self.win.getYSize() // 2)

    def centerCursor(self, cursor):
        center = self.getViewportCenterPixels()
        cursor.setPos(
            self.mapToGlobal(QtCore.QPoint(self.width() / 2,
                                           self.height() / 2)))
        self.inputDevice.setPointerInWindow(center.x, center.y)

    def viewportToWorld(self, viewport, vec=False):
        front = Point3()
        back = Point3()
        self.lens.extrude(viewport, front, back)
        world = (front + back) / 2

        worldMat = self.cam.getMat(render)
        if vec:
            world = worldMat.xformVec(world)
        else:
            world = worldMat.xformPoint(world)

        return world

    def worldToViewport(self, world):
        # move into local camera space
        invMat = Mat4(self.cam.getMat(render))
        invMat.invertInPlace()

        local = invMat.xformPoint(world)

        point = Point2()
        self.lens.project(local, point)

        return point

    def zeroUnusedCoordinate(self, vec):
        pass

    def click(self, mask, queue=None, traverser=None, root=None):
        if not self.mouseWatcher.hasMouse():
            return None

        if not queue:
            queue = self.clickQueue

        self.clickRay.setFromLens(self.camNode, self.mouseWatcher.getMouse())
        self.clickNode.setFromCollideMask(mask)
        self.clickNode.setIntoCollideMask(BitMask32.allOff())
        self.clickNp.reparentTo(self.cam)
        queue.clearEntries()
        if not traverser:
            base.clickTraverse(self.clickNp, queue)
        else:
            if not root:
                root = self.doc.render
            traverser.addCollider(self.clickNp, queue)
            traverser.traverse(root)
            traverser.removeCollider(self.clickNp)
        queue.sortEntries()
        self.clickNp.reparentTo(NodePath())

        return queue.getEntries()

    def fixRatio(self, size=None):
        if not self.lens:
            return

        if size is None:
            aspectRatio = self.win.getXSize() / self.win.getYSize()
        else:
            if size.y > 0:
                aspectRatio = size.x / size.y
            else:
                aspectRatio = 1.0

        if self.is2D():
            zoomFactor = (1.0 / self.zoom) * 100.0
            self.lens.setFilmSize(zoomFactor * aspectRatio, zoomFactor)
        else:
            self.lens.setAspectRatio(aspectRatio)

        if aspectRatio != self.__oldAspectRatio:
            self.__oldAspectRatio = aspectRatio
            # Fix up some anything that depends on the aspectRatio
            if aspectRatio < 1:
                # If the window is TALL, lets expand the top and bottom
                self.aspect2d.setScale(1.0, aspectRatio, aspectRatio)
                self.a2dTop = 1.0 / aspectRatio
                self.a2dBottom = -1.0 / aspectRatio
                self.a2dLeft = -1
                self.a2dRight = 1.0
            else:
                # If the window is WIDE, lets expand the left and right
                self.aspect2d.setScale(1.0 / aspectRatio, 1.0, 1.0)
                self.a2dTop = 1.0
                self.a2dBottom = -1.0
                self.a2dLeft = -aspectRatio
                self.a2dRight = aspectRatio

            # Reposition the aspect2d marker nodes
            self.a2dTopCenter.setPos(0, 0, self.a2dTop)
            self.a2dTopCenterNs.setPos(0, 0, self.a2dTop)
            self.a2dBottomCenter.setPos(0, 0, self.a2dBottom)
            self.a2dBottomCenterNs.setPos(0, 0, self.a2dBottom)
            self.a2dLeftCenter.setPos(self.a2dLeft, 0, 0)
            self.a2dLeftCenterNs.setPos(self.a2dLeft, 0, 0)
            self.a2dRightCenter.setPos(self.a2dRight, 0, 0)
            self.a2dRightCenterNs.setPos(self.a2dRight, 0, 0)

            self.a2dTopLeft.setPos(self.a2dLeft, 0, self.a2dTop)
            self.a2dTopLeftNs.setPos(self.a2dLeft, 0, self.a2dTop)
            self.a2dTopRight.setPos(self.a2dRight, 0, self.a2dTop)
            self.a2dTopRightNs.setPos(self.a2dRight, 0, self.a2dTop)
            self.a2dBottomLeft.setPos(self.a2dLeft, 0, self.a2dBottom)
            self.a2dBottomLeftNs.setPos(self.a2dLeft, 0, self.a2dBottom)
            self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
            self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)

    def resizeEvent(self, event):
        if not self.win:
            return

        newsize = LVector2i(event.size().width(), event.size().height())
        self.qtWidget.resize(newsize[0], newsize[1])
        self.qtWidget.move(0, 0)

        #props = WindowProperties()
        #props.setSize(newsize)
        #props.setOrigin(0, 0)
        #self.win.requestProperties(props)

        self.fixRatio(newsize)

        self.onResize(newsize)

        self.updateView()

    def onResize(self, newsize):
        pass

    def draw(self):
        pass

    def enable(self):
        # Render to the viewport
        self.win.setActive(True)
        self.enabled = True

    def disable(self):
        # Don't render to the viewport
        self.win.setActive(False)
        self.enabled = False
예제 #52
0
class Player(DirectObject):
    def __init__(self, _main):
        self.main = _main

        # Stats
        self.moveSpeed = 8
        self.inventory = []
        self.maxCarryWeight = 20.0 #kg ?
        self.currentInventoryWeight = 0.0

        # Inventory GUI
        self.inventoryGui = Inventory()
        self.inventoryGui.hide()
        self.inventoryActive = False
        self.craftInventory = CraftInventory()
        self.craftInventory.hide()

        # enable movements through the level
        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0}
        self.player = NodePath("Player")#loader.loadModel("smiley")
        self.player.setPos(149.032, 329.324, 11.3384)
        self.player.setH(180)
        self.player.reparentTo(render)

        self.accept("w", self.setKey, ["forward",1])
        self.accept("w-up", self.setKey, ["forward",0])
        self.accept("a", self.setKey, ["left",1])
        self.accept("a-up", self.setKey, ["left",0])
        self.accept("s", self.setKey, ["backward",1])
        self.accept("s-up", self.setKey, ["backward",0])
        self.accept("d", self.setKey, ["right",1])
        self.accept("d-up", self.setKey, ["right",0])
        self.accept("mouse1", self.handleLeftMouse)
        self.accept("i", self.toggleInventory)
        self.accept("c", self.toggleCraftInventory)


        # screen sizes
        self.winXhalf = base.win.getXSize() / 2
        self.winYhalf = base.win.getYSize() / 2

        self.mouseSpeedX = 0.1
        self.mouseSpeedY = 0.1

        camera.setH(180)
        camera.reparentTo(self.player)
        camera.setZ(self.player, 2)
        base.camLens.setFov(75)
        base.camLens.setNear(0.8)

        # Mouse controls
        self.mouseNode = CollisionNode('mouseRay')
        self.mouseNodeNP = camera.attachNewNode(self.mouseNode)
        self.mouseNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.mouseRay = CollisionRay()
        self.mouseNode.addSolid(self.mouseRay)
        self.mouseRayHandler = CollisionHandlerQueue()

        # Collision Traverser
        self.traverser = CollisionTraverser("Player Traverser")
        base.cTrav = self.traverser
        self.traverser.addCollider(self.mouseNodeNP, self.mouseRayHandler)

    def run(self):
        taskMgr.add(self.move, "moveTask", priority=-4)

    def pause(self):
        taskMgr.remove("moveTask")

    def setKey(self, key, value):
        self.keyMap[key] = value

    def move(self, task):
        if not base.mouseWatcherNode.hasMouse(): return task.cont

        pointer = base.win.getPointer(0)
        mouseX = pointer.getX()
        mouseY = pointer.getY()

        if base.win.movePointer(0, self.winXhalf, self.winYhalf):
            # calculate the looking up/down of the camera.
            # NOTE: for first person shooter, the camera here can be replaced
            # with a controlable joint of the player model
            p = camera.getP() - (mouseY - self.winYhalf) * self.mouseSpeedY
            if p <-80:
                p = -80
            elif p > 90:
                p = 90
            camera.setP(p)

            # rotate the player's heading according to the mouse x-axis movement
            h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX
            if h <-360:
                h = 360
            elif h > 360:
                h = -360
            self.player.setH(h)

        # basic movement of the player
        if self.keyMap["left"] != 0:
            self.player.setX(self.player, self.moveSpeed * globalClock.getDt())
        if self.keyMap["right"] != 0:
            self.player.setX(self.player, -self.moveSpeed * globalClock.getDt())
        if self.keyMap["forward"] != 0:
            self.player.setY(self.player, -self.moveSpeed * globalClock.getDt())
        if self.keyMap["backward"] != 0:
            self.player.setY(self.player, self.moveSpeed * globalClock.getDt())


        # keep the player on the ground
        elevation = self.main.t.terrain.getElevation(self.player.getX(), self.player.getY())
        self.player.setZ(elevation*self.main.t.zScale)

        return task.cont

    def toggleInventory(self):
        if self.inventoryActive:
            self.inventoryGui.hide()
            self.inventoryActive = False
            self.run()
        else:
            self.inventoryGui.show()
            self.inventoryActive = True
            self.pause()

    def toggleCraftInventory(self):
        if self.inventoryActive:
            self.craftInventory.hide()
            self.inventoryActive = False
            self.run()
        else:
            self.craftInventory.updateList(self.inventory)
            self.craftInventory.show()
            self.inventoryActive = True
            self.pause()

    def handleLeftMouse(self):
        # Do the mining
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            self.mouseRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())

            self.traverser.traverse(render)
            # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue.
            if self.mouseRayHandler.getNumEntries() > 0:
            # This is so we get the closest object.
                self.mouseRayHandler.sortEntries()
                pickedObj = self.mouseRayHandler.getEntry(0).getIntoNodePath()

                # Range check
                if (self.player.getPos() - pickedObj.getPos(render)).length() <= 3.0:
                    self.mine(pickedObj)
                else:
                    print "You are to far, move closer!"


    def mine(self, _nodeNP):
        self.nodeNP = _nodeNP

        # get the object class
        for node in self.main.nodeGen.currentNodes:
            if self.main.nodeGen.currentNodes[node] in self.inventory:
                print "new Loot:", self.main.nodeGen.currentNodes[node].giveLoot()
                self.inventory.append(self.main.nodeGen.currentNodes[node])
                if self.main.nodeGen.currentNodes[node].lootLeft == 0:
                    self.main.nodeGen.currentNodes[node].removeModel()
                    break
                break


            # if mining node
            else:

                if self.main.nodeGen.currentNodes[node].model and self.main.nodeGen.currentNodes[node].model.getPos() == self.nodeNP.getPos(render):
                    #self.main.nodeGen.currentNodes[node].removeModel()
                    self.inventory.append(self.main.nodeGen.currentNodes[node])
                    self.currentInventoryWeight += self.main.nodeGen.currentNodes[node].weight
                    self.inventoryGui.updateList(self.inventory)
                    print "You received:", self.main.nodeGen.currentNodes[node].giveLoot(), self.main.nodeGen.currentNodes[node].giveType(), "Ores"
                    print "Inventory:", self.inventory
                    print "Current Weight:", self.currentInventoryWeight
                    break

        print self.player.getPos()
예제 #53
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))
예제 #54
0
파일: picker.py 프로젝트: jhamrick/scenesim
class Picker(Viewer):
    """ View and click objects in a scene."""

    def __init__(self):
        # Parent init.
        super(Picker, self).__init__()
        self.disableMouse()
        # Picker stuff.
        self.contact_margin = Vec3(0.01, 0.01, 0.01)
        self.parser = None
        self.marked = None
        self.attached_pairs = set()
        self.contacts = None
        self.contact_points = None
        self.contact_bottoms = None
        self.compound_components = []
        self.compound_objects = []
        self.joints = JointManager()
        self.wire_attrib = RenderModeAttrib.make(
            RenderModeAttrib.MWireframe, 4.)
        self.attachment_colors = (Vec4(0.1, 0.1, 1., 1.),
                                  Vec4(0.1, 0.8, 0.1, 1.),
                                  Vec4(1., 0.1, 1., 1.),
                                  Vec4(1., 0.5, 0.1, 1.),
                                  Vec4(1., 1., 1., 1.))
        self.max_attach = 999
        self.permanent_events += ["mouse1"]
        # Make cursor dot.
        self.cursor = self._build_cursor("cross")
        s = 0.08
        self.cursor.setScale(s, s, s)
        self.cursor.setColor(1, 1, 1, 1)
        self.cursor.reparentTo(self.aspect2d)
        self.taskMgr.add(self.draw_cursor2d, "draw_cursor2d")
        self.permanent_tasks.append("draw_cursor2d")

    def init_ssos(self, *args, **kwargs):
        super(Picker, self).init_ssos(*args, **kwargs)

    def init_physics(self, *args, **kwargs):
        super(Picker, self).init_physics(*args, **kwargs)
        self.joints.bbase = self.bbase

    def init_picker(self):
        # Collision traverser
        self.traverser = CollisionTraverser("traverser")
        # Collision handler
        self.handler = CollisionHandlerQueue()
        # Initialize and set up picker ray node and NodePath
        self.picker = CollisionNode("mouse_ray")
        self.pickerNP = self.camera.attachNewNode(self.picker)
        self.picker.setFromCollideMask(GeomNode.getDefaultCollideMask())
        self.picker_ray = CollisionRay()
        self.picker.addSolid(self.picker_ray)
        self.traverser.addCollider(self.pickerNP, self.handler)
        mark_color = (1, 1, 1, 0.3)
        self.base_mark = self.create_mark(color=mark_color)
        connector_color = (1, 1, 1, 1)
        self.base_connector = self.create_connector(color=connector_color)

    def _build_cursor(self, shape="sphere"):
        if shape == "sphere":
            cursor = self._load("sphere.bam")
        elif shape == "cross":
            cursor = LineNodePath()
            lines = [[Point3(-0.5, 0, 0), Point3(0.5, 0, 0)],
                     [Point3(0, 0, -0.5), Point3(0, 0, 0.5)]]
            cursor.drawLines(lines)
            cursor.setThickness(1)
            cursor.create()
            # cursor = NodePath("cross")
            # S = {"cylinderX.bam": ((0., 0., 0.), (1., 0.1, 0.1)),
            #      "cylinderY.bam": ((0., 0., 0.), (0.1, 1., 0.1)),
            #      "cylinderZ.bam": ((0., 0., 0.), (0.1, 0.1, 1.))}
            # for k, v in S.iteritems():
            #     m = self._load(k)
            #     m.setName(k)
            #     m.setPos(*v[0])
            #     m.setScale(*v[1])
            #     m.reparentTo(cursor)
        #BP()
        return cursor

    def create_mark(self, color):
        """ Makes a graphical mark object."""
        # Make a graphical box.
        props = dict(name="mark", color=color, model="box-round.egg")
        obj = GSO(props=props)
        return obj

    def create_connector(self, color):
        """ Makes a graphical connector object."""
        # Make a graphical box.
        props = dict(name="connector", color=color, model="connector.egg")
        obj = GSO(props=props)
        return obj

    def start_picker(self, pickables):
        # Set pickable objs.
        for i, obj in enumerate(pickables):
            obj.setTag("pickable", str(i))
        # Add mouse events.
        self.accept("mouse1", self.clicked, extraArgs=[1])
        # Start contact detector.
        detector = ContactDetector(self.bbase.world, self.scene,
                                   margin=self.contact_margin)
        self.contacts = detector.contacts
        self.contact_bodies = detector.bodies
        self.contact_points = detector.points
        parser = Parser(self.contacts, self.contact_bodies)
        self.contact_bottoms = parser.bottom_bodies
        self.connectors = {}

    def stop_picker(self):
        self.removeTask("mouse1")

    def goto_sso(self, *args, **kwargs):
        self.clear_attachments()
        self.stop_picker()
        super(Picker, self).goto_sso(*args, **kwargs)
        self.remove_physics()
        # Start picker.
        pickables = self.sso.descendants(type_=PSO)
        self.start_picker(pickables)
        self.attach_physics()

    def get_picked_obj(self):
        mpos = self.mouseWatcherNode.getMouse()
        self.picker_ray.setFromLens(self.cam.node(), mpos.getX(), mpos.getY())
        self.traverser.traverse(self.render)
        if self.handler.getNumEntries() > 0:
            # This is so we get the closest object
            self.handler.sortEntries()
            entries = self.handler.getEntries()
            for entry in entries:
                picked_obj = entry.getIntoNodePath().findNetTag("pickable")
                if not picked_obj.isEmpty():
                    break
            if picked_obj.isEmpty():
                picked_obj = None
        else:
            picked_obj = None
        return picked_obj

    def clicked(self, button):
        """ Mouse click handler."""
        if self.mouseWatcherNode.hasMouse():
            # Get picked object
            picked_obj = self.get_picked_obj()
            if picked_obj is not None:
                if self.marked is None:
                    # New mark activated.
                    self.marked = picked_obj
                    self.show_marked(picked_obj, True)
                    event = "mark"
                elif picked_obj == self.marked:
                    # Existing mark deactivated.
                    self.show_marked(picked_obj, False)
                    self.marked = None
                    event = "unmark"
                else:
                    # New attachment or detachment.
                    pair = tuple(sorted((self.marked, picked_obj)))
                    ij = tuple(sorted((self.contact_bodies.index(pair[0]),
                                       self.contact_bodies.index(pair[1]))))
                    if ij in self.contacts:
                        f_add = (ij, pair) not in self.attached_pairs
                        if (not f_add or len(self.attached_pairs) <
                            self.max_attach):
                            self.store_attachment(ij, pair, f_add)
                            self.show_marked(self.marked, False)
                            self.marked = None
                            event = "attach" if f_add else "detach"
                        else:
                            print("Max attachments already reached.")
                            event = "max-attach"
                    else:
                        event = "non-contact"
            else:
                event = "non-pick"
            return picked_obj, event

    def store_attachment(self, ij, pair, f_add):
        """ Stores the attached objects, and draws them."""
        if f_add:
            self.attached_pairs.add((ij, pair))
            self.show_attachment(ij, True)
            self.attach_pair(pair, True)
        else:
            try:
                self.attached_pairs.remove((ij, pair))
            except KeyError:
                pass
            else:
                self.attach_pair(pair, False)
                self.show_attachment(ij, False)

    def clear_attachments(self):
        """ Clear all attachments."""
        if self.marked:
            self.show_marked(self.marked, False)
            self.marked = None
            self.mark = None
        for ij, pair in self.attached_pairs:
            self.attach_pair(pair, False)
            self.show_attachment(ij, False)
        self.attached_pairs = set()
        #
        self.reset_compounds()
        self.contacts = None
        self.contact_bodies = None
        self.contact_points = None
        self.contact_bottoms = None

    def _make_mark(self, node, extent, name):
        """ Makes a mark GSO."""
        mark = self.base_mark.copy()
        mat = node.getMat(self.scene)
        mark.apply_prop(dict(name=name), other=self.scene)
        mark.setMat(self.scene, mat)
        mark.setScale(self.scene, mark.getScale(self.scene) + extent)
        mark.wrtReparentTo(node)
        return mark

    def show_marked(self, node, f_on):
        """ Turns on/off marked graphic."""
        if f_on:
            extent = Vec3(0.15, 0.15, 0.15)
            name = "mark"
            self.mark = self._make_mark(node, extent, name)
            self.mark.init_tree(tags=("model",))
            # Exclude object from casting shadows
            self.mark.hide(self.shadow_mask)
            self.mark.setTransparency(TransparencyAttrib.MAlpha)
            self.mark.setDepthWrite(False)
            self.mark.setBin("fixed", 0, priority=5)
        else:
            self.mark.removeNode()

    def _make_connector(self, parent, points, extent, name):
        """ Makes connector object."""
        connector = self.base_connector.copy()
        scale = Vec3(*(np.ptp(points, axis=0)))
        scale_extended = scale + extent
        pos = Point3(*(np.min(points, axis=0) + scale / 2.))
        connector.apply_prop(dict(name=name, scale=scale_extended, pos=pos),
                             other=self.scene)
        connector.wrtReparentTo(parent)
        return connector

    def show_attachment(self, ij, f_on):
        """ Turns on/off attachment graphic."""
        if f_on:
            parent = self.contact_bottoms[ij]
            points = self.contact_points[ij]
            extent = Vec3(0.15, 0.15, 0.15)
            name = "connector_%d-%d" % ij
            self.connectors[ij] = self._make_connector(parent, points,
                                                       extent, name)
            self.connectors[ij].init_tree(tags=("model",))
        else:
            self.connectors.pop(ij).removeNode()

    # def attach_pair(self, pair, f_on):
    #     """ Adds/removes physical attachment between a pair of nodes."""
    #     key = tuple(sorted(p.node() for p in pair))
    #     # key = frozenset(pair)
    #     if f_on:
    #         # Create the joint and add it.
    #         self.joints[key] = self.joints.make_fixed(*pair)
    #     else:
    #         # Remove it.
    #         del self.joints[key]

    def attach_physics(self):
        # Attach `self.scene` to the physics world.
        try:
            exclude = zip(*self.compound_components)[0]
        except IndexError:
            exclude = []
        bnodes = [bnode for bnode in self.scene.descendants(type_=PSO)
                  if bnode not in exclude]
        for bnode in bnodes:
            bnode.init_resources(tags=("shape",))
            bnode.setCollideMask(BitMask32.allOn())
            bnode.node().setDeactivationEnabled(False)
        self.bbase.attach(bnodes)

    def reset_compounds(self):
        for n, p in self.compound_components:
            n.wrtReparentTo(p)
        self.compound_components = []
        for cnode in self.compound_objects:
            cnode.destroy_resources()
            cnode.removeNode()
        self.compound_objects = []

    def make_attachment_graph(self):
        if not self.contact_bodies:
            return None
        n = len(self.contact_bodies)
        mtx = np.zeros((n, n), dtype="i")
        for (i, j), _ in self.attached_pairs:
            # i = self.contact_bodies.index(pair[0])
            # j = self.contact_bodies.index(pair[1])
            mtx[i, j] = 1
            # mtx[j, i] = 1
        graph = nx.from_numpy_matrix(mtx)
        return graph

    def attach_pair(self, pair, f_on):
        """ Adds/removes physical attachment between a pair of nodes."""
        # Get the connected subgroups.
        graph = self.make_attachment_graph()
        sgs = [sg for sg in nx.connected_components(graph) if len(sg) > 1]
        self.reset_compounds()
        # Iterate over subgroups, creating compound shapes.
        for sg in sgs:
            nodes = [self.contact_bodies[i] for i in sg]
            parents = [c.getParent() for c in nodes]
            self.compound_components.extend(zip(nodes, parents))
            cname = "+".join([str(i) for i in sorted(sg)])
            cnode = CPSO(cname)
            cnode.reparentTo(self.scene)
            cnode.add(nodes)
            cnode.init_tree(tags=("shape",))
            cnode.destroy_component_shapes()
            self.compound_objects.append(cnode)
예제 #55
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)
예제 #56
0
class CameraShyFirstPerson(FirstPerson):
    toonInFocusColor = VBase4(0.25, 1.0, 0.25, 1.0)
    toonOutOfFocusColor = VBase4(1.0, 1.0, 1.0, 1.0)
    fullyChargedState = 5

    def __init__(self, mg):
        self.mg = mg
        self.cameraFocus = None
        self.batteryFrame = None
        self.batteryBg = None
        self.batteryBar = None
        self.rechargeSound = None
        self.fullyChargedSound = None
        self.hasToonInFocus = False
        self.toonToTakePicOf = None
        self.cameraRechargeState = None
        self.cameraRechargingLabel = None
        self.cameraFlashSeq = None
        self.camFSM = ClassicFSM('CameraFSM', [State('off', self.enterOff, self.exitOff), State('ready', self.enterCameraReady, self.exitCameraReady), State('recharge', self.enterCameraRecharge, self.exitCameraRecharge)], 'off', 'off')
        self.camFSM.enterInitialState()
        FirstPerson.__init__(self)
        return

    def movementTask(self, task):
        if not inputState.isSet('jump') and not base.localAvatar.walkControls.isAirborne and inputState.isSet('forward') or inputState.isSet('reverse') or inputState.isSet('slideLeft') or inputState.isSet('slideRight'):
            if base.localAvatar.getAnimState() != 'run':
                base.localAvatar.setAnimState('run')
                base.localAvatar.playMovementSfx('run')
                self.mg.sendUpdate('runningAvatar', [base.localAvatar.doId])
        elif inputState.isSet('jump') or base.localAvatar.walkControls.isAirborne:
            if base.localAvatar.getAnimState() != 'jump':
                base.localAvatar.setAnimState('jump')
                base.localAvatar.playMovementSfx(None)
                self.mg.sendUpdate('jumpingAvatar', [base.localAvatar.doId])
        elif base.localAvatar.getAnimState() != 'neutral':
            base.localAvatar.setAnimState('neutral')
            base.localAvatar.playMovementSfx(None)
            self.mg.sendUpdate('standingAvatar', [base.localAvatar.doId])
        return task.cont

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterCameraReady(self):
        self.acceptOnce('mouse1', self.__mouse1Pressed)

    def stopCameraFlash(self):
        if self.cameraFlashSeq:
            self.cameraFlashSeq.finish()
            self.cameraFlashSeq = None
        return

    def __mouse1Pressed(self):
        self.cameraFlashSeq = Sequence(Func(base.transitions.setFadeColor, 1, 1, 1), Func(base.transitions.fadeOut, 0.1), Wait(0.1), Func(base.transitions.fadeIn, 0.1), Wait(0.1), Func(base.transitions.setFadeColor, 0, 0, 0))
        self.cameraFlashSeq.start()
        self.mg.sendUpdate('remoteAvatarTakePicture', [base.localAvatar.doId])
        self.mg.myRemoteAvatar.takePicture()
        if self.hasToonInFocus and self.toonToTakePicOf:
            self.mg.sendUpdate('tookPictureOfToon', [self.toonToTakePicOf.doId])
        self.camFSM.request('recharge')

    def exitCameraReady(self):
        self.ignore('mouse1')

    def enterCameraRecharge(self):
        self.batteryBar.update(0)
        taskMgr.add(self.__rechargeNextState, 'rechargeCamera')

    def __rechargeNextState(self, task):
        if self.cameraRechargeState == None:
            self.cameraRechargeState = -1
        self.cameraRechargeState += 1
        if self.cameraRechargeState > 0:
            base.playSfx(self.rechargeSound)
        self.batteryBar.update(self.cameraRechargeState)
        if self.cameraRechargeState == self.fullyChargedState:
            base.playSfx(self.fullyChargedSound)
            self.camFSM.request('ready')
            return task.done
        else:
            task.delayTime = 1.0
            return task.again

    def exitCameraRecharge(self):
        taskMgr.remove('rechargeCamera')
        self.cameraRechargeState = None
        return

    def __handleRayInto(self, entry):
        intoNP = entry.getIntoNodePath()
        toonNP = intoNP.getParent()
        for key in base.cr.doId2do.keys():
            obj = base.cr.doId2do[key]
            if obj.__class__.__name__ == 'DistributedToon':
                if obj.getKey() == toonNP.getKey():
                    self.__handleToonInFocus(obj)

    def __handleRayOut(self, entry):
        intoNP = entry.getIntoNodePath()
        toonNP = intoNP.getParent()
        for key in base.cr.doId2do.keys():
            obj = base.cr.doId2do[key]
            if obj.__class__.__name__ == 'DistributedToon':
                if obj.getKey() == toonNP.getKey():
                    self.toonToTakePicOf = None
                    self.hasToonInFocus = False
                    if self.cameraFocus.getColorScale() == self.toonInFocusColor:
                        self.cameraFocus.setColorScale(self.toonOutOfFocusColor)

        return

    def __handleToonInFocus(self, toon):
        if not self.hasToonInFocus or self.toonToTakePicOf is not None or self.toonToTakePicOf.doId != toon.doId:
            self.toonToTakePicOf = toon
            self.hasToonInFocus = True
            self.cameraFocus.setColorScale(self.toonInFocusColor)
        return

    def start(self):
        self.fullyChargedSound = base.loadSfx('phase_4/audio/sfx/MG_pairing_match.mp3')
        self.rechargeSound = base.loadSfx('phase_4/audio/sfx/MG_sfx_travel_game_blue_arrow.mp3')
        self.batteryFrame = DirectFrame(parent=base.a2dBottomRight, pos=(-0.2, 0, 0.1), scale=(0.8, 0, 1))
        self.batteryBg = OnscreenImage(image='phase_4/maps/battery_charge_frame.png', parent=self.batteryFrame)
        self.batteryBg.setTransparency(1)
        self.batteryBg.setX(0.03)
        self.batteryBg.setScale(0.17, 0, 0.05)
        self.batteryBar = DirectWaitBar(value=0, range=5, barColor=(1, 1, 1, 1), relief=None, scale=(0.12, 0.0, 0.3), parent=self.batteryFrame)
        self.cameraFocus = loader.loadModel('phase_4/models/minigames/photo_game_viewfinder.bam')
        self.cameraFocus.reparentTo(base.aspect2d)
        self.focusCollHandler = CollisionHandlerEvent()
        self.focusCollHandler.setInPattern('%fn-into')
        self.focusCollHandler.setOutPattern('%fn-out')
        self.focusCollNode = CollisionNode('mouseRay')
        self.focusCollNP = base.camera.attachNewNode(self.focusCollNode)
        self.focusCollNode.setCollideMask(BitMask32(0))
        self.focusCollNode.setFromCollideMask(CIGlobals.WallBitmask)
        self.focusRay = CollisionRay()
        self.focusRay.setFromLens(base.camNode, 0.0, 0.0)
        self.focusCollNode.addSolid(self.focusRay)
        base.cTrav.addCollider(self.focusCollNP, self.focusCollHandler)
        base.localAvatar.walkControls.setWalkSpeed(CIGlobals.ToonForwardSpeed, 0.0, CIGlobals.ToonReverseSpeed, CIGlobals.ToonRotateSpeed)
        FirstPerson.start(self)
        return

    def reallyStart(self):
        self.accept('mouseRay-into', self.__handleRayInto)
        self.accept('mouseRay-out', self.__handleRayOut)
        self.camFSM.request('recharge')
        taskMgr.add(self.movementTask, 'movementTask')
        FirstPerson.reallyStart(self)

    def end(self):
        self.camFSM.request('off')
        taskMgr.remove('movementTask')
        self.ignore('mouseRay-into')
        self.ignore('mouseRay-out')
        FirstPerson.end(self)

    def reallyEnd(self):
        self.batteryBar.destroy()
        self.batteryBar = None
        self.batteryBg.destroy()
        self.batteryBg = None
        self.batteryFrame.destroy()
        self.batteryFrame = None
        self.cameraFocus.removeNode()
        self.cameraFocus = None
        self.focusCollHandler = None
        self.focusCollNode = None
        self.focusCollNP.removeNode()
        self.focusCollNP = None
        self.focusRay = None
        self.hasToonInFocus = None
        self.toonToTakePicOf = None
        self.fullyChargedSound = None
        self.rechargeSound = None
        self.stopCameraFlash()
        FirstPerson.reallyEnd(self)
        base.localAvatar.walkControls.setWalkSpeed(CIGlobals.ToonForwardSpeed, CIGlobals.ToonJumpForce, CIGlobals.ToonReverseSpeed, CIGlobals.ToonRotateSpeed)
        return

    def cleanup(self):
        self.camFSM.requestFinalState()
        self.camFSM = None
        FirstPerson.cleanup(self)
        return