Ejemplo n.º 1
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
Ejemplo n.º 2
0
class HitscanWeapon(Weapon):
    def __init__(self, mask, damage, knockback, range=None):
        Weapon.__init__(self, mask, range, damage, knockback)

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

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

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

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

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

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

        self.traverser.traverse(render)

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

            return True, rayHit
        else:
            return False, None

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

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

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

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

        Weapon.cleanup(self)
class SmartCamera:
    UPDATE_TASK_NAME = 'update_smartcamera'
    notify = directNotify.newCategory('SmartCamera')

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

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

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

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

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

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

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

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

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

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

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

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

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

    def get_default_pos(self):
        return self.default_pos

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

    def get_parent(self):
        return self.parent

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    def handleCameraFloorInteraction(self):
        self.putCameraFloorRayOnCamera()
        self.ccTravFloor.traverse(self.__geom)
        if self.__onLevelGround:
            return
        if self.camFloorCollisionQueue.getNumEntries() == 0:
            return
        self.camFloorCollisionQueue.sortEntries()
        camObstrCollisionEntry = self.camFloorCollisionQueue.getEntry(0)
        camHeightFromFloor = camObstrCollisionEntry.getSurfacePoint(self.ccRayNodePath)[2]
        self.cameraZOffset = camera.getPos()[2] + camHeightFromFloor
        if self.cameraZOffset < 0:
            self.cameraZOffset = 0
        if self.__floorDetected == 0:
            self.__floorDetected = 1
            self.popCameraToDest()
Ejemplo n.º 4
0
class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.seeNode = self.render.attachNewNode("see")

        self.cam.reparentTo(self.seeNode)
        self.cam.setPos(0, 0, 5)

        self.fpscamera = fpscontroller.FpsController(self, self.seeNode)
        self.fpscamera.setFlyMode(True)

        self.prevPos = self.fpscamera.getPos()
        self.prevInto = None
        self.info = self.genLabelText("Position: <unknown>", 4)

        self.makeInstructions()
        self.initCollisions()

        self.leftColor = LVecBase4i(224, 224, 64, 255)
        self.rightColor = LVecBase4i(64, 224, 224, 255)

        self.isDrawing = False
        self.toggleDrawing()

        self.accept("escape", sys.exit)  # Escape quits
        self.accept("enter", self.toggleDrawing)

    def initCollisions(self):
        # Initialize the collision traverser.
        self.cTrav = CollisionTraverser()

        self.cTrav.showCollisions(self.render)

        #         self.cQueue = CollisionHandlerQueue()

        # Initialize the Pusher collision handler.
        # self.pusher = CollisionHandlerPusher()
        self.pusher = CollisionHandlerFloor()

        ### player

        print DirectNotifyGlobal.directNotify.getCategories()
        # Create a collsion node for this object.
        playerNode = CollisionNode("player")
        playerNode.addSolid(CollisionSphere(0, 0, 0, 1))

        #         playerNode.setFromCollideMask(BitMask32.bit(0))
        #         playerNode.setIntoCollideMask(BitMask32.allOn())

        # Attach the collision node to the object's model.
        self.playerC = self.fpscamera.player.attachNewNode(playerNode)
        # Set the object's collision node to render as visible.
        self.playerC.show()

        # Add the 'player' collision node to the Pusher collision handler.
        # self.pusher.addCollider(self.playerC, self.fpscamera.player)
        # self.pusher.addCollider(playerC, self.fpscamera.player)

    #         self.cTrav.addCollider(self.playerC, self.cQueue)

    def toggleDrawing(self):
        self.isDrawing = not self.isDrawing

        if self.isDrawing:
            self.drawText.setText("Enter: Turn off drawing")
            self.fpscamera.setFlyMode(True)
            self.prevPos = None

            self.cTrav.removeCollider(self.playerC)
            self.pusher.removeCollider(self.playerC)

            self.removeTask("updatePhysics")
            self.addTask(self.drawHere, "drawHere")

            self.geomNode = GeomNode("geomNode")
            self.geomNodePath = self.render.attachNewNode(self.geomNode)

            self.geomNodePath.setTwoSided(True)

            # apparently p3tinydisplay needs this
            self.geomNodePath.setColorOff()

            # Create a collision node for this object.
            self.floorCollNode = CollisionNode("geom")

            #             self.floorCollNode.setFromCollideMask(BitMask32.bit(0))
            #             self.floorCollNode.setIntoCollideMask(BitMask32.allOn())

            # Attach the collision node to the object's model.
            floorC = self.geomNodePath.attachNewNode(self.floorCollNode)
            # Set the object's collision node to render as visible.
            floorC.show()

            # self.pusher.addCollider(floorC, self.geomNodePath)

            self.newVertexData()

            self.newGeom()

        else:
            self.drawText.setText("Enter: Turn on drawing")
            self.removeTask("drawHere")
            if self.prevPos:
                self.completePath()

            self.fpscamera.setFlyMode(True)

            self.drive.setPos(self.fpscamera.getPos())

            self.cTrav.addCollider(self.playerC, self.pusher)
            self.pusher.addCollider(self.playerC, self.fpscamera.player)

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

    def newVertexData(self):
        fmt = GeomVertexFormat.getV3c4()
        #         fmt = GeomVertexFormat.getV3n3c4()
        self.vertexData = GeomVertexData("path", fmt, Geom.UHStatic)
        self.vertexWriter = GeomVertexWriter(self.vertexData, "vertex")
        #         self.normalWriter = GeomVertexWriter(self.vertexData, 'normal')
        self.colorWriter = GeomVertexWriter(self.vertexData, "color")

    def newGeom(self):
        self.triStrips = GeomTristrips(Geom.UHDynamic)
        self.geom = Geom(self.vertexData)
        self.geom.addPrimitive(self.triStrips)

    def makeInstructions(self):
        OnscreenText(text="Draw Path by Walking", style=1, fg=(1, 1, 0, 1), pos=(0.5, -0.95), scale=0.07)

        self.drawText = self.genLabelText("", 0)
        self.genLabelText("Walk (W/S/A/D), Jump=Space, Look=PgUp/PgDn", 1)
        self.genLabelText("  (hint, go backwards with S to see your path immediately)", 2)
        self.genLabelText("ESC: Quit", 3)

    def genLabelText(self, text, i):
        return OnscreenText(text=text, pos=(-1.3, 0.95 - 0.05 * i), fg=(1, 1, 0, 1), align=TextNode.ALeft, scale=0.05)

    def drawHere(self, task):
        pos = self.fpscamera.getPos()
        self.info.setText(
            "Position: {0}, {1}, {2} at {3} by {4}".format(
                int(pos.x * 100) / 100.0,
                int(pos.y * 100) / 100.0,
                int(pos.z) / 100.0,
                self.fpscamera.getHeading(),
                self.fpscamera.getLookAngle(),
            )
        )

        prevPos = self.prevPos

        if not prevPos:
            self.prevPos = pos

        elif (pos - prevPos).length() > 1:
            self.drawQuadTo(prevPos, pos, 2)

            row = self.vertexWriter.getWriteRow()
            numPrims = self.triStrips.getNumPrimitives()
            if numPrims == 0:
                primVerts = row
            else:
                primVerts = row - self.triStrips.getPrimitiveEnd(numPrims - 1)

            if primVerts >= 4:
                self.triStrips.closePrimitive()

                if row >= 256:
                    print "Packing and starting anew"
                    newGeom = True
                    self.geom.unifyInPlace(row, False)
                else:
                    newGeom = False

                self.completePath()

                if newGeom:
                    self.newVertexData()

                self.newGeom()
                if not newGeom:
                    self.triStrips.addConsecutiveVertices(row - 2, 2)
                else:
                    self.drawQuadTo(prevPos, pos, 2)

            self.leftColor[1] += 63
            self.rightColor[2] += 37

            self.prevPos = pos

        return task.cont

    def drawLineTo(self, pos, color):
        self.vertexWriter.addData3f(pos.x, pos.y, pos.z)
        #         self.normalWriter.addData3f(0, 0, 1)
        self.colorWriter.addData4i(color)

        self.triStrips.addNextVertices(1)

    def drawQuadTo(self, a, b, width):
        """ a (to) b are vectors defining a line bisecting a new quad. """
        into = b - a
        if abs(into.x) + abs(into.y) < 1:
            if not self.prevInto:
                return
            into = self.prevInto
            print into
        else:
            into.normalize()

        # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space

        if self.vertexWriter.getWriteRow() == 0:
            self.drawQuadRow(a, into, width)

        self.drawQuadRow(b, into, width)

        self.prevInto = into

    def drawQuadRow(self, a, into, width):
        """ a defines a point, with 'into' being the normalized direction. """

        # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space

        aLeft = Vec3(a.x - into.y * width, a.y + into.x * width, a.z)
        aRight = Vec3(a.x + into.y * width, a.y - into.x * width, a.z)

        row = self.vertexWriter.getWriteRow()

        self.vertexWriter.addData3f(aLeft)
        self.vertexWriter.addData3f(aRight)

        #         self.normalWriter.addData3f(Vec3(0, 0, 1))
        #         self.normalWriter.addData3f(Vec3(0, 0, 1))

        self.colorWriter.addData4i(self.leftColor)
        self.colorWriter.addData4i(self.rightColor)

        self.triStrips.addConsecutiveVertices(row, 2)

    def completePath(self):
        self.geomNode.addGeom(self.geom)

        if self.triStrips.getNumPrimitives() == 0:
            return

        floorMesh = CollisionFloorMesh()

        tris = self.triStrips.decompose()
        p = 0
        vertexReader = GeomVertexReader(self.vertexData, "vertex")
        for i in range(tris.getNumPrimitives()):
            v0 = tris.getPrimitiveStart(i)
            ve = tris.getPrimitiveEnd(i)
            if v0 < ve:
                vertexReader.setRow(tris.getVertex(v0))
                floorMesh.addVertex(Point3(vertexReader.getData3f()))
                vertexReader.setRow(tris.getVertex(v0 + 1))
                floorMesh.addVertex(Point3(vertexReader.getData3f()))
                vertexReader.setRow(tris.getVertex(v0 + 2))
                floorMesh.addVertex(Point3(vertexReader.getData3f()))
                floorMesh.addTriangle(p, p + 1, p + 2)
                p += 3

        self.floorCollNode.addSolid(floorMesh)

    def updatePhysics(self, task):
        pos = self.fpscamera.getPos()
        self.info.setText(
            "Position: {0}, {1}, {2}".format(int(pos.x * 100) / 100.0, int(pos.y * 100) / 100.0, int(pos.z) / 100.0)
        )
        return task.cont
