Exemple #1
0
class CamManager(DirectObject.DirectObject):
    """1st or 3d person camera, or disable
    """
    def __init__(self, game):
        self.game = game
        self.char = self.game.char
        self.win = self.game.gui.win
        self.hotkeys = self.game.gui.hotkeys
        self.node = NodePath('char')
        self.Ccentr = NodePath('Ccentr')
        self.Ccentr.reparentTo(self.node)
        self.Ccentr.setZ(1)
        self.third_dist = -6
        self.sleep = 0.001
        self.camera = self.game.gui.camera
        self.char.reparentTo(self.node)
        taskMgr.setupTaskChain('cam_move', numThreads = 1,
                       frameSync = False, threadPriority = TPUrgent, timeslicePriority = False)


    def set_enable(self, value, third = False):
        self.enable = value
        self.third = third

        self.node.reparentTo(self.game.world.root_node)
        self.node.setPos(self.game.world.avatar.getPos())
        if self.enable:
            self.camera.reparentTo(self.Ccentr)
            if self.third:
                self.camera.setPos(0, self.third_dist, 0)
                #self.char.show()
            else:
                self.camera.setPos(0, 0, 0)
                #self.char.hide()
            self.camera.lookAt(self.Ccentr)
            taskMgr.add(self.mouse_update, 'mouse-task')
        else:
            self.camera.reparentTo(self.game.world.root_node)
            self.camera.setPos(self.game.world.root_node, self.game.world.avatar.getPos(self.game.world.root_node))
            self.node.detachNode()

    #@profile_decorator
    def mouse_update(self, task):
        """ this task updates the mouse """
        if not self.enable:
            return task.done

        md = base.win.getPointer(0)
        x = md.getX()
        y = md.getY()
        if self.win.movePointer(0, self.win.getXSize()/2, self.win.getYSize()/2):
            self.node.setH(self.node.getH() -  (x - self.win.getXSize()/2)*0.1)
            self.Ccentr.setP(self.Ccentr.getP() - (y - self.win.getYSize()/2)*0.1)

        time.sleep(self.sleep)
        return task.cont

    def point_dist(self, p1, p2):
        return math.sqrt((p1[0]-p2[0])**2+(p1[1]-p2[1])**2+(p1[2]-p2[2])**2)
Exemple #2
0
class Player:
    def __init__(self, x, y, z, id):
        self.health = 100
        radius = .15
        height = 1
        shape = BulletCylinderShape(radius, height, ZUp)
        self.playerNode = BulletCharacterControllerNode(shape, 0.4, str(id))
        self.playerNode.setMaxJumpHeight(2.0)
        self.playerNode.setJumpSpeed(4.0)
        self.playerNP = base.render.attachNewNode(self.playerNode)
        self.playerNP.setPos(x, y, z)
        self.playerModel = Actor('models/soldier.egg', {"idle": "models/soldier_ani_idle.egg",
                                                        "walk": "models/soldier_ani_walk.egg",
                                                        "pistol": "models/soldier_ani_pistol.egg",
                                                        "death": "models/soldier_ani_death.egg",})

        self.playerModel.makeSubpart("legs", ["mixamorig:LeftUpLeg", "mixamorig:RightUpLeg"])
        self.playerModel.makeSubpart("hips", ["mixamorig:Hips"], ["mixamorig:LeftUpLeg", "mixamorig:RightUpLeg", "mixamorig:Spine"])
        self.playerModel.makeSubpart("upperBody", ["mixamorig:Spine"])
        self.playerModel.pose("idle", 0, partName="hips")

        self.playerModel.setH(90)
        self.playerModel.setScale(.06)
        self.playerModel.setZ(-.45)
        self.playerModel.flattenLight()
        # self.playerModel.setLightOff()self.playerSpine
        self.playerModel.reparentTo(self.playerNP)

        self.playerSpine = self.playerModel.controlJoint(None, 'modelRoot', 'mixamorig:Spine')
        self.hand = self.playerModel.exposeJoint(None, 'modelRoot', 'mixamorig:RightHand')
        self.spineExpose = self.playerModel.exposeJoint(None, 'modelRoot', 'mixamorig:Spine')
        self.playerSpine.setH(-7)

        # player weapon
        self.weapon = Ak47(self.hand)

        # player animation
        self.xSpeed = 0
        self.ySpeed = 0
        self.animation = Animation(self)

        self.model = NodePath("MySpineNode")

    def bendBody(self):
        self.model.setPos(self.spineExpose, 0, 0, 0)
        obj = RayCollider.getObjectHit()
        self.model.lookAt(obj)
        self.playerSpine.setP(self.model.getP())
Exemple #3
0
class LocalPlayer(object):
    def __init__(self, mapobj, showbase):
        self.x = None
        self.y = None
        self.win = showbase.win
        self.map = mapobj
        self.mouseWatcherNode = showbase.mouseWatcherNode
        self.accept = showbase.accept
        self.camera = showbase.camera
        self.setup_input()

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(showbase.render)
        self.up = Vec3(0, 1, 0)

        incarn = self.map.world.get_incarn()
        walker_color_dict = {
            "barrel_color": [219.0 / 255, 16.0 / 255, 50.0 / 255],
            "visor_color": [157.0 / 255, 14.0 / 255, 48.0 / 255],
            "body_primary_color": [44.0 / 255, 31.0 / 255, 54.0 / 255],
            "body_secondary_color": [80.0 / 255, 44.0 / 255, 62.0 / 255],
        }
        self.walker = self.map.world.attach(Walker(incarn, colordict=walker_color_dict, player=True))
        taskMgr.add(self.move, "move")

    def setup_input(self):
        self.key_map = {
            "cam_forward": 0,
            "cam_left": 0,
            "cam_backward": 0,
            "cam_right": 0,
            "left": 0,
            "right": 0,
            "forward": 0,
            "backward": 0,
            "rotateLeft": 0,
            "rotateRight": 0,
            "walkForward": 0,
            "crouch": 0,
            "fire": 0,
            "missile": 0,
            "grenade_fire": 0,
            "grenade": 0,
            "print_cam": 0,
        }
        self.accept("escape", sys.exit)
        self.accept("p", self.drop_blocks)

        for key, cmd in KeyMaps.flycam_input_settings:
            self.accept(key, self.set_key, [cmd, 1])
            self.accept(key + "-up", self.set_key, [cmd, 0])

    def move(self, task):
        dt = globalClock.getDt()
        if self.mouseWatcherNode.hasMouse():
            oldx = self.x
            oldy = self.y
            md = self.win.getPointer(0)
            self.x = md.getX()
            self.y = md.getY()
            centerx = self.win.getProperties().getXSize() / 2
            centery = self.win.getProperties().getYSize() / 2
            self.win.movePointer(0, centerx, centery)

            if oldx is not None:
                self.floater.setPos(self.camera, 0, 0, 0)
                self.floater.setHpr(self.camera, 0, 0, 0)
                self.floater.setH(self.floater, (centerx - self.x) * 10 * dt)
                p = self.floater.getP()
                self.floater.setP(self.floater, (centery - self.y) * 10 * dt)
                self.floater.setZ(self.floater, -1)
                angle = self.up.angleDeg(self.floater.getPos() - self.camera.getPos())
                if 10 > angle or angle > 170:
                    self.floater.setPos(self.camera, 0, 0, 0)
                    self.floater.setP(p)
                    self.floater.setZ(self.floater, -1)
                self.camera.lookAt(self.floater.getPos(), self.up)
        else:
            self.x = None
            self.y = None

        if self.key_map["cam_forward"]:
            self.camera.setZ(self.camera, -25 * dt)
        if self.key_map["cam_backward"]:
            self.camera.setZ(self.camera, 25 * dt)
        if self.key_map["cam_left"]:
            self.camera.setX(self.camera, -25 * dt)
        if self.key_map["cam_right"]:
            self.camera.setX(self.camera, 25 * dt)
        if self.key_map["print_cam"]:
            print "CAMERA: Pos - %s, Hpr - %s" % (self.camera.get_pos(), self.camera.get_hpr())
            self.key_map["print_cam"] = 0

        self.walker.handle_command("forward", self.key_map["forward"])
        self.walker.handle_command("left", self.key_map["left"])
        self.walker.handle_command("backward", self.key_map["backward"])
        self.walker.handle_command("right", self.key_map["right"])
        self.walker.handle_command("crouch", self.key_map["crouch"])

        self.walker.handle_command("fire", self.key_map["fire"])
        if self.key_map["fire"]:
            self.key_map["fire"] = 0
        self.walker.handle_command("missile", self.key_map["missile"])
        if self.key_map["missile"]:
            self.key_map["missile"] = 0
        self.walker.handle_command("grenade_fire", self.key_map["grenade_fire"])
        if self.key_map["grenade_fire"]:
            self.key_map["grenade_fire"] = 0
        self.walker.handle_command("grenade", self.key_map["grenade"])
        if self.key_map["grenade"]:
            self.key_map["grenade"] = 0

        return task.cont

    def set_key(self, key, value):
        self.key_map[key] = value

    def drop_blocks(self):
        block = self.map.world.attach(FreeSolid(Block((1, 1, 1), (1, 0, 0, 1), 0.01, (0, 40, 0), (0, 0, 0)), 0.01))
        for i in range(10):
            rand_pos = (random.randint(-25, 25), 40, random.randint(-25, 25))
            block = self.map.world.attach(FreeSolid(Block((1, 1, 1), (1, 0, 0, 1), 0.01, rand_pos, (0, 0, 0)), 0.01))