Ejemplo n.º 5
0
class LevelEditor(DirectObject):
    notify = directNotify.newCategory("Foundry")

    DocActions = [
        KeyBind.FileSave, KeyBind.FileSaveAll, KeyBind.FileSaveAs,
        KeyBind.FileClose, KeyBind.FileCloseAll, KeyBind.Undo, KeyBind.Redo,
        KeyBind.ViewQuads, KeyBind.View3D, KeyBind.ViewXY, KeyBind.ViewYZ,
        KeyBind.ViewXZ, KeyBind.Toggle2DGrid, KeyBind.Toggle3DGrid,
        KeyBind.ToggleGridSnap, KeyBind.IncGridSize, KeyBind.DecGridSize
    ]

    def __init__(self):
        DirectObject.__init__(self)

        if ConfigVariableBool("want-pstats", False):
            PStatClient.connect()

        self.docTitle = ""
        self.viewportName = ""

        self.renderRequested = False

        ###################################################################
        # Minimal emulation of ShowBase glue code. Note we're not using
        # ShowBase because there's too much going on in there that assumes
        # too much (one camera, one lens, one aspect2d, lots of bloat).

        self.graphicsEngine = GraphicsEngine.getGlobalPtr()
        self.pipe = GraphicsPipeSelection.getGlobalPtr().makeDefaultPipe()
        if not self.pipe:
            self.notify.error("No graphics pipe is available!")
            return

        self.globalClock = ClockObject.getGlobalClock()
        # Since we have already started up a TaskManager, and probably
        # a number of tasks; and since the TaskManager had to use the
        # TrueClock to tell time until this moment, make sure the
        # globalClock object is exactly in sync with the TrueClock.
        trueClock = TrueClock.getGlobalPtr()
        self.globalClock.setRealTime(trueClock.getShortTime())
        self.globalClock.tick()
        builtins.globalClock = self.globalClock

        self.loader = CogInvasionLoader(self)
        self.graphicsEngine.setDefaultLoader(self.loader.loader)
        builtins.loader = self.loader

        self.taskMgr = taskMgr
        builtins.taskMgr = self.taskMgr

        self.dgTrav = DataGraphTraverser()

        self.dataRoot = NodePath("data")
        self.hidden = NodePath("hidden")

        self.aspect2d = NodePath("aspect2d")
        builtins.aspect2d = self.aspect2d

        # Messages that are sent regardless of the active document.
        self.messenger = messenger
        builtins.messenger = self.messenger

        builtins.base = self
        builtins.hidden = self.hidden

        ###################################################################

        self.clickTrav = CollisionTraverser()

        # All open documents.
        self.documents = []
        # The focused document.
        self.document = None

        TextNode.setDefaultFont(
            loader.loadFont("resources/models/fonts/consolas.ttf"))

        self.initialize()

    def requestRender(self):
        self.renderRequested = True

    def setWindowSubTitle(self, sub):
        title = LEGlobals.AppName
        if sub:
            title += " - " + sub
        self.qtWindow.setWindowTitle(title)

    def __docLoop(self):
        if self.document:
            self.document.step()

    def __gbcLoop(self):
        TransformState.garbageCollect()
        RenderState.garbageCollect()

    def __dataLoop(self):
        self.dgTrav.traverse(self.dataRoot.node())

    def __igLoop(self):
        if self.renderRequested:
            self.graphicsEngine.renderFrame()
            #self.graphicsEngine.syncFrame()
            #self.graphicsEngine.readyFlip()
            self.graphicsEngine.flipFrame()
            #self.graphicsEngine.openWindows()
            self.renderRequested = False
        else:
            #self.graphicsEngine.flipFrame()
            self.globalClock.tick()
            PStatClient.mainTick()
        throwNewFrame()

    def openDocument(self, filename):
        doc = Document()
        self.documents.append(doc)
        doc.page.showMaximized()
        doc.open(filename)
        doc.updateTabText()

        if len(self.documents) == 1:
            self.enableDocActions()

    def setActiveDoc(self, doc):
        if self.document:
            self.document.deactivated()
        self.document = doc
        if not doc:
            return
        doc.activated()
        doc.updateTabText()
        base.document = doc

    def reqCloseDocument(self, doc):
        return self.qtWindow.closeDoc(doc)

    def closeDocument(self, doc):
        doc.close()
        if doc == base.document:
            self.qtWindow.docArea.activateNextSubWindow()
        self.documents.remove(doc)
        if len(self.documents) == 0:
            self.disableDocActions()

    def enableDocActions(self):
        for act in self.DocActions:
            self.menuMgr.enableAction(act)

    def disableDocActions(self):
        for act in self.DocActions:
            self.menuMgr.disableAction(act)

    def clickTraverse(self, np, handler, travRoot=None):
        self.clickTrav.addCollider(np, handler)
        if not travRoot:
            travRoot = self.render
        self.clickTrav.traverse(travRoot)
        self.clickTrav.removeCollider(np)

    def snapToGrid(self, point):
        if GridSettings.GridSnap:
            return LEUtils.snapToGrid(GridSettings.DefaultStep, point)
        return point

    def initialize(self):
        self.loader.mountMultifiles()
        self.loader.mountMultifile("resources/mod.mf")

        self.fgd = FgdParse('resources/phase_14/etc/cio.fgd')
        self.qtApp = LevelEditorApp()
        self.qtWindow = self.qtApp.window
        self.menuMgr = MenuManager()
        self.menuMgr.addMenuItems()
        ToolManager.addToolActions()
        SelectionManager.addModeActions()
        self.qtWindow.initialize()
        # Open a blank document
        #self.openDocument(None)
        self.adjustGridText()
        self.brushMgr = BrushManager()
        self.modelBrowser = ModelBrowser(None)
        self.materialBrowser = MaterialBrowser(None)

        self.menuMgr.connect(KeyBind.ToggleGridSnap, self.__gridSnap)
        self.menuMgr.connect(KeyBind.IncGridSize, self.__incGridSize)
        self.menuMgr.connect(KeyBind.DecGridSize, self.__decGridSize)
        self.menuMgr.connect(KeyBind.Toggle2DGrid, self.__toggleGrid)
        self.menuMgr.connect(KeyBind.Toggle3DGrid, self.__toggleGrid3D)
        self.menuMgr.connect(KeyBind.ViewQuads, self.__viewQuads)
        self.menuMgr.connect(KeyBind.View3D, self.__view3D)
        self.menuMgr.connect(KeyBind.ViewXY, self.__viewXY)
        self.menuMgr.connect(KeyBind.ViewXZ, self.__viewXZ)
        self.menuMgr.connect(KeyBind.ViewYZ, self.__viewYZ)

        self.menuMgr.action(KeyBind.ToggleGridSnap).setChecked(
            GridSettings.GridSnap)
        self.menuMgr.action(KeyBind.Toggle2DGrid).setChecked(
            GridSettings.EnableGrid)
        self.menuMgr.action(KeyBind.Toggle3DGrid).setChecked(
            GridSettings.EnableGrid3D)

        self.brushMgr.addBrushes()

    def __viewQuads(self):
        self.document.page.arrangeInQuadLayout()

    def __view3D(self):
        self.document.page.focusOnViewport(VIEWPORT_3D)

    def __viewXY(self):
        self.document.page.focusOnViewport(VIEWPORT_2D_TOP)

    def __viewYZ(self):
        self.document.page.focusOnViewport(VIEWPORT_2D_SIDE)

    def __viewXZ(self):
        self.document.page.focusOnViewport(VIEWPORT_2D_FRONT)

    def __gridSnap(self):
        GridSettings.GridSnap = not GridSettings.GridSnap
        self.adjustGridText()

    def __toggleGrid(self):
        GridSettings.EnableGrid = not GridSettings.EnableGrid
        self.adjustGridText()
        self.document.update2DViews()

    def __toggleGrid3D(self):
        GridSettings.EnableGrid3D = not GridSettings.EnableGrid3D
        self.adjustGridText()
        self.document.update3DViews()

    def __incGridSize(self):
        GridSettings.DefaultStep *= 2
        GridSettings.DefaultStep = min(256, GridSettings.DefaultStep)
        self.adjustGridText()
        self.document.updateAllViews()

    def __decGridSize(self):
        GridSettings.DefaultStep //= 2
        GridSettings.DefaultStep = max(1, GridSettings.DefaultStep)
        self.adjustGridText()
        self.document.updateAllViews()

    def adjustGridText(self):
        text = "Snap: %s Grid: %i" % ("On" if GridSettings.GridSnap else "Off",
                                      GridSettings.DefaultStep)
        self.qtApp.window.gridSnapLabel.setText(text)

    def run(self):
        self.running = True
        while self.running:
            fr = globalClock.getAverageFrameRate()
            dt = globalClock.getDt()
            self.qtWindow.fpsLabel.setText("%.2f ms / %i fps" %
                                           (dt * 1000, fr))
            self.qtApp.processEvents()
            self.__gbcLoop()
            self.__dataLoop()
            self.__docLoop()
            self.taskMgr.step()
            self.__igLoop()
Ejemplo n.º 6
0
class LevelEditor(HostBase):
    notify = directNotify.newCategory("Foundry")

    DocActions = [
        KeyBind.FileSave, KeyBind.FileSaveAll, KeyBind.FileSaveAs,
        KeyBind.FileClose, KeyBind.FileCloseAll, KeyBind.Undo, KeyBind.Redo,
        KeyBind.ViewQuads, KeyBind.View3D, KeyBind.ViewXY, KeyBind.ViewYZ,
        KeyBind.ViewXZ, KeyBind.Toggle2DGrid, KeyBind.Toggle3DGrid,
        KeyBind.ToggleGridSnap, KeyBind.IncGridSize, KeyBind.DecGridSize
    ]

    def __init__(self):
        self.gotLocalConfig = False

        HostBase.__init__(self)

        self.docTitle = ""
        self.viewportName = ""

        self.renderRequested = False

        ###################################################################
        # Minimal emulation of ShowBase glue code. Note we're not using
        # ShowBase because there's too much going on in there that assumes
        # too much (one camera, one lens, one aspect2d, lots of bloat).

        self.graphicsEngine = GraphicsEngine.getGlobalPtr()
        self.pipe = GraphicsPipeSelection.getGlobalPtr().makeDefaultPipe()
        if not self.pipe:
            self.notify.error("No graphics pipe is available!")
            return

        self.dgTrav = DataGraphTraverser()

        self.dataRoot = NodePath("data")
        self.hidden = NodePath("hidden")

        self.aspect2d = NodePath("aspect2d")
        builtins.aspect2d = self.aspect2d

        builtins.hidden = self.hidden

        ###################################################################

        self.clickTrav = CollisionTraverser()

        # All open documents.
        self.documents = []
        # The focused document.
        self.document = None

        TextNode.setDefaultFont(
            loader.loadFont("resources/models/fonts/consolas.ttf"))

    def requestRender(self):
        self.renderRequested = True

    def setWindowSubTitle(self, sub):
        title = LEGlobals.AppName
        if sub:
            title += " - " + sub
        self.qtWindow.setWindowTitle(title)

    def __docLoop(self):
        if self.document:
            self.document.step()

    def __gbcLoop(self):
        TransformState.garbageCollect()
        RenderState.garbageCollect()

    def __dataLoop(self):
        self.dgTrav.traverse(self.dataRoot.node())

    def __igLoop(self):
        if self.renderRequested:
            self.graphicsEngine.renderFrame()
            #self.graphicsEngine.syncFrame()
            #self.graphicsEngine.readyFlip()
            self.graphicsEngine.flipFrame()
            #self.graphicsEngine.openWindows()
            self.renderRequested = False
        else:
            #self.graphicsEngine.flipFrame()
            self.globalClock.tick()
            PStatClient.mainTick()
        throwNewFrame()

    def openDocument(self, filename):
        doc = Document()
        self.documents.append(doc)
        doc.page.showMaximized()
        doc.open(filename)
        doc.updateTabText()

        if len(self.documents) == 1:
            self.enableDocActions()
            self.materialPanel.show()

    def setActiveDoc(self, doc):
        if self.document:
            self.document.deactivated()
        self.document = doc
        if not doc:
            return
        doc.activated()
        doc.updateTabText()
        base.document = doc

    def reqCloseDocument(self, doc):
        return self.qtWindow.closeDoc(doc)

    def closeDocument(self, doc):
        doc.close()
        if doc == base.document:
            self.qtWindow.docArea.activateNextSubWindow()
        self.documents.remove(doc)
        if len(self.documents) == 0:
            self.disableDocActions()
            self.materialPanel.hide()

    def enableDocActions(self):
        for act in self.DocActions:
            self.menuMgr.enableAction(act)

    def disableDocActions(self):
        for act in self.DocActions:
            self.menuMgr.disableAction(act)

    def clickTraverse(self, np, handler, travRoot=None):
        self.clickTrav.addCollider(np, handler)
        if not travRoot:
            travRoot = self.render
        self.clickTrav.traverse(travRoot)
        self.clickTrav.removeCollider(np)

    def snapToGrid(self, point):
        if GridSettings.GridSnap:
            return LEUtils.snapToGrid(GridSettings.DefaultStep, point)
        return point

    def loadDefaultConfig(self):
        HostBase.loadDefaultConfig(self)

        data = """
        bounds-type box
        """

        self.loadDefaultPRCData("leveleditor", data)

    def loadLocalConfig(self):
        HostBase.loadLocalConfig(self)
        ret = self.loadLocalPRCFile("leveleditor")
        if ret:
            self.gotLocalConfig = True

    def loadFGDFiles(self):
        """Reads the .fgd files specified in the config file"""

        self.fgd = Fgd()
        numVals = LEConfig.fgd_files.getNumUniqueValues()

        if numVals == 0:
            QtWidgets.QMessageBox.critical(
                None, LEGlobals.AppName,
                "No FGD files specified in local config!",
                QtWidgets.QMessageBox.Ok)
            sys.exit(1)

        for i in range(numVals):
            fgdFilename = LEConfig.fgd_files.getUniqueValue(i)
            fgd = FgdParse(fgdFilename)
            self.fgd.add_include(fgd)

    def startup(self):
        HostBase.startup(self)

        #self.loader.mountMultifiles()
        #self.loader.mountMultifile("resources/mod.mf")

        self.qtApp = LevelEditorApp()
        self.qtWindow = self.qtApp.window

        if not self.gotLocalConfig:
            QtWidgets.QMessageBox.critical(
                None, LEGlobals.AppName,
                "Local config file not found. Please make sure that "
                "etc/leveleditor.prc exists on your working directory or "
                "search path.")
            sys.exit(1)

        self.loadFGDFiles()

        self.menuMgr = MenuManager()
        self.menuMgr.addMenuItems()
        ToolManager.addToolActions()
        SelectionManager.addModeActions()
        self.qtWindow.initialize()
        # Open a blank document
        #self.openDocument(None)
        self.adjustGridText()
        self.brushMgr = BrushManager()
        self.modelBrowser = ModelBrowser(None)
        self.materialBrowser = MaterialBrowser(None)
        self.materialPanel = ActiveMaterialPanel()

        self.menuMgr.connect(KeyBind.ToggleGridSnap, self.__gridSnap)
        self.menuMgr.connect(KeyBind.IncGridSize, self.__incGridSize)
        self.menuMgr.connect(KeyBind.DecGridSize, self.__decGridSize)
        self.menuMgr.connect(KeyBind.Toggle2DGrid, self.__toggleGrid)
        self.menuMgr.connect(KeyBind.Toggle3DGrid, self.__toggleGrid3D)
        self.menuMgr.connect(KeyBind.ViewQuads, self.__viewQuads)
        self.menuMgr.connect(KeyBind.View3D, self.__view3D)
        self.menuMgr.connect(KeyBind.ViewXY, self.__viewXY)
        self.menuMgr.connect(KeyBind.ViewXZ, self.__viewXZ)
        self.menuMgr.connect(KeyBind.ViewYZ, self.__viewYZ)

        self.menuMgr.action(KeyBind.ToggleGridSnap).setChecked(
            GridSettings.GridSnap)
        self.menuMgr.action(KeyBind.Toggle2DGrid).setChecked(
            GridSettings.EnableGrid)
        self.menuMgr.action(KeyBind.Toggle3DGrid).setChecked(
            GridSettings.EnableGrid3D)

        self.brushMgr.addBrushes()

        # Set the default active material here
        MaterialPool.setActiveMaterial(
            MaterialPool.getMaterial(LEConfig.default_material.getValue()))

    def __viewQuads(self):
        self.document.page.arrangeInQuadLayout()

    def __view3D(self):
        self.document.page.focusOnViewport(VIEWPORT_3D)

    def __viewXY(self):
        self.document.page.focusOnViewport(VIEWPORT_2D_TOP)

    def __viewYZ(self):
        self.document.page.focusOnViewport(VIEWPORT_2D_SIDE)

    def __viewXZ(self):
        self.document.page.focusOnViewport(VIEWPORT_2D_FRONT)

    def __gridSnap(self):
        GridSettings.GridSnap = not GridSettings.GridSnap
        self.adjustGridText()

    def __toggleGrid(self):
        GridSettings.EnableGrid = not GridSettings.EnableGrid
        self.adjustGridText()
        self.document.update2DViews()

    def __toggleGrid3D(self):
        GridSettings.EnableGrid3D = not GridSettings.EnableGrid3D
        self.adjustGridText()
        self.document.update3DViews()

    def __incGridSize(self):
        GridSettings.DefaultStep *= 2
        GridSettings.DefaultStep = min(256, GridSettings.DefaultStep)
        self.adjustGridText()
        self.document.updateAllViews()

    def __decGridSize(self):
        GridSettings.DefaultStep //= 2
        GridSettings.DefaultStep = max(1, GridSettings.DefaultStep)
        self.adjustGridText()
        self.document.updateAllViews()

    def adjustGridText(self):
        text = "Snap: %s Grid: %i" % ("On" if GridSettings.GridSnap else "Off",
                                      GridSettings.DefaultStep)
        self.qtApp.window.gridSnapLabel.setText(text)

    def preRunFrame(self):
        fr = globalClock.getAverageFrameRate()
        dt = globalClock.getDt()
        self.qtWindow.fpsLabel.setText("%.2f ms / %i fps" % (dt * 1000, fr))
        self.qtApp.processEvents()
        self.__gbcLoop()
        self.__dataLoop()
        self.__docLoop()

    def postRunFrame(self):
        self.__igLoop()