Exemple #4
0
class Vehicle(ActorNode):
    def __init__(self, parent=None):
        '''
        Create a new Vehicle node. Physics should be initialized before any
        instances of Vehicle are created.

        arguments:
          parent -- A PandaNode for the vehicle to attach to. Default is None,
                    in which case the Vehicle should be added to the scene
                    graph via NodePath.attachNewNode().

        '''
        ActorNode.__init__(self, 'VehiclePhysics')
        base.physicsMgr.attachPhysicalNode(self)

        self.getPhysicsObject().setMass(MASS)
        if parent:
            self.myPath = parent.attachNewNode(self)
        else:
            self.myPath = NodePath(self)

        # Load vehicle model and place in the transparent bin.
        vehicleModel = loader.loadModel(MODEL_PATH)
        hull = vehicleModel.find('**/Hull')
        hull.setBin('transparent', 30)
        pwnsEnclosure = vehicleModel.find('**/Pwns_Enclosure')
        pwnsEnclosure.setBin('transparent', 30)
        self.myPath.setPos(0, 0, -0.0)
        selectable = self.myPath.attachNewNode(SelectableNode('vehicle sel'))
        vehicleModel.reparentTo(selectable)

        # ==== Initialize Physics ==== #
        thrusterForceNode = ForceNode('ThrusterForce')
        self.myPath.attachNewNode(thrusterForceNode)

        self.linearForce = LinearVectorForce(0, 0, 0)
        self.linearForce.setMassDependent(1)
        self.angularForce = AngularVectorForce(0, 0, 0)

        thrusterForceNode.addForce(self.linearForce)
        thrusterForceNode.addForce(self.angularForce)

        self.getPhysical(0).addLinearForce(self.linearForce)
        self.getPhysical(0).addAngularForce(self.angularForce)

        self.previousXY = (self.myPath.getX(), self.myPath.getY())

        self.tm = ThrusterManager()

        # Add self.updatePhysics to the task manager and run this task as
        # frequently as possible.
        self.updatePhysicsTask = taskMgr.add(self.updatePhysics,
                                             'UpdatePhysics')

        # ==== Initialize Cameras ==== #
        lens = PerspectiveLens()
        lens.setNearFar(0.05, 100.0)
        #Use either FocalLength or Fov. Fov ~40 is about what actual forward cameras are
        #lens.setFocalLength(0.8)
        lens.setFov(70, 70)
        camera = Camera("Forward_left", lens).getPath()
        camera.reparentTo(vehicleModel.find('**/Forward_Camera'))
        camera.setX(camera.getX() - 0.1)  # Forward cameras 20cm apart
        camera.setY(
            camera.getY() +
            0.05)  # Move in front of torpedo tubes to avoid abstruction
        camera.setHpr(0, 0, 0)

        camera = Camera("Forward_right", lens).getPath()
        camera.reparentTo(vehicleModel.find('**/Forward_Camera'))
        camera.setX(camera.getX() + 0.1)  # Forward cameras 20cm apart
        camera.setY(
            camera.getY() +
            0.05)  # Move in front of torpedo tubes to avoid abstruction
        camera.setHpr(0, 0, 0)

        lens = PerspectiveLens()
        lens.setNearFar(0.05, 100.0)
        lens.setFocalLength(0.8)
        camera = Camera("Downward", lens).getPath()
        camera.reparentTo(vehicleModel.find('**/Downward_Camera'))
        camera.setHpr(0, -90, 0)

        #Layout link (to access hydrophone information)
        self.layout = None

        #Hydrophone variables
        self.start_time = time()
        self.last_hydro_update = time()

    def setLayout(self, layout):
        #Add a link to the layout to allow for referencing other objects
        #This is necessary for the hydrophone addition
        self.layout = layout

    def getDepth(self):
        ''' Returns the depth of the vehicle, in meters. '''
        return -0.15 - self.myPath.getZ()

    def getHeading(self):
        ''' Returns the heading of the vehicle, in clockwise degrees. '''
        # Panda uses counter-clockwise degrees, with the range (-180, 180].
        heading = self.myPath.getH()
        if heading < 0:
            return -heading
        elif heading > 0:
            return 360 - heading
        else:
            return 0

    def updatePhysics(self, task):
        '''
        Use the motor PWM values calculated by the controller to apply forces
        to the simulated vehicle.

        This runs at every frame, so it needs to complete quickly.

        '''
        outputs = shm.kalman.get()
        self.tm.update(outputs)
        passive_wrench = vehicle.passive_forces(outputs, self.tm)
        passive_forces, passive_torques = passive_wrench[:3], \
                                          passive_wrench[3:]

        # Get motor thrusts
        thrusts = np.array(self.tm.get_thrusts())

        # Add passive forces and torques to that produced by thrusters,
        # converting them to sub space first.
        force = self.tm.total_thrust(thrusts) + \
                self.tm.orientation.conjugate() * passive_forces
        torque = self.tm.total_torque(thrusts) + \
                self.tm.orientation.conjugate() * passive_torques

        # Finally apply forces and torques to the model
        # we also need to account for panda3d's strange coordinate system
        # (x and y are flipped and z points up (instead of down))
        self.linearForce.setVector(force_subspace[1], \
                                   force_subspace[0], \
                                  -force_subspace[2])

        # We're supposed to use axis angle here, but I'm being sneaky
        # and using the torque vector directly, i.e. non normalized axis angle
        # with the hopes that this LRotationf constructor will figure it out
        self.angularForce.setQuat(\
            LRotationf(LVector3f(torque_subspace[1], \
                                 torque_subspace[0], \
                                -torque_subspace[2]), 1))

        # Update shared variables for controller
        outputs.heading = self.getHeading()
        outputs.pitch = self.myPath.getP()
        outputs.roll = self.myPath.getR()

        # This velocity is in world space
        # We need to put it into THRUST CONVENTION SPACE
        # which we assume kalman outputs in...
        velocity = self.getPhysicsObject().getVelocity()

        # Bring the velocity into THRUST CONVENTION SPACE
        # Don't forget to account for panda's coordinate system
        velocity = self.tm.heading_quat.conjugate() * \
                  np.array((velocity.getY(), velocity.getX(), -velocity.getZ()))

        outputs.velx = velocity[0]
        outputs.vely = velocity[1]
        outputs.depth_rate = velocity[2]

        outputs.depth = self.getDepth()
        outputs.north = self.myPath.getY()
        outputs.east = self.myPath.getX()

        dX = self.myPath.getX() - self.previousXY[0]
        dY = self.myPath.getY() - self.previousXY[1]

        # Forward and sway are in THRUST CONVENTION SPACE
        # don't forget to account for panda's coordinate system
        dF, dS, dD = self.tm.heading_quat.conjugate() * np.array((dY, dX, 0.0))

        outputs.forward += dF
        outputs.sway += dS

        # Output some quaternions, accounting for Panda's coordinate system
        outputs.q0, outputs.q2, outputs.q1, outputs.q3 = self.myPath.getQuat()
        outputs.q3 *= -1.0

        shm.kalman.set(outputs)

        svHeadingInt.set(self.getHeading())
        svDepth.set(self.getDepth())
        #XXX: Approximate altitude assuming that the pool is 12 feet deep
        svAltitude.set(3.6 - self.getDepth())
        svDvlDmgNorth.set(self.myPath.getY())
        svDvlDmgEast.set(self.myPath.getX())

        self.previousXY = (self.myPath.getX(), self.myPath.getY())  #update

        self.output_hydro_data()

        return Task.cont

    def output_hydro_data(self):
        #Update simulated hydrophone values
        pingers = []  #Get all pingers from the layout
        for element in self.layout.elements:
            if element.getTypeName() == "Pinger":
                pingers.append(element)

        HYDRO_TICK_PERIOD = 1

        if time() - self.last_hydro_update > HYDRO_TICK_PERIOD:
            dt = time() - self.last_hydro_update
            self.last_hydro_update = time()

            if shm.hydrophones_settings.dsp_mode.get() == 1:  #Search mode
                #Incr search count
                shm.hydrophones_results.search_count.set(
                    shm.hydrophones_results.search_count.get() + 1)

                #Generate proper "hydrophone bins" marks
                sb = 0
                for p in pingers:
                    f = p.pinger_frequency
                    dc = (f - (shm.hydrophones_settings.searchCenter.get() -
                               shm.hydrophones_settings.searchDelta.get())
                          ) / shm.hydrophones_settings.searchStep.get() + 0.5
                    sb |= 1 << int(dc)
                shm.hydrophones_results.search_bins.set(sb)

            else:  #Track Mode
                #Incr ping count
                shm.hydrophones_results.ping_count.set(
                    shm.hydrophones_results.ping_count.get() + 1)

                #Determine which pinger we are actively tracking (within 0.7khz of target)
                targetp = None
                for p in pingers:
                    if abs(shm.hydrophones_settings.trackFrequency.get() -
                           p.pinger_frequency) < 700:
                        targetp = p

                if targetp is not None:
                    shm.hydrophones_results.intensity.set(
                        int(shm.hydrophones_settings.trackMagThresh.get() +
                            1e4 * random()))
                    shm.hydrophones_results.ping_time.set(int(dt * 1000))

                    pp = targetp.path.getPos()

                    vv = vector.Vector(self.myPath.getY(), self.myPath.getX())
                    pv = vector.Vector(pp.getY(), pp.getX())

                    #heading
                    dv = pv - vv
                    ang = vector.GetAuvAngle(dv)
                    hdiff = helpers.heading_diff(self.getHeading(), ang)

                    shm.hydrophones_results.heading.set(hdiff)

                    #elevation
                    dh = self.myPath.getZ() - pp.getZ()
                    dist = vector.Length(dv)
                    elev = math.degrees(math.atan2(dist, dh))
                    elev = min(elev, 90)

                    shm.hydrophones_results.elevation.set(elev)

                    #phase calculations
                    dy = self.myPath.getY() - pp.getY()
                    dx = self.myPath.getX() - pp.getX()
                    yang = math.degrees(math.atan2(dist, dy))
                    xang = math.degrees(math.atan2(dist, dx))

                    shm.hydrophones_results.phaseX.set((90.0 - xang) / 90.0)
                    shm.hydrophones_results.phaseY.set((90.0 - yang) / 90.0)
                    shm.hydrophones_results.phaseZ.set((90.0 - elev) / 90.0)

                else:
                    shm.hydrophones_results.heading.set(0)
                    shm.hydrophones_results.elevation.set(0)
                    shm.hydrophones_results.intensity.set(0)
                    shm.hydrophones_results.ping_time.set(0)

            shm.hydrophones_results.uptime.set(int(time() - self.start_time))

    def __del__(self):
        ''' Remove update tasks from the panda task manager. '''
        taskMgr.remove(self.updatePhysicsTask)
        ActorNode.__del__(self)
Exemple #5
0
class CameraHandler():
    """Hold the different cameras"""

    def __init__(self, _engine, _mode):
        self.mode = _mode
    	self.engine = _engine
        self.camDummy = None
    	player = self.engine.GameObjects["player"].bulletBody
        if self.mode == "TPA":
            self.initTPAMode(player)
        else:
            self.initTPSMode(player)

    def update(self, dt):
        if self.mode == "TPA":
            self.followPlayerTPA(dt)
        else:
            self.followPlayerTPS(dt)

    def stop(self):
        base.camera.reparentTo(render)
        base.camera.setPos(0,0,0)

    #
    # Third person shooter mode
    #
    def initTPSMode(self, player):
        """Sets the cam mode to a third person shooter mode, so the
        cam will be up and behind the player as well as always look
        in the direction the player faces"""
        # Setup the camera so that its on the player
        self.camDummy = NodePath(PandaNode("camDummy"))
        self.camDummy.reparentTo(player.movementParent)
        self.camDummy.setPos(0, 0, 1.8)
        base.camera.reparentTo(self.camDummy)
        base.camera.setPos(0, -8, 2)

    def followPlayerTPS(self, dt):
    	player = self.engine.GameObjects["player"].bulletBody
        ih = self.engine.inputHandler
        if base.win.movePointer(0, ih.winXhalf, ih.winYhalf) \
               and base.mouseWatcherNode.hasMouse():
            cam = self.camDummy.getP() - (ih.mouseY - ih.winYhalf) * ih.mouseSpeedY
            if cam <-80:
                cam = -80
            elif cam > 90:
                cam = 90
            self.camDummy.setP(cam)
    	base.camera.lookAt(self.camDummy)

    #
    # Third person adventure mode
    #
    def initTPAMode(self, player):
        """Sets the cam mode to a third person adventure mode, so the
        cam will be up and behind the player and will be lazily move
        behind the player."""
        # create a new dummy node that the cam will look at
        self.camDummy = NodePath(PandaNode("camDummy"))
        self.camDummy.reparentTo(render)
        # Setup the camera so that its on the player
        base.camera.reparentTo(self.camDummy)
        base.camera.setPos(player.getX(), player.getY() - 6.0, player.getZ() + 4.0)

    def followPlayerTPA(self, dt):
    	player = self.engine.GameObjects["player"].bulletBody
        base.camera.lookAt(player.getPos())

        ih = self.engine.inputHandler
        if base.win.movePointer(0, ih.winXhalf, ih.winYhalf) \
               and base.mouseWatcherNode.hasMouse():
            omega = (ih.mouseX - ih.winXhalf)*-ih.mouseSpeedX * dt * 0.25
            if omega != 0.0:
                base.camera.setX(base.camera, omega)

        camvec = player.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        minCamDist = 2.0
        maxCamDist = 8.0
        if camdist > maxCamDist:
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-maxCamDist))
            camdist = maxCamDist
        if camdist < minCamDist:
            base.camera.setPos(base.camera.getPos() - camvec*(minCamDist-camdist))
            camdist = minCamDist

        if base.camera.getZ() > self.camDummy.getZ() + 2:
            base.camera.setZ(self.camDummy.getZ() + 2)
        elif base.camera.getZ() < self.camDummy.getZ() + 1:
            base.camera.setZ(self.camDummy.getZ() + 1)

        self.camDummy.setPos(player.getPos())
        self.camDummy.setZ(player.getZ() + 2.0)
        base.camera.lookAt(self.camDummy)
Exemple #6
0
class CogdoFlyingCameraManager:
    def __init__(self, cam, parent, player, level):
        self._toon = player.toon
        self._camera = cam
        self._parent = parent
        self._player = player
        self._level = level
        self._enabled = False

    def enable(self):
        if self._enabled:
            return
        self._toon.detachCamera()
        self._prevToonY = 0.0
        levelBounds = self._level.getBounds()
        l = Globals.Camera.LevelBoundsFactor
        self._bounds = ((levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]),
                        (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]),
                        (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2]))
        self._lookAtZ = self._toon.getHeight(
        ) + Globals.Camera.LookAtToonHeightOffset
        self._camParent = NodePath('CamParent')
        self._camParent.reparentTo(self._parent)
        self._camParent.setPos(self._toon, 0, 0, 0)
        self._camParent.setHpr(180, Globals.Camera.Angle, 0)
        self._camera.reparentTo(self._camParent)
        self._camera.setPos(0, Globals.Camera.Distance, 0)
        self._camera.lookAt(self._toon, 0, 0, self._lookAtZ)
        self._cameraLookAtNP = NodePath('CameraLookAt')
        self._cameraLookAtNP.reparentTo(self._camera.getParent())
        self._cameraLookAtNP.setPosHpr(self._camera.getPos(),
                                       self._camera.getHpr())
        self._levelBounds = self._level.getBounds()
        self._enabled = True
        self._frozen = False
        self._initCollisions()

    def _initCollisions(self):
        self._camCollRay = CollisionRay()
        camCollNode = CollisionNode('CameraToonRay')
        camCollNode.addSolid(self._camCollRay)
        camCollNode.setFromCollideMask(OTPGlobals.WallBitmask
                                       | OTPGlobals.CameraBitmask
                                       | ToontownGlobals.FloorEventBitmask
                                       | ToontownGlobals.CeilingBitmask)
        camCollNode.setIntoCollideMask(0)
        self._camCollNP = self._camera.attachNewNode(camCollNode)
        self._camCollNP.show()
        self._collOffset = Vec3(0, 0, 0.5)
        self._collHandler = CollisionHandlerQueue()
        self._collTrav = CollisionTraverser()
        self._collTrav.addCollider(self._camCollNP, self._collHandler)
        self._betweenCamAndToon = {}
        self._transNP = NodePath('trans')
        self._transNP.reparentTo(render)
        self._transNP.setTransparency(True)
        self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon)
        self._transNP.setBin('fixed', 10000)

    def _destroyCollisions(self):
        self._collTrav.removeCollider(self._camCollNP)
        self._camCollNP.removeNode()
        del self._camCollNP
        del self._camCollRay
        del self._collHandler
        del self._collOffset
        del self._betweenCamAndToon
        self._transNP.removeNode()
        del self._transNP

    def freeze(self):
        self._frozen = True

    def unfreeze(self):
        self._frozen = False

    def disable(self):
        if not self._enabled:
            return
        self._destroyCollisions()
        self._camera.wrtReparentTo(render)
        self._cameraLookAtNP.removeNode()
        del self._cameraLookAtNP
        self._camParent.removeNode()
        del self._camParent
        del self._prevToonY
        del self._lookAtZ
        del self._bounds
        del self._frozen
        self._enabled = False

    def update(self, dt=0.0):
        self._updateCam(dt)
        self._updateCollisions()

    def _updateCam(self, dt):
        toonPos = self._toon.getPos()
        camPos = self._camParent.getPos()
        x = camPos[0]
        z = camPos[2]
        toonWorldX = self._toon.getX(render)
        maxX = Globals.Camera.MaxSpinX
        toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX)
        spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (
            maxX * maxX)
        newH = 180.0 + spinAngle
        self._camParent.setH(newH)
        spinAngle = spinAngle * (pi / 180.0)
        distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle)
        distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle)
        d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0])
        if abs(d) > Globals.Camera.LeewayX:
            if d > Globals.Camera.LeewayX:
                x = toonPos[0] + Globals.Camera.LeewayX
            else:
                x = toonPos[0] - Globals.Camera.LeewayX
        x = self._toon.getX(render) + distToRightOfToon
        boundToonZ = min(toonPos[2], self._bounds[2][1])
        d = z - boundToonZ
        if d > Globals.Camera.MinLeewayZ:
            if self._player.velocity[2] >= 0 and toonPos[
                    1] != self._prevToonY or self._player.velocity[2] > 0:
                z = boundToonZ + d * INVERSE_E**(dt *
                                                 Globals.Camera.CatchUpRateZ)
            elif d > Globals.Camera.MaxLeewayZ:
                z = boundToonZ + Globals.Camera.MaxLeewayZ
        elif d < -Globals.Camera.MinLeewayZ:
            z = boundToonZ - Globals.Camera.MinLeewayZ
        if self._frozen:
            y = camPos[1]
        else:
            y = self._toon.getY(render) - distBehindToon
        self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z))
        if toonPos[2] < self._bounds[2][1]:
            h = self._cameraLookAtNP.getH()
            if d >= Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ)
            elif d <= -Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._camParent, 0, 0,
                                            self._lookAtZ)
            self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0)
            self._camera.setHpr(
                smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr()))
        self._prevToonY = toonPos[1]

    def _updateCollisions(self):
        pos = self._toon.getPos(self._camera) + self._collOffset
        self._camCollRay.setOrigin(pos)
        direction = -Vec3(pos)
        direction.normalize()
        self._camCollRay.setDirection(direction)
        self._collTrav.traverse(render)
        nodesInBetween = {}
        if self._collHandler.getNumEntries() > 0:
            self._collHandler.sortEntries()
            for entry in self._collHandler.getEntries():
                name = entry.getIntoNode().getName()
                if name.find('col_') >= 0:
                    np = entry.getIntoNodePath().getParent()
                    if np not in nodesInBetween:
                        nodesInBetween[np] = np.getParent()

        for np in nodesInBetween.keys():
            if np in self._betweenCamAndToon:
                del self._betweenCamAndToon[np]
            else:
                np.setTransparency(True)
                np.wrtReparentTo(self._transNP)
                if np.getName().find('lightFixture') >= 0:
                    if not np.find('**/*floor_mesh').isEmpty():
                        np.find('**/*floor_mesh').hide()
                elif np.getName().find('platform') >= 0:
                    if not np.find('**/*Floor').isEmpty():
                        np.find('**/*Floor').hide()

        for np, parent in self._betweenCamAndToon.items():
            np.wrtReparentTo(parent)
            np.setTransparency(False)
            if np.getName().find('lightFixture') >= 0:
                if not np.find('**/*floor_mesh').isEmpty():
                    np.find('**/*floor_mesh').show()
            elif np.getName().find('platform') >= 0:
                if not np.find('**/*Floor').isEmpty():
                    np.find('**/*Floor').show()

        self._betweenCamAndToon = nodesInBetween