Ejemplo n.º 7
0
class CellManager(object):
    """Creates a collision ray and collision traverser to use for
    selecting the current cell."""
    def __init__(self, game):
        self.game = game
        self.cells = {}
        self.cells_by_collider = {}
        self.cell_picker_world = NodePath('cell_picker_world')
        self.ray = CollisionRay()
        self.ray.setDirection(LVector3.down())
        cnode = CollisionNode('cell_raycast_cnode')
        self.ray_nodepath = self.cell_picker_world.attachNewNode(cnode)
        self.ray_nodepath.node().addSolid(self.ray)
        self.ray_nodepath.node().setIntoCollideMask(
            0)  # not for colliding into
        self.ray_nodepath.node().setFromCollideMask(1)
        self.traverser = CollisionTraverser('traverser')
        self.last_known_cell = None

    def add_cell(self, collider, name):
        """Add a new cell."""
        cell = Cell(self, name, collider)
        self.cells[name] = cell
        self.cells_by_collider[collider.node()] = cell

    def get_cell(self, pos):
        """Given a position, return the nearest cell below that position.
        If no cell is found, returns None."""
        self.ray.setOrigin(pos)
        queue = CollisionHandlerQueue()
        self.traverser.addCollider(self.ray_nodepath, queue)
        self.traverser.traverse(self.cell_picker_world)
        self.traverser.removeCollider(self.ray_nodepath)
        queue.sortEntries()
        if not queue.getNumEntries():
            return None
        entry = queue.getEntry(0)
        cnode = entry.getIntoNode()
        try:
            return self.cells_by_collider[cnode]
        except KeyError:
            raise Warning('collision ray collided with something '
                          'other than a cell: %s' % cnode)

    def get_dist_to_cell(self, pos):
        """Given a position, return the distance to the nearest cell
        below that position. If no cell is found, returns None."""
        self.ray.setOrigin(pos)
        queue = CollisionHandlerQueue()
        self.traverser.addCollider(self.ray_nodepath, queue)
        self.traverser.traverse(self.cell_picker_world)
        self.traverser.removeCollider(self.ray_nodepath)
        queue.sortEntries()
        if not queue.getNumEntries():
            return None
        entry = queue.getEntry(0)
        return (entry.getSurfacePoint(self.cell_picker_world) - pos).length()

    def load_cells_from_model(self, modelpath):
        """Loads cells from an EGG file. Cells must be named in the
        format "cell#" to be loaded by this function."""
        cell_model = self.game.loader.loadModel(modelpath)
        for collider in cell_model.findAllMatches('**/+GeomNode'):
            name = collider.getName()
            if name.startswith('cell'):
                self.add_cell(collider, name[4:])
        cell_model.removeNode()

    def load_portals_from_model(self, modelpath):
        """Loads portals from an EGG file. Portals must be named in the
        format "portal_#to#_*" to be loaded by this function, whereby the
        first # is the from cell, the second # is the into cell, and * can
        be anything."""
        portal_model = loader.loadModel(modelpath)
        portal_nodepaths = portal_model.findAllMatches('**/+PortalNode')
        for portal_nodepath in portal_nodepaths:
            name = portal_nodepath.getName()
            if name.startswith('portal_'):
                from_cell_id, into_cell_id = name.split('_')[1].split('to')
                try:
                    from_cell = self.cells[from_cell_id]
                except KeyError:
                    print('could not load portal "%s" because cell "%s"'
                          'does not exist' % (name, from_cell_id))
                    continue
                try:
                    into_cell = self.cells[into_cell_id]
                except KeyError:
                    print('could not load portal "%s" because cell "%s"'
                          'does not exist' % (name, into_cell_id))
                    continue
                from_cell.add_portal(portal_nodepath, into_cell)
        portal_model.removeNode()

    def update(self):
        """Show the cell the camera is currently in and hides the rest.
        If the camera is not in a cell, use the last known cell that the
        camera was in. If the camera has not yet been in a cell, then all
        cells will be hidden."""
        camera_pos = self.game.camera.getPos(self.game.render)
        for cell in self.cells:
            self.cells[cell].nodepath.hide()
        current_cell = self.get_cell(camera_pos)
        if current_cell is None:
            if self.last_known_cell is None:
                return
            self.last_known_cell.nodepath.show()
        else:
            self.last_known_cell = current_cell
            current_cell.nodepath.show()
Ejemplo n.º 8
0
class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.seeNode = self.render.attachNewNode('see')

        self.cam.reparentTo(self.seeNode)
        self.cam.setPos(0, 0, 5)

        self.fpscamera = fpscontroller.FpsController(self, self.seeNode)
        self.fpscamera.setFlyMode(True)

        self.prevPos = self.fpscamera.getPos()
        self.prevInto = None
        self.info = self.genLabelText("Position: <unknown>", 4)

        self.makeInstructions()
        self.initCollisions()

        self.leftColor = LVecBase4i(224, 224, 64, 255)
        self.rightColor = LVecBase4i(64, 224, 224, 255)

        self.isDrawing = False
        self.toggleDrawing()

        self.accept("escape", sys.exit)  #Escape quits
        self.accept("enter", self.toggleDrawing)

    def initCollisions(self):
        # Initialize the collision traverser.
        self.cTrav = CollisionTraverser()

        self.cTrav.showCollisions(self.render)

        #         self.cQueue = CollisionHandlerQueue()

        # Initialize the Pusher collision handler.
        #self.pusher = CollisionHandlerPusher()
        self.pusher = CollisionHandlerFloor()

        ### player

        print DirectNotifyGlobal.directNotify.getCategories()
        # Create a collsion node for this object.
        playerNode = CollisionNode('player')
        playerNode.addSolid(CollisionSphere(0, 0, 0, 1))

        #         playerNode.setFromCollideMask(BitMask32.bit(0))
        #         playerNode.setIntoCollideMask(BitMask32.allOn())

        # Attach the collision node to the object's model.
        self.playerC = self.fpscamera.player.attachNewNode(playerNode)
        # Set the object's collision node to render as visible.
        self.playerC.show()

        # Add the 'player' collision node to the Pusher collision handler.
        #self.pusher.addCollider(self.playerC, self.fpscamera.player)
        #self.pusher.addCollider(playerC, self.fpscamera.player)