Exemple #7
0
class CameraControl(DirectObject, HasKeybinds):
    """ adds controls to a given camera, usually base.camera"""
    def __init__(self,camera=None):
        #camera setup
        self.camera = camera
        if self.camera == None:
            self.camera = base.camera


        #XXX note, when moving cam target we need to make sure the camera doesnt move too...
        cameraBase = GeomNode('cameraBase') #utility node for pan
        targetGeom = makeCameraTarget()
        cameraBase.addGeom(targetGeom)
        self.cameraBase = render.attachNewNode(cameraBase)
        #self.cameraBase.setTwoSided(True) #backface culling issue with my tristrip fail

        self.cameraTarget = NodePath('cameraTarget') #utility node for rot, zoom, reattach
        self.cameraTarget.reparentTo(self.cameraBase)
        #self.cameraTarget.reparentTo(render)
        self.camera.reparentTo(self.cameraTarget)


        self.track = self.camera.attachNewNode('track')  #hack for pointing vector
        self.track.setPos(LVecBase3f(0,50,0))
        #nn = GeomNode('helper')
        #ng = makeCameraTarget()
        #nn.addGeom(targetGeom)
        #self.track.attachNewNode(nn)

        #keybind setup
        self.__ends__=defaultdict(list)

        #self.accept("escape", sys.exit)  #no, exit_cleanup will handle this...

        for function_name, key in keybinds['view'].items():
            #self.accept(key,taskMgr.add,(getattr(self,function),function+'Task'))
            self.accept(key, self.makeTask, [function_name])  # TODO split out functions that don't require tasks
            keytest=key.split('-')[-1]
            #print(keytest)
            if keytest in {'mouse1','mouse2','mouse3'}:
                self.addEndTask(keytest,function_name)
                self.accept(keytest+'-up', self.endTask, [keytest,function_name])

        #gains #TODO tweak me!
        self.XGAIN = .01
        self.YGAIN = .01

        #window setup
        self.getWindowSize()
        self.accept('window-event', self.getWindowSize)
        


        #self.accept('mouse1') #mouse 1 by itself does selection?
        #self.accpet('mouse3') #pan
        #self.accpet('mouse2')

        #--camera moves relatvie to arbitrary origin--
        #pan in plane
        #zoom #this needs to be on a log scale, linear is balls
        #rotate
        #--camera in place--
        #roll camera in place
        #yaw
        #pitch
        #look at selection/origin/center of mass of
        #--camera lense changes--
        #fov (for perspective)
        #perspective/orthographic
        #--worldcraft--
        #z mode wasd + mouse to orient for zooming

        #--selection functions we need to leave space for--
        #drop origin if we don't have something selected
        #click select
        #drag select, logial intersec
        #right click for menu

        self.__ch__=None
        self.__cp__=None
        self.__cr__=None
        self.__cth__=None
        self.__ctp__=None

        pass

    def getWindowSize(self,wat=None):
        self.__winx__ = base.win.getXSize()
        self.__winy__ = base.win.getYSize()
        #print(self.__winx__,self.__winy__)

    def makeTask(self, function_name):
        """ ye old task spawner """
        if hasattr(self, function_name):
            if base.mouseWatcherNode.hasMouse():
                x,y = base.mouseWatcherNode.getMouse()
                setattr(self, '__%sTask_s__'%function_name, (x,y)) #this should be faster
                taskMgr.add(getattr(self,function_name), function_name+'Task')
        else:
            raise KeyError('Check your keybinds, there is no function by that name here!')

    def addEndTask(self,key,function_name):
        self.__ends__[key].append(function_name)

    def endTask(self, key, function):
        for func in self.__ends__[key]:
            taskMgr.remove(func+'Task')
            setattr(self, '__%sTask_s__'%func, None) #this should be faster
        self.__ch__=None #FIXME this seems hackish
        self.__cp__=None
        self.__cr__=None
        self.__cth__=None
        self.__ctp__=None

    def getMouseDdDt(self, name): #XXX deprecated
        """ use gain to adjust pixels per degree
            this should probably be normalized to screen size actually?
            or no... but to what?
        """
        if base.mouseWatcherNode.hasMouse():
            x,z = base.mouseWatcherNode.getMouse()
            sx,sz = getattr(self,'__%s_start__'%name)
            print(x,sx)
            print(z,sz)
            if z != sz or x != sx: #watch out for aliasing here...
                norm = (((x - sx) * self.XGAIN)**2 + ((z - sz) * self.YGAIN)**2)**.5
                #norm =  ((x - sx) * self.X_GAIN), ((z - sz) * self.Y_GAIN)
                setattr(self, '__%s_start__'%name, (x,z))
                return norm
            else: #mouse has not moved
                return 0

    def getMouseDdDf(self,name):
        if base.mouseWatcherNode.hasMouse():
            x,y = base.mouseWatcherNode.getMouse()
            sx,sy = getattr(self,'__%s_s__'%(name))
            dx = (x - sx) * self.XGAIN * self.__winx__
            dy = (y - sy) * self.YGAIN * self.__winy__
            return dx, dy

    def getMouseCross(self,name): #FIXME may need to do this incrementally as we started with...
        if base.mouseWatcherNode.hasMouse():
            x,y = base.mouseWatcherNode.getMouse()
            sx,sy = getattr(self,'__%s_s__'%(name))

            dx = (x - sx) * self.XGAIN * self.__winx__
            dy = (y - sy) * self.YGAIN * self.__winy__
            norm = (dx**2 + dy**2)**.5
            cross = x * sy - y * sx

            return cross * norm

    @event_callback
    def home(self, task):
        self.camera.lookAt(self.cameraBase)
        taskMgr.remove(task.getName())
        return task.cont

    @event_callback
    def pan(self, task):
        """ I don't like it, it's weird! """
        invert = -1
        magic_number = 15
        magic_number = 20
        if base.mouseWatcherNode.hasMouse():
            x,y = base.mouseWatcherNode.getMouse()
            sx,sy = getattr(self,'__%s_s__'%(task.getName()))
            dx = (x - sx) * self.XGAIN * self.__winx__ * magic_number * invert
            dy = (y - sy) * self.YGAIN * self.__winy__ * magic_number * invert
            #cx,cy,cz = self.camera.getPos()
            self.camera.setPos(self.camera,dx,0,dy)
            setattr(self, '__%s_s__'%task.getName(), (x,y)) #reset each frame to compensate for moving from own position
            #nx,ny,nz = self.camera.getPos()
            #dx2, dy2, dz2 = nx-cx, ny-cy, nz-cz
            #self.camera.setPos(cx,cz,cy)
            #self.cameraBase.setPos(self.cameraBase,dx2,dy2,dz2) #a hack to move cameraBase as if it were the camera
            #self.cameraTarget.setPos(self.cameraBase,dx2,dy2,dz2) #a hack to move cameraBase as if it were the camera
        return task.cont

    @event_callback
    def zoom_in_slow(self, task, speed = 10):
        return self.zoom_in(task, speed) #hehe this will work because it just passes the task :)

    @event_callback
    def zoom_out_slow(self, task, speed = 10):
        return self.zoom_out(task, speed)

    @event_callback
    def zoom_in_fast(self, task, speed = 1000):
        return self.zoom_in(task, speed) #hehe this will work because it just passes the task :)

    @event_callback
    def zoom_out_fast(self, task, speed = 1000):
        return self.zoom_out(task, speed)


    @event_callback
    def zoom_in(self, task, speed = 100): #FIXME zoom_in and zoom_out still get custom xys even thought they don't use them!
        self.camera.setPos(self.camera,0,speed,0)
        taskMgr.remove(task.getName())
        return task.cont

    @event_callback
    def zoom_out(self, task, speed = 100):
        self.camera.setPos(self.camera,0,-speed,0)
        taskMgr.remove(task.getName()) #we do it this way instead of addOnce because we want to add all the tasks in one go
        return task.cont

    @event_callback
    def rotate(self, task): #FIXME disregard orientation acqurie proper mouse movements!
        dx,dy = self.getMouseDdDf(task.getName())
        if self.__cth__ == None:
            self.__cth__ = self.cameraTarget.getH()
        if self.__ctp__ == None:
            self.__ctp__ = self.cameraTarget.getP()
        self.cameraTarget.setH(self.__cth__ - dx * 10)
        self.cameraTarget.setP(self.__ctp__ + dy * 10)
        return task.cont

    #if we are in camera mode
    @event_callback
    def pitch(self, task):
        dx,dy = self.getMouseDdDf(task.getName())
        print('got pitch',dy)
        return task.cont

    @event_callback
    def look(self, task): #AKA heading in hpr
        dx,dy = self.getMouseDdDf(task.getName())
        if self.__ch__ == None:
            self.__ch__ = self.camera.getH()
        if self.__cp__ == None:
            self.__cp__ = self.camera.getP()
        self.camera.setH(self.__ch__ - dx)
        self.camera.setP(self.__cp__ + dy) #FIXME when we're clicking this might should be inverted?
        return task.cont

    @event_callback
    def roll(self, task):
        """ ALWAYS roll with respect to axis of rotation"""
        if self.__cr__ == None:
            self.__cr__ = self.cameraTarget.getR()
        #cross product idiot
        cross = self.getMouseCross(task.getName())

        self.cameraTarget.setR(self.__cr__ - cross * 10 )
        return task.cont