#         self.cTrav.addCollider(self.playerC, self.cQueue)

    def toggleDrawing(self):
        self.isDrawing = not self.isDrawing

        if self.isDrawing:
            self.drawText.setText("Enter: Turn off drawing")
            self.fpscamera.setFlyMode(True)
            self.prevPos = None

            self.cTrav.removeCollider(self.playerC)
            self.pusher.removeCollider(self.playerC)

            self.removeTask('updatePhysics')
            self.addTask(self.drawHere, 'drawHere')

            self.geomNode = GeomNode('geomNode')
            self.geomNodePath = self.render.attachNewNode(self.geomNode)

            self.geomNodePath.setTwoSided(True)

            # apparently p3tinydisplay needs this
            self.geomNodePath.setColorOff()

            # Create a collision node for this object.
            self.floorCollNode = CollisionNode('geom')

            #             self.floorCollNode.setFromCollideMask(BitMask32.bit(0))
            #             self.floorCollNode.setIntoCollideMask(BitMask32.allOn())

            # Attach the collision node to the object's model.
            floorC = self.geomNodePath.attachNewNode(self.floorCollNode)
            # Set the object's collision node to render as visible.
            floorC.show()

            #self.pusher.addCollider(floorC, self.geomNodePath)

            self.newVertexData()

            self.newGeom()

        else:
            self.drawText.setText("Enter: Turn on drawing")
            self.removeTask('drawHere')
            if self.prevPos:
                self.completePath()

            self.fpscamera.setFlyMode(True)

            self.drive.setPos(self.fpscamera.getPos())

            self.cTrav.addCollider(self.playerC, self.pusher)
            self.pusher.addCollider(self.playerC, self.fpscamera.player)

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

    def newVertexData(self):
        fmt = GeomVertexFormat.getV3c4()
        #         fmt = GeomVertexFormat.getV3n3c4()
        self.vertexData = GeomVertexData("path", fmt, Geom.UHStatic)
        self.vertexWriter = GeomVertexWriter(self.vertexData, 'vertex')
        #         self.normalWriter = GeomVertexWriter(self.vertexData, 'normal')
        self.colorWriter = GeomVertexWriter(self.vertexData, 'color')

    def newGeom(self):
        self.triStrips = GeomTristrips(Geom.UHDynamic)
        self.geom = Geom(self.vertexData)
        self.geom.addPrimitive(self.triStrips)

    def makeInstructions(self):
        OnscreenText(text="Draw Path by Walking",
                     style=1,
                     fg=(1, 1, 0, 1),
                     pos=(0.5, -0.95),
                     scale=.07)

        self.drawText = self.genLabelText("", 0)
        self.genLabelText("Walk (W/S/A/D), Jump=Space, Look=PgUp/PgDn", 1)
        self.genLabelText(
            "  (hint, go backwards with S to see your path immediately)", 2)
        self.genLabelText("ESC: Quit", 3)

    def genLabelText(self, text, i):
        return OnscreenText(text=text,
                            pos=(-1.3, .95 - .05 * i),
                            fg=(1, 1, 0, 1),
                            align=TextNode.ALeft,
                            scale=.05)

    def drawHere(self, task):
        pos = self.fpscamera.getPos()
        self.info.setText("Position: {0}, {1}, {2} at {3} by {4}".format(
            int(pos.x * 100) / 100.,
            int(pos.y * 100) / 100.,
            int(pos.z) / 100., self.fpscamera.getHeading(),
            self.fpscamera.getLookAngle()))

        prevPos = self.prevPos

        if not prevPos:
            self.prevPos = pos

        elif (pos - prevPos).length() > 1:
            self.drawQuadTo(prevPos, pos, 2)

            row = self.vertexWriter.getWriteRow()
            numPrims = self.triStrips.getNumPrimitives()
            if numPrims == 0:
                primVerts = row
            else:
                primVerts = row - self.triStrips.getPrimitiveEnd(numPrims - 1)

            if primVerts >= 4:
                self.triStrips.closePrimitive()

                if row >= 256:
                    print "Packing and starting anew"
                    newGeom = True
                    self.geom.unifyInPlace(row, False)
                else:
                    newGeom = False

                self.completePath()

                if newGeom:
                    self.newVertexData()

                self.newGeom()
                if not newGeom:
                    self.triStrips.addConsecutiveVertices(row - 2, 2)
                else:
                    self.drawQuadTo(prevPos, pos, 2)

            self.leftColor[1] += 63
            self.rightColor[2] += 37

            self.prevPos = pos

        return task.cont

    def drawLineTo(self, pos, color):
        self.vertexWriter.addData3f(pos.x, pos.y, pos.z)
        #         self.normalWriter.addData3f(0, 0, 1)
        self.colorWriter.addData4i(color)

        self.triStrips.addNextVertices(1)

    def drawQuadTo(self, a, b, width):
        """ a (to) b are vectors defining a line bisecting a new quad. """
        into = (b - a)
        if abs(into.x) + abs(into.y) < 1:
            if not self.prevInto:
                return
            into = self.prevInto
            print into
        else:
            into.normalize()

        # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space

        if self.vertexWriter.getWriteRow() == 0:
            self.drawQuadRow(a, into, width)

        self.drawQuadRow(b, into, width)

        self.prevInto = into

    def drawQuadRow(self, a, into, width):
        """ a defines a point, with 'into' being the normalized direction. """

        # the perpendicular of (a,b) is (-b,a); we want the path to be "flat" in Z=space

        aLeft = Vec3(a.x - into.y * width, a.y + into.x * width, a.z)
        aRight = Vec3(a.x + into.y * width, a.y - into.x * width, a.z)

        row = self.vertexWriter.getWriteRow()

        self.vertexWriter.addData3f(aLeft)
        self.vertexWriter.addData3f(aRight)

        #         self.normalWriter.addData3f(Vec3(0, 0, 1))
        #         self.normalWriter.addData3f(Vec3(0, 0, 1))

        self.colorWriter.addData4i(self.leftColor)
        self.colorWriter.addData4i(self.rightColor)

        self.triStrips.addConsecutiveVertices(row, 2)

    def completePath(self):
        self.geomNode.addGeom(self.geom)

        if self.triStrips.getNumPrimitives() == 0:
            return

        floorMesh = CollisionFloorMesh()

        tris = self.triStrips.decompose()
        p = 0
        vertexReader = GeomVertexReader(self.vertexData, 'vertex')
        for i in range(tris.getNumPrimitives()):
            v0 = tris.getPrimitiveStart(i)
            ve = tris.getPrimitiveEnd(i)
            if v0 < ve:
                vertexReader.setRow(tris.getVertex(v0))
                floorMesh.addVertex(Point3(vertexReader.getData3f()))
                vertexReader.setRow(tris.getVertex(v0 + 1))
                floorMesh.addVertex(Point3(vertexReader.getData3f()))
                vertexReader.setRow(tris.getVertex(v0 + 2))
                floorMesh.addVertex(Point3(vertexReader.getData3f()))
                floorMesh.addTriangle(p, p + 1, p + 2)
                p += 3

        self.floorCollNode.addSolid(floorMesh)

    def updatePhysics(self, task):
        pos = self.fpscamera.getPos()
        self.info.setText("Position: {0}, {1}, {2}".format(
            int(pos.x * 100) / 100.,
            int(pos.y * 100) / 100.,
            int(pos.z) / 100.))
        return task.cont
Ejemplo n.º 9
0
class CellManager(object):
    """Creates a collision ray and collision traverser to use for
    selecting the current cell."""
    def __init__(self, game):
        self.game = game
        self.cells = {}
        self.cells_by_collider = {}
        self.cell_picker_world = NodePath('cell_picker_world')
        self.ray = CollisionRay()
        self.ray.setDirection(LVector3.down())
        cnode = CollisionNode('cell_raycast_cnode')
        self.ray_nodepath = self.cell_picker_world.attachNewNode(cnode)
        self.ray_nodepath.node().addSolid(self.ray)
        self.ray_nodepath.node().setIntoCollideMask(0) # not for colliding into
        self.ray_nodepath.node().setFromCollideMask(1)
        self.traverser = CollisionTraverser('traverser')
        self.last_known_cell = None

    def add_cell(self, collider, name):
        """Add a new cell."""
        cell = Cell(self, name, collider)
        self.cells[name] = cell
        self.cells_by_collider[collider.node()] = cell

    def get_cell(self, pos):
        """Given a position, return the nearest cell below that position.
        If no cell is found, returns None."""
        self.ray.setOrigin(pos)
        queue = CollisionHandlerQueue()
        self.traverser.addCollider(self.ray_nodepath, queue)
        self.traverser.traverse(self.cell_picker_world)
        self.traverser.removeCollider(self.ray_nodepath)
        queue.sortEntries()
        if not queue.getNumEntries():
            return None
        entry = queue.getEntry(0)
        cnode = entry.getIntoNode()
        try:
            return self.cells_by_collider[cnode]
        except KeyError:
            raise Warning('collision ray collided with something '
                          'other than a cell: %s' % cnode)

    def get_dist_to_cell(self, pos):
        """Given a position, return the distance to the nearest cell
        below that position. If no cell is found, returns None."""
        self.ray.setOrigin(pos)
        queue = CollisionHandlerQueue()
        self.traverser.addCollider(self.ray_nodepath, queue)
        self.traverser.traverse(self.cell_picker_world)
        self.traverser.removeCollider(self.ray_nodepath)
        queue.sortEntries()
        if not queue.getNumEntries():
            return None
        entry = queue.getEntry(0)
        return (entry.getSurfacePoint(self.cell_picker_world) - pos).length()

    def load_cells_from_model(self, modelpath):
        """Loads cells from an EGG file. Cells must be named in the
        format "cell#" to be loaded by this function."""
        cell_model = self.game.loader.loadModel(modelpath)
        for collider in cell_model.findAllMatches('**/+GeomNode'):
            name = collider.getName()
            if name.startswith('cell'):
                self.add_cell(collider, name[4:])
        cell_model.removeNode()

    def load_portals_from_model(self, modelpath):
        """Loads portals from an EGG file. Portals must be named in the
        format "portal_#to#_*" to be loaded by this function, whereby the
        first # is the from cell, the second # is the into cell, and * can
        be anything."""
        portal_model = loader.loadModel(modelpath)
        portal_nodepaths = portal_model.findAllMatches('**/+PortalNode')
        for portal_nodepath in portal_nodepaths:
            name = portal_nodepath.getName()
            if name.startswith('portal_'):
                from_cell_id, into_cell_id = name.split('_')[1].split('to')
                try:
                    from_cell = self.cells[from_cell_id]
                except KeyError:
                    print ('could not load portal "%s" because cell "%s"'
                           'does not exist' % (name, from_cell_id))
                    continue
                try:
                    into_cell = self.cells[into_cell_id]
                except KeyError:
                    print ('could not load portal "%s" because cell "%s"'
                           'does not exist' % (name, into_cell_id))
                    continue
                from_cell.add_portal(portal_nodepath, into_cell)
        portal_model.removeNode()

    def update(self):
        """Show the cell the camera is currently in and hides the rest.
        If the camera is not in a cell, use the last known cell that the
        camera was in. If the camera has not yet been in a cell, then all
        cells will be hidden."""
        camera_pos = self.game.camera.getPos(self.game.render)
        for cell in self.cells:
            self.cells[cell].nodepath.hide()
        current_cell = self.get_cell(camera_pos)
        if current_cell is None:
            if self.last_known_cell is None:
                return
            self.last_known_cell.nodepath.show()
        else:
            self.last_known_cell = current_cell
            current_cell.nodepath.show()