Exemple #8
0
class CameraControl(DirectObject, HasKeybinds):
    """ adds controls to a given camera, usually base.camera"""
    def __init__(self, camera=None):
        #camera setup
        self.camera = camera
        if self.camera == None:
            self.camera = base.camera

        #XXX note, when moving cam target we need to make sure the camera doesnt move too...
        cameraBase = GeomNode('cameraBase')  #utility node for pan
        targetGeom = makeCameraTarget()
        cameraBase.addGeom(targetGeom)
        self.cameraBase = render.attachNewNode(cameraBase)
        #self.cameraBase.setTwoSided(True) #backface culling issue with my tristrip fail

        self.cameraTarget = NodePath(
            'cameraTarget')  #utility node for rot, zoom, reattach
        self.cameraTarget.reparentTo(self.cameraBase)
        #self.cameraTarget.reparentTo(render)
        self.camera.reparentTo(self.cameraTarget)

        self.track = self.camera.attachNewNode(
            'track')  #hack for pointing vector
        self.track.setPos(LVecBase3f(0, 50, 0))
        #nn = GeomNode('helper')
        #ng = makeCameraTarget()
        #nn.addGeom(targetGeom)
        #self.track.attachNewNode(nn)

        #keybind setup
        self.__ends__ = defaultdict(list)

        #self.accept("escape", sys.exit)  #no, exit_cleanup will handle this...

        for function_name, key in keybinds['view'].items():
            #self.accept(key,taskMgr.add,(getattr(self,function),function+'Task'))
            self.accept(
                key, self.makeTask,
                [function_name
                 ])  # TODO split out functions that don't require tasks
            keytest = key.split('-')[-1]
            #print(keytest)
            if keytest in {'mouse1', 'mouse2', 'mouse3'}:
                self.addEndTask(keytest, function_name)
                self.accept(keytest + '-up', self.endTask,
                            [keytest, function_name])

        #gains #TODO tweak me!
        self.XGAIN = .01
        self.YGAIN = .01

        #window setup
        self.getWindowSize()
        self.accept('window-event', self.getWindowSize)

        #self.accept('mouse1') #mouse 1 by itself does selection?
        #self.accpet('mouse3') #pan
        #self.accpet('mouse2')

        #--camera moves relatvie to arbitrary origin--
        #pan in plane
        #zoom #this needs to be on a log scale, linear is balls
        #rotate
        #--camera in place--
        #roll camera in place
        #yaw
        #pitch
        #look at selection/origin/center of mass of
        #--camera lense changes--
        #fov (for perspective)
        #perspective/orthographic
        #--worldcraft--
        #z mode wasd + mouse to orient for zooming

        #--selection functions we need to leave space for--
        #drop origin if we don't have something selected
        #click select
        #drag select, logial intersec
        #right click for menu

        self.__ch__ = None
        self.__cp__ = None
        self.__cr__ = None
        self.__cth__ = None
        self.__ctp__ = None

        pass

    def getWindowSize(self, wat=None):
        self.__winx__ = base.win.getXSize()
        self.__winy__ = base.win.getYSize()
        #print(self.__winx__,self.__winy__)

    def makeTask(self, function_name):
        """ ye old task spawner """
        if hasattr(self, function_name):
            if base.mouseWatcherNode.hasMouse():
                x, y = base.mouseWatcherNode.getMouse()
                setattr(self, '__%sTask_s__' % function_name,
                        (x, y))  #this should be faster
                taskMgr.add(getattr(self, function_name),
                            function_name + 'Task')
        else:
            raise KeyError(
                'Check your keybinds, there is no function by that name here!')

    def addEndTask(self, key, function_name):
        self.__ends__[key].append(function_name)

    def endTask(self, key, function):
        for func in self.__ends__[key]:
            taskMgr.remove(func + 'Task')
            setattr(self, '__%sTask_s__' % func, None)  #this should be faster
        self.__ch__ = None  #FIXME this seems hackish
        self.__cp__ = None
        self.__cr__ = None
        self.__cth__ = None
        self.__ctp__ = None

    def getMouseDdDt(self, name):  #XXX deprecated
        """ use gain to adjust pixels per degree
            this should probably be normalized to screen size actually?
            or no... but to what?
        """
        if base.mouseWatcherNode.hasMouse():
            x, z = base.mouseWatcherNode.getMouse()
            sx, sz = getattr(self, '__%s_start__' % name)
            print(x, sx)
            print(z, sz)
            if z != sz or x != sx:  #watch out for aliasing here...
                norm = (((x - sx) * self.XGAIN)**2 +
                        ((z - sz) * self.YGAIN)**2)**.5
                #norm =  ((x - sx) * self.X_GAIN), ((z - sz) * self.Y_GAIN)
                setattr(self, '__%s_start__' % name, (x, z))
                return norm
            else:  #mouse has not moved
                return 0

    def getMouseDdDf(self, name):
        if base.mouseWatcherNode.hasMouse():
            x, y = base.mouseWatcherNode.getMouse()
            sx, sy = getattr(self, '__%s_s__' % (name))
            dx = (x - sx) * self.XGAIN * self.__winx__
            dy = (y - sy) * self.YGAIN * self.__winy__
            return dx, dy

    def getMouseCross(
            self, name
    ):  #FIXME may need to do this incrementally as we started with...
        if base.mouseWatcherNode.hasMouse():
            x, y = base.mouseWatcherNode.getMouse()
            sx, sy = getattr(self, '__%s_s__' % (name))

            dx = (x - sx) * self.XGAIN * self.__winx__
            dy = (y - sy) * self.YGAIN * self.__winy__
            norm = (dx**2 + dy**2)**.5
            cross = x * sy - y * sx

            return cross * norm

    @event_callback
    def home(self, task):
        self.camera.lookAt(self.cameraBase)
        taskMgr.remove(task.getName())
        return task.cont

    @event_callback
    def pan(self, task):
        """ I don't like it, it's weird! """
        invert = -1
        magic_number = 15
        magic_number = 20
        if base.mouseWatcherNode.hasMouse():
            x, y = base.mouseWatcherNode.getMouse()
            sx, sy = getattr(self, '__%s_s__' % (task.getName()))
            dx = (x - sx) * self.XGAIN * self.__winx__ * magic_number * invert
            dy = (y - sy) * self.YGAIN * self.__winy__ * magic_number * invert
            #cx,cy,cz = self.camera.getPos()
            self.camera.setPos(self.camera, dx, 0, dy)
            setattr(
                self, '__%s_s__' % task.getName(), (x, y)
            )  #reset each frame to compensate for moving from own position
            #nx,ny,nz = self.camera.getPos()
            #dx2, dy2, dz2 = nx-cx, ny-cy, nz-cz
            #self.camera.setPos(cx,cz,cy)
            #self.cameraBase.setPos(self.cameraBase,dx2,dy2,dz2) #a hack to move cameraBase as if it were the camera
            #self.cameraTarget.setPos(self.cameraBase,dx2,dy2,dz2) #a hack to move cameraBase as if it were the camera
        return task.cont

    @event_callback
    def zoom_in_slow(self, task, speed=10):
        return self.zoom_in(
            task,
            speed)  #hehe this will work because it just passes the task :)

    @event_callback
    def zoom_out_slow(self, task, speed=10):
        return self.zoom_out(task, speed)

    @event_callback
    def zoom_in_fast(self, task, speed=1000):
        return self.zoom_in(
            task,
            speed)  #hehe this will work because it just passes the task :)

    @event_callback
    def zoom_out_fast(self, task, speed=1000):
        return self.zoom_out(task, speed)

    @event_callback
    def zoom_in(
        self,
        task,
        speed=100
    ):  #FIXME zoom_in and zoom_out still get custom xys even thought they don't use them!
        self.camera.setPos(self.camera, 0, speed, 0)
        taskMgr.remove(task.getName())
        return task.cont

    @event_callback
    def zoom_out(self, task, speed=100):
        self.camera.setPos(self.camera, 0, -speed, 0)
        taskMgr.remove(
            task.getName()
        )  #we do it this way instead of addOnce because we want to add all the tasks in one go
        return task.cont

    @event_callback
    def rotate(self, task
               ):  #FIXME disregard orientation acqurie proper mouse movements!
        dx, dy = self.getMouseDdDf(task.getName())
        if self.__cth__ == None:
            self.__cth__ = self.cameraTarget.getH()
        if self.__ctp__ == None:
            self.__ctp__ = self.cameraTarget.getP()
        self.cameraTarget.setH(self.__cth__ - dx * 10)
        self.cameraTarget.setP(self.__ctp__ + dy * 10)
        return task.cont

    #if we are in camera mode
    @event_callback
    def pitch(self, task):
        dx, dy = self.getMouseDdDf(task.getName())
        print('got pitch', dy)
        return task.cont

    @event_callback
    def look(self, task):  #AKA heading in hpr
        dx, dy = self.getMouseDdDf(task.getName())
        if self.__ch__ == None:
            self.__ch__ = self.camera.getH()
        if self.__cp__ == None:
            self.__cp__ = self.camera.getP()
        self.camera.setH(self.__ch__ - dx)
        self.camera.setP(
            self.__cp__ +
            dy)  #FIXME when we're clicking this might should be inverted?
        return task.cont

    @event_callback
    def roll(self, task):
        """ ALWAYS roll with respect to axis of rotation"""
        if self.__cr__ == None:
            self.__cr__ = self.cameraTarget.getR()
        #cross product idiot
        cross = self.getMouseCross(task.getName())

        self.cameraTarget.setR(self.__cr__ - cross * 10)
        return task.cont
Exemple #9
0
class LocalPlayer(object):
    def __init__(self, mapobj, showbase):
        self.x = None
        self.y = None
        self.win = showbase.win
        self.map = mapobj
        self.mouseWatcherNode = showbase.mouseWatcherNode
        self.accept = showbase.accept
        self.camera = showbase.camera
        self.setup_input()

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(showbase.render)
        self.up = Vec3(0, 1, 0)

        incarn = self.map.world.get_incarn()
        walker_color_dict = {
            "barrel_color": [219.0 / 255, 16.0 / 255, 50.0 / 255],
            "visor_color": [157.0 / 255, 14.0 / 255, 48.0 / 255],
            "body_primary_color": [44.0 / 255, 31.0 / 255, 54.0 / 255],
            "body_secondary_color": [80.0 / 255, 44.0 / 255, 62.0 / 255]
        }
        self.walker = self.map.world.attach(
            Walker(incarn, colordict=walker_color_dict, player=True))
        taskMgr.add(self.move, 'move')

    def setup_input(self):
        self.key_map = {
            'cam_forward': 0,
            'cam_left': 0,
            'cam_backward': 0,
            'cam_right': 0,
            'left': 0,
            'right': 0,
            'forward': 0,
            'backward': 0,
            'rotateLeft': 0,
            'rotateRight': 0,
            'walkForward': 0,
            'crouch': 0,
            'fire': 0,
            'missile': 0,
            'grenade_fire': 0,
            'grenade': 0,
            'print_cam': 0
        }
        self.accept('escape', sys.exit)
        self.accept('p', self.drop_blocks)

        for key, cmd in KeyMaps.flycam_input_settings:
            self.accept(key, self.set_key, [cmd, 1])
            self.accept(key + "-up", self.set_key, [cmd, 0])

    def move(self, task):
        dt = globalClock.getDt()
        if self.mouseWatcherNode.hasMouse():
            oldx = self.x
            oldy = self.y
            md = self.win.getPointer(0)
            self.x = md.getX()
            self.y = md.getY()
            centerx = self.win.getProperties().getXSize() / 2
            centery = self.win.getProperties().getYSize() / 2
            self.win.movePointer(0, centerx, centery)

            if (oldx is not None):
                self.floater.setPos(self.camera, 0, 0, 0)
                self.floater.setHpr(self.camera, 0, 0, 0)
                self.floater.setH(self.floater, (centerx - self.x) * 10 * dt)
                p = self.floater.getP()
                self.floater.setP(self.floater, (centery - self.y) * 10 * dt)
                self.floater.setZ(self.floater, -1)
                angle = self.up.angleDeg(self.floater.getPos() -
                                         self.camera.getPos())
                if 10 > angle or angle > 170:
                    self.floater.setPos(self.camera, 0, 0, 0)
                    self.floater.setP(p)
                    self.floater.setZ(self.floater, -1)
                self.camera.lookAt(self.floater.getPos(), self.up)
        else:
            self.x = None
            self.y = None

        if (self.key_map['cam_forward']):
            self.camera.setZ(self.camera, -25 * dt)
        if (self.key_map['cam_backward']):
            self.camera.setZ(self.camera, 25 * dt)
        if (self.key_map['cam_left']):
            self.camera.setX(self.camera, -25 * dt)
        if (self.key_map['cam_right']):
            self.camera.setX(self.camera, 25 * dt)
        if (self.key_map['print_cam']):
            print "CAMERA: Pos - %s, Hpr - %s" % (self.camera.get_pos(),
                                                  self.camera.get_hpr())
            self.key_map['print_cam'] = 0

        self.walker.handle_command('forward', self.key_map['forward'])
        self.walker.handle_command('left', self.key_map['left'])
        self.walker.handle_command('backward', self.key_map['backward'])
        self.walker.handle_command('right', self.key_map['right'])
        self.walker.handle_command('crouch', self.key_map['crouch'])

        self.walker.handle_command('fire', self.key_map['fire'])
        if self.key_map['fire']: self.key_map['fire'] = 0
        self.walker.handle_command('missile', self.key_map['missile'])
        if self.key_map['missile']: self.key_map['missile'] = 0
        self.walker.handle_command('grenade_fire',
                                   self.key_map['grenade_fire'])
        if self.key_map['grenade_fire']: self.key_map['grenade_fire'] = 0
        self.walker.handle_command('grenade', self.key_map['grenade'])
        if self.key_map['grenade']: self.key_map['grenade'] = 0

        return task.cont

    def set_key(self, key, value):
        self.key_map[key] = value

    def drop_blocks(self):
        block = self.map.world.attach(
            FreeSolid(
                Block((1, 1, 1), (1, 0, 0, 1), 0.01, (0, 40, 0), (0, 0, 0)),
                0.01))
        for i in range(10):
            rand_pos = (random.randint(-25, 25), 40, random.randint(-25, 25))
            block = self.map.world.attach(
                FreeSolid(
                    Block((1, 1, 1), (1, 0, 0, 1), 0.01, rand_pos, (0, 0, 0)),
                    0.01))