Ejemplo n.º 10
0
class CollisionChecker(object):
    """
    A fast collision checker that allows maximum 32 collision pairs
    author: weiwei
    date: 20201214osaka
    """
    def __init__(self, name="auto"):
        self.ctrav = CollisionTraverser()
        self.chan = CollisionHandlerQueue()
        self.np = NodePath(name)
        self.bitmask_list = [BitMask32(2**n) for n in range(31)]
        self._bitmask_ext = BitMask32(
            2**31)  # 31 is prepared for cd with external non-active objects
        self.all_cdelements = [
        ]  # a list of cdlnks or cdobjs for quick accessing the cd elements (cdlnks/cdobjs)

    def add_cdlnks(self, jlcobj, lnk_idlist):
        """
        The collision node of the given links will be attached to self.np, but their collision bitmask will be cleared
        When the a robot_s is treated as an obstacle by another robot_s, the IntoCollideMask of its all_cdelements will be
        set to BitMask32(2**31), so that the other robot_s can compare its active_cdelements with the all_cdelements.
        :param jlcobj:
        :param lnk_idlist:
        :return:
        author: weiwei
        date: 20201216toyonaka
        """
        for id in lnk_idlist:
            if jlcobj.lnks[id]['cdprimit_childid'] == -1:  # first time add
                cdnp = jlcobj.lnks[id]['collision_model'].copy_cdnp_to(
                    self.np, clearmask=True)
                self.ctrav.addCollider(cdnp, self.chan)
                self.all_cdelements.append(jlcobj.lnks[id])
                jlcobj.lnks[id]['cdprimit_childid'] = len(
                    self.all_cdelements) - 1
            else:
                raise ValueError("The link is already added!")

    def set_active_cdlnks(self, activelist):
        """
        The specified collision links will be used for collision detection with external obstacles
        :param activelist: essentially a from list like [jlchain.lnk0, jlchain.lnk1...]
                           the correspondent tolist will be set online in cd functions
                           TODO use all elements in self.all_cdnlks if None
        :return:
        author: weiwei
        date: 20201216toyonaka
        """
        for cdlnk in activelist:
            if cdlnk['cdprimit_childid'] == -1:
                raise ValueError(
                    "The link needs to be added to collider using the add_cdlnks function first!"
                )
            cdnp = self.np.getChild(cdlnk['cdprimit_childid'])
            cdnp.node().setFromCollideMask(self._bitmask_ext)

    def set_cdpair(self, fromlist, intolist):
        """
        The given collision pair will be used for self collision detection
        :param fromlist: [[bool, cdprimit_cache], ...]
        :param intolist: [[bool, cdprimit_cache], ...]
        :return:
        author: weiwei
        date: 20201215
        """
        if len(self.bitmask_list) == 0:
            raise ValueError("Too many collision pairs! Maximum: 29")
        allocated_bitmask = self.bitmask_list.pop()
        for cdlnk in fromlist:
            if cdlnk['cdprimit_childid'] == -1:
                raise ValueError(
                    "The link needs to be added to collider using the addjlcobj function first!"
                )
            cdnp = self.np.getChild(cdlnk['cdprimit_childid'])
            current_from_cdmask = cdnp.node().getFromCollideMask()
            new_from_cdmask = current_from_cdmask | allocated_bitmask
            cdnp.node().setFromCollideMask(new_from_cdmask)
        for cdlnk in intolist:
            if cdlnk['cdprimit_childid'] == -1:
                raise ValueError(
                    "The link needs to be added to collider using the addjlcobj function first!"
                )
            cdnp = self.np.getChild(cdlnk['cdprimit_childid'])
            current_into_cdmask = cdnp.node().getIntoCollideMask()
            new_into_cdmask = current_into_cdmask | allocated_bitmask
            cdnp.node().setIntoCollideMask(new_into_cdmask)

    def add_cdobj(self, objcm, rel_pos, rel_rotmat, into_list):
        """
        :return: cdobj_info, a dictionary that mimics a joint link; Besides that, there is an additional 'into_list'
                 key to hold into_list to easily toggle off the bitmasks.
        """
        cdobj_info = {}
        cdobj_info['collision_model'] = objcm  # for reversed lookup
        cdobj_info['gl_pos'] = objcm.get_pos()
        cdobj_info['gl_rotmat'] = objcm.get_rotmat()
        cdobj_info['rel_pos'] = rel_pos
        cdobj_info['rel_rotmat'] = rel_rotmat
        cdobj_info['into_list'] = into_list
        cdnp = objcm.copy_cdnp_to(self.np, clearmask=True)
        cdnp.node().setFromCollideMask(self._bitmask_ext)  # set active
        self.ctrav.addCollider(cdnp, self.chan)
        self.all_cdelements.append(cdobj_info)
        cdobj_info['cdprimit_childid'] = len(self.all_cdelements) - 1
        self.set_cdpair([cdobj_info], into_list)
        return cdobj_info

    def delete_cdobj(self, cdobj_info):
        """
        :param cdobj_info: an lnk-like object generated by self.add_objinhnd
        :param objcm:
        :return:
        """
        self.all_cdelements.remove(cdobj_info)
        cdnp_to_delete = self.np.getChild(cdobj_info['cdprimit_childid'])
        self.ctrav.removeCollider(cdnp_to_delete)
        this_cdmask = cdnp_to_delete.node().getFromCollideMask()
        for cdlnk in cdobj_info['into_list']:
            cdnp = self.np.getChild(cdlnk['cdprimit_childid'])
            current_into_cdmask = cdnp.node().getIntoCollideMask()
            new_into_cdmask = current_into_cdmask & ~this_cdmask
            cdnp.node().setIntoCollideMask(new_into_cdmask)
        cdnp_to_delete.detachNode()
        self.bitmask_list.append(this_cdmask)

    def is_collided(self,
                    obstacle_list=[],
                    otherrobot_list=[],
                    toggle_contact_points=False):
        """
        :param obstacle_list: staticgeometricmodel
        :param otherrobot_list:
        :return:
        """
        for cdelement in self.all_cdelements:
            pos = cdelement['gl_pos']
            rotmat = cdelement['gl_rotmat']
            cdnp = self.np.getChild(cdelement['cdprimit_childid'])
            cdnp.setPosQuat(da.npv3_to_pdv3(pos), da.npmat3_to_pdquat(rotmat))
            # print(da.npv3mat3_to_pdmat4(pos, rotmat))
            # print("From", cdnp.node().getFromCollideMask())
            # print("Into", cdnp.node().getIntoCollideMask())
        # print("xxxx colliders xxxx")
        # for collider in self.ctrav.getColliders():
        #     print(collider.getMat())
        #     print("From", collider.node().getFromCollideMask())
        #     print("Into", collider.node().getIntoCollideMask())
        # attach obstacles
        obstacle_parent_list = []
        for obstacle in obstacle_list:
            obstacle_parent_list.append(obstacle.objpdnp.getParent())
            obstacle.objpdnp.reparentTo(self.np)
        # attach other robots
        for robot in otherrobot_list:
            for cdnp in robot.cc.np.getChildren():
                current_into_cdmask = cdnp.node().getIntoCollideMask()
                new_into_cdmask = current_into_cdmask | self._bitmask_ext
                cdnp.node().setIntoCollideMask(new_into_cdmask)
            robot.cc.np.reparentTo(self.np)
        # collision check
        self.ctrav.traverse(self.np)
        # clear obstacles
        for i, obstacle in enumerate(obstacle_list):
            obstacle.objpdnp.reparentTo(obstacle_parent_list[i])
        # clear other robots
        for robot in otherrobot_list:
            for cdnp in robot.cc.np.getChildren():
                current_into_cdmask = cdnp.node().getIntoCollideMask()
                new_into_cdmask = current_into_cdmask & ~self._bitmask_ext
                cdnp.node().setIntoCollideMask(new_into_cdmask)
            robot.cc.np.detachNode()
        if self.chan.getNumEntries() > 0:
            collision_result = True
        else:
            collision_result = False
        if toggle_contact_points:
            contact_points = [
                da.pdv3_to_npv3(cd_entry.getSurfacePoint(base.render))
                for cd_entry in self.chan.getEntries()
            ]
            return collision_result, contact_points
        else:
            return collision_result

    def show_cdprimit(self):
        """
        Copy the current nodepath to base.render to show collision states
        TODO: maintain a list to allow unshow
        :return:
        author: weiwei
        date: 20220404
        """
        # print("call show_cdprimit")
        snp_cpy = self.np.copyTo(base.render)
        for cdelement in self.all_cdelements:
            pos = cdelement['gl_pos']
            rotmat = cdelement['gl_rotmat']
            cdnp = snp_cpy.getChild(cdelement['cdprimit_childid'])
            cdnp.setPosQuat(da.npv3_to_pdv3(pos), da.npmat3_to_pdquat(rotmat))
            cdnp.show()

    def disable(self):
        """
        clear pairs and nodepath
        :return:
        """
        for cdelement in self.all_cdelements:
            cdelement['cdprimit_childid'] = -1
        self.all_cdelements = []
        for child in self.np.getChildren():
            child.removeNode()
        self.bitmask_list = list(range(31))
Ejemplo n.º 11
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:
                    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