Exemple #10
0
class Player(object):
    """
        Player is the main actor in the fps game
    """
    FORWARD = Vec3(0,2,0)
    BACK = Vec3(0,-1,0)
    LEFT = Vec3(-1,0,0)
    RIGHT = Vec3(1,0,0)
    FLYUP = Vec3(0,0,1)
    FLYDN = Vec3(0,0,-1)
    STOP = Vec3(0)
    PORTAL_CYCLE = {
        'blue' : 'orange',
        'orange' : 'blue',
        }

    def __init__(self, base, fps, osd):
        self.base = base
        self.fps = fps
        self.osd = osd
        self.speed = RUN_SPEED
        self.walk = self.STOP
        self.readyToJump = False
        self.intoPortal = None
        self.mass = Mass()
        self.origin = self.fps.level.settings.origin
        self.bporigin = (999,999,999)
        self.oporigin = (999,999,999)
        self.current_target = None
        self.canPortal = []
        self.canSetTarget = True
        self.selectedCubes = []
        self.editorTextureStage = TextureStage('editor')
        self.editorSelectedTexture = loader.loadTexture('models/tex/selected.png')
        self.selectingForMulti = False
        # Init functions
        self.loadModel()
        self.makePortals()
        self.setUpCamera()
        if self.fps.editor_mode:
            self.createMouseCollisions()
            self.speed = self.speed * 5
            self.attachEditorControls()
            self.attachEditorTasks()
        else:
            self.createCollisions()
            self.attachStandardControls()
            self.attachStandardTasks()

    def loadModel(self):
        """ make the nodepath for player """
        self.node = NodePath('player')
        self.node.reparentTo(render)
        self.node.setPos(*self.origin)
        self.node.setScale(0.05)
        self.mass.pos = VBase3(self.node.getX(), self.node.getY(), self.node.getZ())

    def makePortals(self):
        # The BLUE CUBE
        bpor = loader.loadModel("cube_nocol")
        bpor.setTag('noportals', '1')
        bpor.reparentTo(render)
        bpor.setPos(*self.bporigin)
        bpor.setScale(0.3,0.02,0.5)
        # The BLUE CUBE's camera
        bbuffer = self.base.win.makeTextureBuffer("B Buffer", 512, 512)
        bbuffer.setSort(-100)
        bcamera = self.base.makeCamera(bbuffer)
        bcamera.node().getLens().setAspectRatio(0.3/0.5)
        bcamera.node().getLens().setFov(15)
        bcamera.reparentTo(bpor)
        bcamera.node().setScene(render)

        # The ORANGE CUBE
        opor = loader.loadModel("cube_nocol")
        opor.setTag('noportals', '1')
        opor.reparentTo(render)
        opor.setPos(*self.oporigin)
        opor.setScale(0.3,0.02,0.5)
        # The ORANGE CUBE's camera
        obuffer = self.base.win.makeTextureBuffer("O Buffer", 512, 512)
        obuffer.setSort(-100)
        ocamera = self.base.makeCamera(obuffer)
        ocamera.node().getLens().setAspectRatio(0.3/0.5)
        ocamera.node().getLens().setFov(15)
        ocamera.reparentTo(opor)
        ocamera.node().setScene(render)

        # Assign the textures
        bpor.setTexture(obuffer.getTexture())
        opor.setTexture(bbuffer.getTexture())
        # Store the portals and theirs cameras
        self.bluePortal = bpor
        self.bluePortal.setHpr(0,90,0)
        self.orangePortal = opor
        self.orangePortal.setHpr(0,-90,0)
        self.bcamera = bcamera
        self.ocamera = ocamera

    def setUpCamera(self):
        """ puts camera at the players node """
        pl =  self.base.cam.node().getLens()
        pl.setFov(70)
        self.base.cam.node().setLens(pl)
        self.base.camera.reparentTo(self.node)
        self.base.camLens.setFov(100)
        if self.fps.editor_mode:
            self.node.lookAt(self.fps.level.cubes_hash.keys()[0])

    def createCollisions(self):
        self.createPlayerCollisions()
        self.createMouseCollisions()
        self.createPortalCollisions()

    def createPlayerCollisions(self):
        """ create a collision solid and ray for the player """
        cn = CollisionNode('player')
        cn.setFromCollideMask(COLLISIONMASKS['geometry'])
        cn.setIntoCollideMask(COLLISIONMASKS['portals'] | COLLISIONMASKS['exit'] | COLLISIONMASKS['lava'])
        cn.addSolid(CollisionSphere(0,0,0,3))
        solid = self.node.attachNewNode(cn)
        # TODO : find a way to remove that, it's the cause of the little
        # "push me left" effect we see sometime when exiting a portal
        self.base.cTrav.addCollider(solid,self.base.pusher)
        self.base.pusher.addCollider(solid,self.node, self.base.drive.node())
        # init players floor collisions
        ray = CollisionRay()
        ray.setOrigin(0,0,-.2)
        ray.setDirection(0,0,-1)
        cn = CollisionNode('playerRay')
        cn.setFromCollideMask(COLLISIONMASKS['player'])
        cn.setIntoCollideMask(BitMask32.allOff())
        cn.addSolid(ray)
        solid = self.node.attachNewNode(cn)
        self.nodeGroundHandler = CollisionHandlerQueue()
        self.base.cTrav.addCollider(solid, self.nodeGroundHandler)
        # init players ceil collisions
        ray = CollisionRay()
        ray.setOrigin(0,0,.2)
        ray.setDirection(0,0,1)
        cn = CollisionNode('playerUpRay')
        cn.setFromCollideMask(COLLISIONMASKS['player'])
        cn.setIntoCollideMask(BitMask32.allOff())
        cn.addSolid(ray)
        solid = self.node.attachNewNode(cn)
        self.ceilGroundHandler = CollisionHandlerQueue()
        self.base.cTrav.addCollider(solid, self.ceilGroundHandler)

    def createMouseCollisions(self):
        # Fire the portals
        firingNode = CollisionNode('mouseRay')
        firingNP = self.base.camera.attachNewNode(firingNode)
        firingNode.setFromCollideMask(COLLISIONMASKS['geometry'])
        firingNode.setIntoCollideMask(BitMask32.allOff())
        firingRay = CollisionRay()
        firingRay.setOrigin(0,0,0)
        firingRay.setDirection(0,1,0)
        firingNode.addSolid(firingRay)
        self.firingHandler = CollisionHandlerQueue()
        self.base.cTrav.addCollider(firingNP, self.firingHandler)

    def createPortalCollisions(self):
        # Enter the portals
        cn = CollisionNode('bluePortal')
        cn.setFromCollideMask(COLLISIONMASKS['portals'])
        cn.setIntoCollideMask(BitMask32.allOff())
        np = self.bluePortal.attachNewNode(cn)
        cn.addSolid(CollisionSphere(0,0,0,2))
        h = CollisionHandlerEvent()
        h.addInPattern('%fn-into-%in')
        h.addOutPattern('%fn-outof-%in')
        self.base.cTrav.addCollider(np, h)
        cn = CollisionNode('orangePortal')
        cn.setFromCollideMask(COLLISIONMASKS['portals'])
        cn.setIntoCollideMask(BitMask32.allOff())
        np = self.orangePortal.attachNewNode(cn)
        cn.addSolid(CollisionSphere(0,0,0,2))
        h = CollisionHandlerEvent()
        h.addInPattern('%fn-into-%in')
        h.addOutPattern('%fn-outof-%in')
        self.base.cTrav.addCollider(np, h)

    def attachCommonControls(self):
        self.base.accept( "z" if AZERTY else "w" , self.addWalk,[self.FORWARD])
        self.base.accept( "z-up" if AZERTY else "w-up" , self.addWalk,[-self.FORWARD] )
        self.base.accept( "s" , self.addWalk,[self.BACK] )
        self.base.accept( "s-up" , self.addWalk,[-self.BACK] )
        self.base.accept( "q" if AZERTY else "a" , self.addWalk,[self.LEFT])
        self.base.accept( "q-up" if AZERTY else "a-up" , self.addWalk,[-self.LEFT] )
        self.base.accept( "d" , self.addWalk,[self.RIGHT] )
        self.base.accept( "d-up" , self.addWalk,[-self.RIGHT] )
        self.base.accept( "r-up" , self.resetPosition )
        self.base.accept( "p-up" , self.showPosition )
        self.base.accept( "b-up" , self.deBug )

    def attachStandardControls(self):
        self.attachCommonControls()
        self.base.accept( "space" , self.__setattr__,["readyToJump",True])
        self.base.accept( "space-up" , self.__setattr__,["readyToJump",False])
        self.base.accept( "c-up" , self.__setattr__,["intoPortal",None] )
        self.base.accept( "e-up" , self.erasePortals )
        self.base.accept( "mouse1" , self.fireBlue )
        self.base.accept( "mouse3" , self.fireOrange )
        # Events
        self.base.accept( "bluePortal-into-player" , self.enterPortal, ["blue"] )
        self.base.accept( "orangePortal-into-player" , self.enterPortal, ["orange"] )
        self.base.accept( "bluePortal-outof-player" , self.exitPortal, ["blue"] )
        self.base.accept( "orangePortal-outof-player" , self.exitPortal, ["orange"] )
        self.base.accept( "levelExit-into-player" , self.levelExit)
        self.base.accept( "lava-into-player" , self.fallIntoLava)

    def attachStandardTasks(self):
        taskMgr.add(self.mouseUpdate, 'mouse-task')
        taskMgr.add(self.moveUpdate, 'move-task')
        taskMgr.add(self.jumpUpdate, 'jump-task')

    def attachEditorControls(self):
        self.attachCommonControls()
        self.base.accept( "space" , self.__setattr__, ['selectingForMulti', 1])
        self.base.accept( "space-up" , self.__setattr__, ['selectingForMulti', 0])
        self.base.accept( "shift-space" , self.__setattr__, ['selectingForMulti', 2])
        self.base.accept( "shift-space-up" , self.__setattr__, ['selectingForMulti', 0])
        self.base.accept( "c-up" , self.clearMultiSelectedCubes)
        self.base.accept( "mouse1" , self.selectCubeForCopy, [1])
        self.base.accept( "wheel_up" , self.selectCubeForChange, [1] )
        self.base.accept( "wheel_down" , self.selectCubeForChange, [-1] )
        self.base.accept( "mouse3" , self.selectCubeForDelete )
        self.base.accept("f11", self.saveLevel)
        self.base.accept("x", self.selectCubeForRectangle)
        self.base.accept("shift-x", self.selectCubeForRectangle, [True])
        self.base.accept("l", self.addLightHere)
        self.base.accept("u", self.fps.level.undo, [1])
        for i in range(1,10):
            self.base.accept( "%i-up" % (i,), self.selectCubeForCopy, [i])
        for key, vec in [("a" if AZERTY else "q", self.FLYUP),("w" if AZERTY else "z", self.FLYDN)]:
            self.base.accept(key, self.addWalk, [vec])
            self.base.accept(key + "-up", self.addWalk, [-vec])

    def attachEditorTasks(self):
        taskMgr.add(self.mouseUpdate, 'mouse-task')
        taskMgr.add(self.moveInEditor, 'move-task')

    def deBug(self):
        import pdb
        pdb.set_trace()
    def showPosition(self):
        print self.node.getPos()
        print self.mass
    def fallIntoLava(self, *args, **kwargs):
        # TODO : sound and message + little delay
        self.erasePortals()
        self.resetPosition()
    def resetPosition(self, *args, **kwargs):
        self.node.setHpr(VBase3(0,0,0))
        self.mass.pos = VBase3(*self.origin)
        self.mass.vel = VBase3(0,0,0)
        self.mass.force = VBase3(0,0,0)
        self.node.setPos(self.mass.pos)
    def erasePortals(self):
        self.bluePortal.setPos(*self.bporigin)
        self.orangePortal.setPos(*self.oporigin)
        self.bluePortal.detachNode()
        self.orangePortal.detachNode()
        self.intoPortal = None
        self.canPortal = []
    #@oldpostracker
    def mouseUpdate(self,task):
        """ this task updates the mouse """
        md = self.base.win.getPointer(0)
        x = md.getX()
        y = md.getY()
        if self.base.win.movePointer(0, self.base.win.getXSize()/2, self.base.win.getYSize()/2):
            self.node.setH(self.node.getH() -  (x - self.base.win.getXSize()/2)*0.1)
            if self.fps.editor_mode:
                self.node.setP(self.node.getP() - (y - self.base.win.getYSize()/2)*0.1)
            else:
                self.base.camera.setP(self.base.camera.getP() - (y - self.base.win.getYSize()/2)*0.1)
            self.canSetTarget = True
            self.bcamera.lookAt(self.bluePortal, self.node.getPos(self.orangePortal))
            self.ocamera.lookAt(self.orangePortal, self.node.getPos(self.bluePortal))
            #self.canPortal = ['blue','orange']
            if self.fps.editor_mode:
                cube, point, normal = self.selectCube()
                self.osd.updateTargetPosition(cube)
        if self.selectingForMulti:
            self.selectCubeForMulti()
        return task.cont

    def addWalk(self, vec):
        self.walk += vec

    def moveUpdate(self,task):
        """ this task makes the player move """
        # move where the keys set it
        self.node.setPos(self.node, self.walk*globalClock.getDt()*self.speed)
        return task.cont

    #@oldpostracker
    def jumpUpdate(self,task):
        """ this task simulates gravity and makes the player jump """
        # get the highest Z from the down casting ray
        highestZ = -100
        lowestZ = 100
        for i in range(self.nodeGroundHandler.getNumEntries()):
            entry = self.nodeGroundHandler.getEntry(i)
            z = entry.getSurfacePoint(render).getZ()
            if z > highestZ and entry.getIntoNode().getName() in ( "CollisionStuff", "Plane", "Cube" ):
                highestZ = z
        for i in range(self.ceilGroundHandler.getNumEntries()):
            entry = self.ceilGroundHandler.getEntry(i)
            z = entry.getSurfacePoint(render).getZ()
            if z < lowestZ and entry.getIntoNode().getName() in ( "CollisionStuff", "Plane", "Cube" ):
                lowestZ = z
        # gravity effects and jumps
        self.mass.simulate(globalClock.getDt())
        self.node.setZ(self.mass.pos.getZ())
        if highestZ > self.node.getZ()-PLAYER_TO_FLOOR_TOLERANCE:
            self.mass.zero()
            self.mass.pos.setZ(highestZ+PLAYER_TO_FLOOR_TOLERANCE)
            self.node.setZ(highestZ+PLAYER_TO_FLOOR_TOLERANCE)
        if lowestZ < self.node.getZ()+PLAYER_TO_FLOOR_TOLERANCE:
            self.mass.zero()
            self.mass.pos.setZ(lowestZ-PLAYER_TO_FLOOR_TOLERANCE)
            self.node.setZ(lowestZ-PLAYER_TO_FLOOR_TOLERANCE)
        if self.readyToJump and self.node.getZ() < highestZ + PLAYER_TO_FLOOR_TOLERANCE_FOR_REJUMP:
            self.mass.jump(JUMP_FORCE)
        return task.cont

    def firePortal(self, name, node):
        def hasTagValue(node, tag, value):
            if node.getTag(tag) == value:
                return True
            for pnum in range(node.getNumParents()):
                return hasTagValue(node.getParent(pnum), tag, value)
            return False
        self.firingHandler.sortEntries()
        if self.firingHandler.getNumEntries() > 0:
            closest = self.firingHandler.getEntry(0)
            if hasTagValue(closest.getIntoNode(), 'noportals', '1'):
                return
            point = closest.getSurfacePoint(render)
            normal = closest.getSurfaceNormal(render)
            node.setPos(point)
            node.lookAt(point + normal)
            node.reparentTo(render)
            dest = self.PORTAL_CYCLE[name]
            if dest not in self.canPortal:
                self.canPortal.append(dest)

    def fireBlue(self, *arg, **kwargs):
        self.firePortal("blue", self.bluePortal)

    def fireOrange(self, *arg, **kwargs):
        self.firePortal("orange", self.orangePortal)

    #@oldpostracker
    def enterPortal(self, color, collision):
        if self.intoPortal is None and color in self.canPortal:
            self.intoPortal = color
            portal = {"orange": self.bluePortal, "blue": self.orangePortal}.get(color)
            otherportal = {"orange": self.orangePortal, "blue": self.bluePortal}.get(color)
            # Handle horizontal portals :
            if portal.getH() == 0:
                self.node.setP(0)
                self.node.setR(0)
            elif otherportal.getH() == 0:
                self.node.setH(portal.getH())
                self.node.setP(0)
                self.node.setR(0)
            else:
                # New HPR is relative to 'new' portal but it the 'same' value
                # as the old HPR seen from the 'other' portal
                oldh_fromportal = self.node.getH(otherportal)
                self.node.setHpr(Vec3(0,0,0))
                self.node.setH(portal, 180-oldh_fromportal)
                newh_fromportal = self.node.getH(portal)
            self.node.setPos(portal, self.walk * 10.)
            self.mass.pos = self.node.getPos()
            # Make half a turn (only if we straffing without walking)
            if self.walk.getY() == 0 and self.walk.getX() != 0:
                self.node.setH(self.node, 180)
                self.node.setPos(self.node, self.walk * 10)
    #@oldpostracker
    def exitPortal(self, color, collision):
        # When you entered the blue portal, you have to exit the orange one
        if self.intoPortal != color:
            self.intoPortal = None

    def levelExit(self, event):
        if self.fps.level.settings.next_level:
            self.fps.level.loadlevel(self.fps.level.settings.next_level)
            self.origin = self.fps.level.settings.origin
            self.resetPosition()
            self.erasePortals()
            self.walk = self.STOP
        else:
            print "You won !"
            sys.exit(0)

    # EDITOR MODE
    def selectCube(self):
        self.firingHandler.sortEntries()
        if self.firingHandler.getNumEntries() > 0:
            closest = self.firingHandler.getEntry(0)
            return closest.getIntoNodePath().getParent().getParent(), closest.getSurfacePoint(render), closest.getSurfaceNormal(render) # render/cube.egg/-PandaNode/-GeomNode
        else:
            return None, None, None

    def clearMultiSelectedCubes(self):
        for c in self.selectedCubes:
            c.clearTexture(self.editorTextureStage)
        self.selectedCubes = []

    def selectCubeForMulti(self):
        cube, point, normal = self.selectCube()
        if cube:
            if self.selectingForMulti == 1:
                cube.setTexture(self.editorTextureStage, self.editorSelectedTexture)
                if cube not in self.selectedCubes:
                    self.selectedCubes.append(cube)
            elif cube in self.selectedCubes:
                cube.clearTexture(self.editorTextureStage)
                self.selectedCubes.remove(cube)

    def selectCubeForCopy(self, qty = 1):
        cube, point, normal = self.selectCube()
        if not (cube and point and normal):
            return
        if self.selectedCubes:
            for c in self.selectedCubes:
                self.fps.level.copyCube(c, normal, qty)
            self.clearMultiSelectedCubes()
        else:
            self.fps.level.copyCube(cube, normal, qty)

    def selectCubeForDelete(self):
        cube, point, normal = self.selectCube()
        if not (cube and point and normal):
            return
        if self.selectedCubes:
            for c in self.selectedCubes:
                self.fps.level.deleteCube(c)
            self.clearMultiSelectedCubes()
        else:
            self.fps.level.deleteCube(cube)

    def selectCubeForChange(self, step = 1):
        cube, point, normal = self.selectCube()
        if not (cube and point and normal):
            return
        if self.selectedCubes:
            for c in self.selectedCubes:
                self.fps.level.changeCube(c, step)
        else:
            self.fps.level.changeCube(cube, step)

    def selectCubeForRectangle(self, makeRoom = False):
        cube, point, normal = self.selectCube()
        if makeRoom:
            self.fps.level.createRoom(cube, self.node) # creates a room from the selected cube to the player(camera) position
        else:
            self.fps.level.createRectangle(cube, self.node) # creates a rectangle from the selected cube to the player(camera) position

    def saveLevel(self):
        camerapos = [self.node.getX(), self.node.getY(), self.node.getZ()]
        levelname = self.fps.levelname
        self.fps.level.savelevel(levelname, camerapos)

    def addLightHere(self):
        camerapos = [self.node.getX(), self.node.getY(), self.node.getZ()]
        self.fps.level.addLightHere(camerapos)

    def moveInEditor(self,task):
        self.node.setPos(self.node, self.walk*globalClock.getDt()*self.speed)
        self.osd.updatePosition(self.node)
        return task.cont
class CogdoFlyingCameraManager:

    def __init__(self, cam, parent, player, level):
        self._toon = player.toon
        self._camera = cam
        self._parent = parent
        self._player = player
        self._level = level
        self._enabled = False

    def enable(self):
        if self._enabled:
            return
        self._toon.detachCamera()
        self._prevToonY = 0.0
        levelBounds = self._level.getBounds()
        l = Globals.Camera.LevelBoundsFactor
        self._bounds = ((levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]), (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]), (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2]))
        self._lookAtZ = self._toon.getHeight() + Globals.Camera.LookAtToonHeightOffset
        self._camParent = NodePath('CamParent')
        self._camParent.reparentTo(self._parent)
        self._camParent.setPos(self._toon, 0, 0, 0)
        self._camParent.setHpr(180, Globals.Camera.Angle, 0)
        self._camera.reparentTo(self._camParent)
        self._camera.setPos(0, Globals.Camera.Distance, 0)
        self._camera.lookAt(self._toon, 0, 0, self._lookAtZ)
        self._cameraLookAtNP = NodePath('CameraLookAt')
        self._cameraLookAtNP.reparentTo(self._camera.getParent())
        self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr())
        self._levelBounds = self._level.getBounds()
        self._enabled = True
        self._frozen = False
        self._initCollisions()

    def _initCollisions(self):
        self._camCollRay = CollisionRay()
        camCollNode = CollisionNode('CameraToonRay')
        camCollNode.addSolid(self._camCollRay)
        camCollNode.setFromCollideMask(OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask)
        camCollNode.setIntoCollideMask(0)
        self._camCollNP = self._camera.attachNewNode(camCollNode)
        self._camCollNP.show()
        self._collOffset = Vec3(0, 0, 0.5)
        self._collHandler = CollisionHandlerQueue()
        self._collTrav = CollisionTraverser()
        self._collTrav.addCollider(self._camCollNP, self._collHandler)
        self._betweenCamAndToon = {}
        self._transNP = NodePath('trans')
        self._transNP.reparentTo(render)
        self._transNP.setTransparency(True)
        self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon)
        self._transNP.setBin('fixed', 10000)

    def _destroyCollisions(self):
        self._collTrav.removeCollider(self._camCollNP)
        self._camCollNP.removeNode()
        del self._camCollNP
        del self._camCollRay
        del self._collHandler
        del self._collOffset
        del self._betweenCamAndToon
        self._transNP.removeNode()
        del self._transNP

    def freeze(self):
        self._frozen = True

    def unfreeze(self):
        self._frozen = False

    def disable(self):
        if not self._enabled:
            return
        self._destroyCollisions()
        self._camera.wrtReparentTo(render)
        self._cameraLookAtNP.removeNode()
        del self._cameraLookAtNP
        self._camParent.removeNode()
        del self._camParent
        del self._prevToonY
        del self._lookAtZ
        del self._bounds
        del self._frozen
        self._enabled = False

    def update(self, dt = 0.0):
        self._updateCam(dt)
        self._updateCollisions()

    def _updateCam(self, dt):
        toonPos = self._toon.getPos()
        camPos = self._camParent.getPos()
        x = camPos[0]
        z = camPos[2]
        toonWorldX = self._toon.getX(render)
        maxX = Globals.Camera.MaxSpinX
        toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX)
        spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (maxX * maxX)
        newH = 180.0 + spinAngle
        self._camParent.setH(newH)
        spinAngle = spinAngle * (pi / 180.0)
        distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle)
        distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle)
        d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0])
        if abs(d) > Globals.Camera.LeewayX:
            if d > Globals.Camera.LeewayX:
                x = toonPos[0] + Globals.Camera.LeewayX
            else:
                x = toonPos[0] - Globals.Camera.LeewayX
        x = self._toon.getX(render) + distToRightOfToon
        boundToonZ = min(toonPos[2], self._bounds[2][1])
        d = z - boundToonZ
        if d > Globals.Camera.MinLeewayZ:
            if self._player.velocity[2] >= 0 and toonPos[1] != self._prevToonY or self._player.velocity[2] > 0:
                z = boundToonZ + d * INVERSE_E ** (dt * Globals.Camera.CatchUpRateZ)
            elif d > Globals.Camera.MaxLeewayZ:
                z = boundToonZ + Globals.Camera.MaxLeewayZ
        elif d < -Globals.Camera.MinLeewayZ:
            z = boundToonZ - Globals.Camera.MinLeewayZ
        if self._frozen:
            y = camPos[1]
        else:
            y = self._toon.getY(render) - distBehindToon
        self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z))
        if toonPos[2] < self._bounds[2][1]:
            h = self._cameraLookAtNP.getH()
            if d >= Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ)
            elif d <= -Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ)
            self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0)
            self._camera.setHpr(smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr()))
        self._prevToonY = toonPos[1]

    def _updateCollisions(self):
        pos = self._toon.getPos(self._camera) + self._collOffset
        self._camCollRay.setOrigin(pos)
        direction = -Vec3(pos)
        direction.normalize()
        self._camCollRay.setDirection(direction)
        self._collTrav.traverse(render)
        nodesInBetween = {}
        if self._collHandler.getNumEntries() > 0:
            self._collHandler.sortEntries()
            for entry in self._collHandler.getEntries():
                name = entry.getIntoNode().getName()
                if name.find('col_') >= 0:
                    np = entry.getIntoNodePath().getParent()
                    if np not in nodesInBetween:
                        nodesInBetween[np] = np.getParent()

        for np in nodesInBetween.keys():
            if np in self._betweenCamAndToon:
                del self._betweenCamAndToon[np]
            else:
                np.setTransparency(True)
                np.wrtReparentTo(self._transNP)
                if np.getName().find('lightFixture') >= 0:
                    np.find('**/*floor_mesh').hide()
                elif np.getName().find('platform') >= 0:
                    np.find('**/*Floor').hide()

        for np, parent in self._betweenCamAndToon.items():
            np.wrtReparentTo(parent)
            np.setTransparency(False)
            if np.getName().find('lightFixture') >= 0:
                np.find('**/*floor_mesh').show()
            elif np.getName().find('platform') >= 0:
                np.find('**/*Floor').show()

        self._betweenCamAndToon = nodesInBetween