コード例 #1
0
ファイル: ModBase.py プロジェクト: tsp-team/ttsp-src
    def lose(self, wait=5.0, duration=2.0):
        if self.lost:
            return

        def adjustMusicVol(vol):
            self.musicManager.setVolume(vol)

        def adjustSfxVol(vol):
            self.sfxManagerList[0].setVolume(vol)

        from direct.gui.DirectGui import OnscreenText, DGG
        from direct.interval.IntervalGlobal import Parallel, Sequence, Wait, LerpFunc, Func
        fadeIval = base.transitions.getFadeOutIval(duration)
        diedText = OnscreenText(text="You failed to save Flippy!\nYou lose!",
                                fg=(1, 1, 1, 1))
        diedText.reparentTo(aspect2d, DGG.FADE_SORT_INDEX + 1)
        diedText.setAlphaScale(0)
        textFadeIval = diedText.colorScaleInterval(duration, (1, 1, 1, 1),
                                                   (1, 1, 1, 0))
        Sequence(
            Wait(wait),
            Parallel(
                fadeIval, textFadeIval,
                LerpFunc(adjustMusicVol, duration,
                         self.musicManager.getVolume(), 0.0),
                LerpFunc(adjustSfxVol, duration,
                         self.sfxManagerList[0].getVolume(), 0.0)),
            Func(self.leaveGame)).start()

        self.lost = True
コード例 #2
0
 def initIntervals(self):
     dur = Globals.LegalEagle.LiftOffTime
     nestPos = self.nest.getPos(render)
     airPos = nestPos + Vec3(0.0, 0.0, Globals.LegalEagle.LiftOffHeight)
     self.takeOffSeq = Sequence(Parallel(Sequence(Wait(dur * 0.59999999999999998), LerpPosInterval(self.suit, dur * 0.40000000000000002, startPos = nestPos, pos = airPos, blendType = 'easeInOut'))), Wait(1.5), Func(self.request, 'next'), name = '%s.takeOffSeq-%i' % (self.__class__.__name__, self.index))
     self.landOnNestPosLerp = LerpPosInterval(self.suit, 1.0, startPos = airPos, pos = nestPos, blendType = 'easeInOut')
     self.landingSeq = Sequence(Func(self.updateLandOnNestPosLerp), Parallel(self.landOnNestPosLerp), Func(self.request, 'next'), name = '%s.landingSeq-%i' % (self.__class__.__name__, self.index))
     dur = Globals.LegalEagle.ChargeUpTime
     self.chargeUpPosLerp = LerpFunc(self.moveAlongChargeUpMopathFunc, fromData = 0.0, toData = self.chargeUpMotionPath.getMaxT(), duration = dur, blendType = 'easeInOut')
     self.chargeUpAttackSeq = Sequence(Func(self.updateChargeUpPosLerp), self.chargeUpPosLerp, Func(self.request, 'next'), name = '%s.chargeUpAttackSeq-%i' % (self.__class__.__name__, self.index))
     dur = Globals.LegalEagle.RetreatToNestTime
     self.retreatToNestPosLerp = LerpPosInterval(self.suit, dur, startPos = Vec3(0, 0, 0), pos = airPos, blendType = 'easeInOut')
     self.retreatToNestSeq = Sequence(Func(self.updateRetreatToNestPosLerp), self.retreatToNestPosLerp, Func(self.request, 'next'), name = '%s.retreatToNestSeq-%i' % (self.__class__.__name__, self.index))
     dur = Globals.LegalEagle.RetreatToSkyTime
     self.retreatToSkyPosLerp = LerpFunc(self.moveAlongRetreatMopathFunc, fromData = 0.0, toData = self.retreatToSkyMotionPath.getMaxT(), duration = dur, blendType = 'easeOut')
     self.retreatToSkySeq = Sequence(Func(self.updateRetreatToSkyPosLerp), self.retreatToSkyPosLerp, Func(self.request, 'next'), name = '%s.retreatToSkySeq-%i' % (self.__class__.__name__, self.index))
     dur = Globals.LegalEagle.PreAttackTime
     self.preAttackLerpXY = LerpFunc(self.updateAttackXY, fromData = 0.0, toData = 1.0, duration = dur)
     self.preAttackLerpZ = LerpFunc(self.updateAttackZ, fromData = 0.0, toData = 1.0, duration = dur, blendType = 'easeOut')
     dur = Globals.LegalEagle.PostAttackTime
     self.postAttackPosLerp = LerpPosInterval(self.suit, dur, startPos = Vec3(0, 0, 0), pos = Vec3(0, 0, 0))
     self.attackSeq = Sequence(Parallel(self.preAttackLerpXY, self.preAttackLerpZ), Func(self.updatePostAttackPosLerp), self.postAttackPosLerp, Func(self.request, 'next'), name = '%s.attackSeq-%i' % (self.__class__.__name__, self.index))
     dur = Globals.LegalEagle.CooldownTime
     self.cooldownSeq = Sequence(Wait(dur), Func(self.request, 'next'), name = '%s.cooldownSeq-%i' % (self.__class__.__name__, self.index))
     self.propTrack = Sequence(ActorInterval(self.prop, 'propeller', startFrame = 0, endFrame = 14))
     self.hoverOverNestSeq = Sequence(ActorInterval(self.suit, 'landing', startFrame = 10, endFrame = 20, playRate = 0.5), ActorInterval(self.suit, 'landing', startFrame = 20, endFrame = 10, playRate = 0.5))
コード例 #3
0
    def __init__(self, type, index, model, collSolid, motionPath = None, motionPattern = None, blendMotion = True, instanceModel = True):
        self.type = type
        self.index = index
        name = 'CogdoFlyingObstacle-%s-%i' % (self.type, self.index)
        if instanceModel:
            self.model = NodePath(name)
            model.instanceTo(self.model)
        else:
            self.model = model
            self.model.setName(name)
        self.currentT = 0.0
        self.direction = 1.0
        self.collNode = None
        self._initCollisions(name, collSolid)
        self.motionPath = motionPath
        self.motionPattern = motionPattern
        self.motionSequence = None
        if blendMotion:
            blendType = 'easeInOut'
        else:
            blendType = 'noBlend'
        if motionPath is not None:

            def moveObstacle(value):
                self.motionPath.goTo(self.model, value)

            self.motionPath = Mopath.Mopath(name='obstacle-%i' % self.index)
            self.motionPath.loadNodePath(motionPath)
            dur = self.motionPath.getMaxT()
            self.motionSequence = Sequence(name='%s.obstacle-%i-motionSequence' % (self.__class__.__name__, self.index))
            movePart1 = LerpFunc(moveObstacle, fromData=0.0, toData=self.motionPath.getMaxT(), duration=dur, blendType=blendType)
            self.motionSequence.append(movePart1)
            if self.motionPattern == CogdoFlyingObstacle.MotionTypes.BackForth:
                movePart2 = LerpFunc(moveObstacle, fromData=self.motionPath.getMaxT(), toData=0.0, duration=dur, blendType=blendType)
                self.motionSequence.append(movePart2)
コード例 #4
0
    def createOnePlayerSequence(self, index, duration):
        """
        create a sequence for one player
        """
        numVotes = self.votes[index]
        direction = self.directions[index]
        def ticketTicker(t, label = self.entryList[index][direction+1],
                         startVotes = 0, endVotes = numVotes):
            label['text'] = str( int(t*endVotes + startVotes))

        track = Parallel()
        #track.append(Func(self.entryList[index][0].show, name='showName %d' % index))
        #track.append(LerpFunc(ticketTicker,duration=duration, name='countVotes %d'% index))

        # lets figure out the total before
        startVotes = 0
        for prev in range(index):
            if self.directions[prev] == direction:
                startVotes += self.votes[prev]

        def totalTicker(t, label = self.totalVotesLabels[direction],
                         startVotes = startVotes, additionalVotes = numVotes):
            label['text'] = str( int(t*additionalVotes + startVotes))

        track.append(LerpFunc(totalTicker, duration=duration, name='countTotal %d' %index))
        if index in self.avVotesLabel:
            def avVotesTicker(t, label = self.avVotesLabel[index],
                              startVotes = 0, endVotes = numVotes, direction = direction):
                oldValue = label['text']
                newValue = int(t*endVotes + startVotes)
                label['text'] = str(newValue)
                if not oldValue == label['text']:
                    if newValue:
                        if direction == 0:
                            self.upArrowSfx[self.curArrowSfxIndex].play()
                        else:
                            self.downArrowSfx[self.curArrowSfxIndex].play()
                            self.curArrowSfxIndex += 1
                        if self.curArrowSfxIndex >= len(self.upArrowSfx):
                            self.curArrowSfxIndex = 0

            label = self.avVotesLabel[index]
            track.append(Func(self.avVotesLabel[index].show, name='showName %d' % index))
            if index in self.avArrows:
                track.append(Func(self.avArrows[index].show, name='showArrow %d' % index))
            if direction == 0 and numVotes:
                #track.append(SoundInterval(self.upArrowSfx))
                pass
            elif direction == 1 and numVotes:
                #track.append(SoundInterval(self.downArrowSfx))
                pass
            else:
                track.append(SoundInterval(self.noVoteSfx))

            track.append(LerpFunc(avVotesTicker,duration=duration,
                                  name='countAvVotes %d'% index))

        return track
    def initPlayer(self):
        #load man
        self.man = render.attachNewNode(
            'man')  # keep this node scaled to identity
        self.man.setPos(0, 0, 10)

        # camera
        base.camera.reparentTo(self.man)
        base.camera.setPos(0, 0, 1.7)
        base.camLens.setNearFar(.1, 1000)
        base.disableMouse()
        #create a collsion solid around the man
        manC = self.man.attachCollisionSphere('manSphere', 0, 0, 1, .4,
                                              self.groundCollBit,
                                              self.collBitOff)
        self.pusher.addCollider(manC, self.man)
        base.cTrav.addCollider(manC, self.pusher)

        speed = 4
        Forward = Vec3(0, speed * 2, 0)
        Back = Vec3(0, -speed, 0)
        Left = Vec3(-speed, 0, 0)
        Right = Vec3(speed, 0, 0)
        Stop = Vec3(0)
        self.walk = Stop
        self.strife = Stop
        self.jump = 0
        taskMgr.add(self.move, 'move-task')
        self.jumping = LerpFunc(Functor(self.__setattr__, "jump"),
                                duration=.5,
                                fromData=.4,
                                toData=0)

        self.accept("escape", sys.exit)
        self.accept("space", self.startJump)
        self.accept("s", self.__setattr__, ["walk", Back])
        self.accept("w", self.__setattr__, ["walk", Forward])
        self.accept("s-up", self.__setattr__, ["walk", Stop])
        self.accept("w-up", self.__setattr__, ["walk", Stop])
        self.accept("a", self.__setattr__, ["strife", Left])
        self.accept("d", self.__setattr__, ["strife", Right])
        self.accept("a-up", self.__setattr__, ["strife", Stop])
        self.accept("d-up", self.__setattr__, ["strife", Stop])
        self.accept("wheel_up", self.nextWeapon)
        self.accept("wheel_down", self.prevWeapon)
        self.accept("1", self.Pistol)
        self.accept("2", self.Shotgun)
        self.accept("3", self.M4)
        self.accept("4", self.Scar)
        self.accept('mouse1', self.onMouseTask)
        #add mouse collision to our world
        self.setupMouseCollision()
        self.manGroundColNp = self.man.attachCollisionRay(
            'manRay', 0, 0, .6, 0, 0, -1, self.groundCollBit, self.collBitOff)
        self.manGroundHandler = CollisionHandlerGravity()
        self.manGroundHandler.addCollider(self.manGroundColNp, self.man)
        base.cTrav.addCollider(self.manGroundColNp, self.manGroundHandler)
コード例 #6
0
ファイル: ArcBall.py プロジェクト: rasheelprogrammer/pirates
    def reorientNorth(self, time=0.0):
        self.setNorth(Vec3(0, 1, 0))
        curQ = self.getInternalQuat()
        pt = self.getCamRayCollision()
        upQ = self.getUprightCorrectionQuat(pt)

        def rotateFunc(t):
            self._rotateQuatByQuat(curQ, upQ, t)

        if self._ballIval:
            self._ballIval.pause()
        self._ballIval = LerpFunc(rotateFunc, duration=time)
        self._ballIval.start()
コード例 #7
0
    def set_scene(self, scene_module):
        # self.transitions.fadeOut(0.2)
        args = []

        if self.scene:
            args.append(
                Parallel(Func(self.fade_out),
                         LerpFunc(self.blur_out, duration=0.2)))
            args.append(Wait(0.2))

        args.append(Func(self._set_scene, scene_module))
        args.append(
            Parallel(Func(self.fade_in), LerpFunc(self.blur_in, duration=0.4)))

        Sequence(*args).start()
コード例 #8
0
    def fadeAudio(self, time, audio, start, end):
        from direct.interval.IntervalGlobal import LerpFunc

        def __changeMusicVolume(vol):
            audio.setVolume(vol)

        LerpFunc(__changeMusicVolume, time, start, end).start()
コード例 #9
0
ファイル: Goon.py プロジェクト: tsp-team/ttsp-src
    def endScan(self):
        if self.shootTrack:
            self.shootTrack.finish()
        if self.lightScanIval:
            self.lightScanIval.pause()
        taskMgr.remove(self.taskName("scanTask"))

        self.scanLoopSound.stop()
        self.shootTrack = Parallel(
            SoundInterval(self.scanEndSound, node=self),
            Sequence(
                LerpHprInterval(self.scannerMdl,
                                duration=0.25,
                                hpr=(180, 0, 0),
                                startHpr=self.scannerMdl.getHpr()),
                LerpScaleInterval(self.scannerMdl,
                                  duration=0.7,
                                  scale=(0.3, 2, 1),
                                  startScale=(2, 2, 1)),
                LerpScaleInterval(self.scannerMdl,
                                  duration=0.7,
                                  scale=(0.01, 0.01, 0.01),
                                  startScale=(0.3, 2, 1)),
                Func(self.scannerMdl.hide),
                LerpFunc(self.blendAnimFromBase,
                         fromData=1,
                         toData=0,
                         duration=0.5,
                         extraArgs=['scan'])))
        self.shootTrack.start()
コード例 #10
0
ファイル: Goon.py プロジェクト: tsp-team/ttsp-src
 def enterScan(self):
     self.setPlayRate(1, "scan")
     self.pingpong("scan", fromFrame=94, toFrame=96)
     self.scannerMdl.setHpr(180, 0, 0)
     self.shootTrack = Sequence(
         LerpFunc(self.blendAnimFromBase,
                  fromData=0,
                  toData=1,
                  duration=0.5,
                  extraArgs=['scan']),
         Parallel(
             SoundInterval(self.scanBeginSound, node=self),
             Func(self.scannerMdl.show),
             Sequence(
                 LerpScaleInterval(self.scannerMdl,
                                   duration=0.5,
                                   scale=(0.3, 2, 1),
                                   startScale=(0.01, 0.01, 0.01)),
                 LerpScaleInterval(self.scannerMdl,
                                   duration=0.5,
                                   scale=(2, 2, 1),
                                   startScale=(0.3, 2, 1)),
                 LerpHprInterval(self.scannerMdl,
                                 duration=0.25,
                                 hpr=(180, 20, 0),
                                 startHpr=(180, 0, 0)))),
         Func(self.beginScan))
     self.shootTrack.start()
コード例 #11
0
 def update_fired_props(self, pos, fwd):
     if pos == (0, 0, 0) and fwd == (0, 0, 0): return
     wpn_np = self.gfx_np.node
     old_pos = wpn_np.get_pos(render)
     self.gfx_np.node.reparent_to(render)
     wpn_np.set_pos(old_pos)
     self.ipos = LerpPosInterval(wpn_np, self.eng.client.rate, pos)
     self.ipos.start()
     fwd_start = render.get_relative_vector(wpn_np, Vec3(0, 1, 0))
     if self.ifwd: self.ifwd.finish()
     self.ifwd = LerpFunc(self._rotate_wpn,
                          fromData=0,
                          toData=1,
                          duration=self.eng.client.rate,
                          extraArgs=[wpn_np, fwd_start, fwd])
     self.ifwd.start()
コード例 #12
0
 def requestChangeVolume(self, duration, finalVolume, priority):
     if priority < self.curPriority:
         return
     self.curPriority = priority
     if not self.sfx.getActive():
         if self.reloadAttempt < 1:
             self.reloadAttempt += 1
             if self.isMusic:
                 self.sfx = loader.loadMusic(self.path)
             else:
                 self.sfx = loader.loadSfx(self.path)
             if self.sfx:
                 self.sfx.setLoop(self.loop)
     self.duration = duration
     self.startVolume = self.getVolume()
     self.finalVolume = finalVolume
     if self.activeInterval:
         self.activeInterval.pause()
         del self.activeInterval
     self.activeInterval = Sequence(
         LerpFunc(self.changeVolumeTask,
                  fromData=self.startVolume,
                  toData=self.finalVolume,
                  duration=self.duration))
     self.activeInterval.start()
コード例 #13
0
def getAlertPulse(text, toScale1=0.12, toScale2=0.1):
    def change_text_scale(num):
        text.setScale(num)

    seq = Sequence(
        LerpFunc(change_text_scale,
                 duration=0.3,
                 toData=toScale1,
                 fromData=0.01,
                 blendType='easeOut'),
        LerpFunc(change_text_scale,
                 duration=0.2,
                 toData=toScale2,
                 fromData=toScale1,
                 blendType='easeInOut'), Wait(3.0), Func(text.setText, ''))
    return seq
コード例 #14
0
class WeaponGfxNetwork(WeaponGfx):
    def __init__(self, mediator, car, cars):
        WeaponGfx.__init__(self, mediator, car, cars)
        self.ipos = None
        self.ifwd = None

    def update_props(self, pos, fwd):
        if pos == (0, 0, 0) and fwd == (0, 0, 0): return
        wpn_np = self.gfx_np.node
        old_pos = wpn_np.get_pos(render)
        self.gfx_np.node.reparent_to(render)
        wpn_np.set_pos(old_pos)
        self.ipos = LerpPosInterval(wpn_np, self.eng.client.rate, pos)
        self.ipos.start()
        fwd_start = render.get_relative_vector(wpn_np, Vec3(0, 1, 0))
        if self.ifwd: self.ifwd.finish()
        self.ifwd = LerpFunc(self._rotate_wpn,
                             fromData=0,
                             toData=1,
                             duration=self.eng.client.rate,
                             extraArgs=[wpn_np, fwd_start, fwd])
        self.ifwd.start()

    def update_fired_props(self, pos, fwd):
        if pos == (0, 0, 0) and fwd == (0, 0, 0): return
        wpn_np = self.gfx_np.node
        old_pos = wpn_np.get_pos(render)
        self.gfx_np.node.reparent_to(render)
        wpn_np.set_pos(old_pos)
        self.ipos = LerpPosInterval(wpn_np, self.eng.client.rate, pos)
        self.ipos.start()
        fwd_start = render.get_relative_vector(wpn_np, Vec3(0, 1, 0))
        if self.ifwd: self.ifwd.finish()
        self.ifwd = LerpFunc(self._rotate_wpn,
                             fromData=0,
                             toData=1,
                             duration=self.eng.client.rate,
                             extraArgs=[wpn_np, fwd_start, fwd])
        self.ifwd.start()

    @staticmethod
    def _rotate_wpn(t, node, start_vec, end_vec):
        interp_vec = Vec3(
            float(start_vec[0]) * (1 - t) + float(end_vec[0]) * t,
            float(start_vec[1]) * (1 - t) + float(end_vec[1]) * t,
            float(start_vec[2]) * (1 - t) + float(end_vec[2]) * t)
        node.look_at(node.get_pos() + interp_vec)

    def destroy(self):
        if self.ipos: self.ipos.finish()
        if self.ifwd: self.ifwd.finish()
        self.ipos = self.ifwd = None
        WeaponGfx.destroy(self)
コード例 #15
0
    def showAlert(self, text):
        self.stopPulse()

        def change_text_scale(num):
            self.alertText.setScale(num)

        base.playSfx(self.popupSound)
        self.alertText.setText(text)
        self.alertPulse = Sequence(
            LerpFunc(change_text_scale,
                     duration=0.3,
                     toData=0.12,
                     fromData=0.01,
                     blendType='easeOut'),
            LerpFunc(change_text_scale,
                     duration=0.2,
                     toData=0.1,
                     fromData=0.12,
                     blendType='easeInOut'), Wait(1.5),
            Func(self.alertText.setText, ''))
        self.alertPulse.start()
コード例 #16
0
    def reorientNorth(self, time = 0.0):
        self.setNorth(Vec3(0, 1, 0))
        curQ = self.getInternalQuat()
        pt = self.getCamRayCollision()
        upQ = self.getUprightCorrectionQuat(pt)

        def rotateFunc(t):
            self._rotateQuatByQuat(curQ, upQ, t)

        if self._ballIval:
            self._ballIval.pause()

        self._ballIval = LerpFunc(rotateFunc, duration = time)
        self._ballIval.start()
コード例 #17
0
 def createLights(self, r, g, b, startColor=1, fade=0):
     self.deleteLights()
     self.amblight = AmbientLight("amblight")
     self.amblight.setColor(VBase4(r, g, b, 1))
     self.ambNode = render.attachNewNode(self.amblight)
     render.setLight(self.ambNode)
     if fade:
         self.lightTrack = LerpFunc(self.setLightColor,
                             fromData=startColor,
                             toData=r,
                             duration=2.5,
                             blendType="easeInOut")
         self.lightTrack.start()
         self.skyTrack = LerpColorInterval(self.sky,
                                     color=VBase4(r + 0.4, g + 0.4, b + 0.4, 1.0),
                                     startColor=VBase4(startColor, startColor, startColor, 1.0),
                                     duration=1.5)
         self.skyTrack.start()
         sky = "tt"
         if r < 0.6:
             sky = "br"
         self.skySeq = Sequence(Wait(1.5), Func(self.createSky, sky))
         self.skySeq.start()
コード例 #18
0
 def setup_credits(self, data):
     base.cam.set_pos(0, -10, 0)
     base.cam.look_at(0, 0, 0)
     self.ball = base.loader.load_model("models/smiley")
     self.ball.reparent_to(base.render)
     return LerpFunc(
         self.run_credits,
         fromData=0,
         toData=1,
         duration=5.0,
         blendType='noBlend',
         extraArgs=[],
         name=None,
     )
コード例 #19
0
ファイル: Goon.py プロジェクト: tsp-team/ttsp-src
 def enterShoot(self, target=None):
     if not target:
         target = base.localAvatar
     self.pose("collapse", 1)
     self.shootTrack = Sequence(
         Parallel(
             Sequence(
                 LerpFunc(self.blendAnimFromBase,
                          fromData=0,
                          toData=1,
                          duration=0.25,
                          extraArgs=['collapse']),
                 ActorInterval(self,
                               "collapse",
                               startFrame=1,
                               endFrame=5,
                               playRate=0.8),
                 ActorInterval(self,
                               "collapse",
                               startFrame=5,
                               endFrame=22,
                               playRate=0.7),
                 ActorInterval(self,
                               "collapse",
                               startFrame=22,
                               endFrame=5,
                               playRate=0.7),
                 LerpFunc(self.blendAnimFromBase,
                          fromData=1,
                          toData=0,
                          duration=0.25,
                          extraArgs=['collapse'])),
             Sequence(Wait(0.1), SoundInterval(self.whipSound, node=self)),
             Sequence(Wait(0.55), SoundInterval(self.shootSound,
                                                node=self)),
             Sequence(Wait(0.635), Func(self.fireLaser, target))))
     self.shootTrack.start()
コード例 #20
0
    def startHitFlyingToonInterval(self):
        hitByEnemyPos = self.toon.getPos(render)
        collVec = hitByEnemyPos - self.collPos
        collVec[2] = 0.0
        collVec.normalize()
        collVec *= Globals.Gameplay.HitKnockbackDist

        def spinPlayer(t, rand):
            if rand == 0:
                self.toon.setH(-(t * 720.0))
            else:
                self.toon.setH(t * 720.0)

        direction = random.randint(0, 1)
        self.startEnemyHitIval(Sequence(Parallel(LerpFunc(spinPlayer, fromData=0.0, toData=1.0, duration=Globals.Gameplay.HitKnockbackTime, blendType='easeInOut', extraArgs=[direction]), LerpPosInterval(self.toon, duration=Globals.Gameplay.HitKnockbackTime, pos=hitByEnemyPos + collVec, blendType='easeOut')), Func(self.request, 'FreeFly'), name='hitByLegalEagleIval-%i' % self.toon.doId))
コード例 #21
0
 def requestChangeVolume(self, duration, finalVolume, priority):
     if priority < self.__currentPriority:
         return
     self.__currentPriority = priority
     self.__duration = duration
     self.__startVolume = self.getVolume()
     self.__finalVolume = finalVolume
     if self.__currentActionInterval:
         self.__currentActionInterval.pause()
         self.__currentActionInterval = None
     self.__currentActionInterval = Sequence(
         LerpFunc(self.__changeVolumeTask,
                  fromData=self.__startVolume,
                  toData=self.__finalVolume,
                  duration=self.__duration))
     self.__currentActionInterval.start()
コード例 #22
0
ファイル: main.py プロジェクト: court-jus/Gate
    def initPlayer(self): 
        #load man 
        self.man = render.attachNewNode('man') # keep this node scaled to identity 
        self.man.setPos(0,0,0) 
        # should be avatar model 
#         model = loader.loadModel('teapot') 
#         model.reparentTo(self.man) 
#         model.setScale(.05) 
        # camera 
        base.camera.reparentTo(self.man) 
        base.camera.setPos(0,0,1.7) 
        base.camLens.setNearFar(.1,1000) 
        base.disableMouse() 
        #create a collsion solid around the man 
        manC = self.man.attachCollisionSphere('manSphere', 0,0,1, .4, self.groundCollBit,self.collBitOff) 
        self.pusher.addCollider(manC,self.man) 
        base.cTrav.addCollider(manC,self.pusher) 

        speed = 4 
        Forward = Vec3(0,speed*2,0) 
        Back = Vec3(0,-speed,0) 
        Left = Vec3(-speed,0,0) 
        Right = Vec3(speed,0,0) 
        Stop = Vec3(0) 
        self.walk = Stop 
        self.strife = Stop 
        self.jump = 0 
        taskMgr.add(self.move, 'move-task') 
        self.jumping = LerpFunc( Functor(self.__setattr__,"jump"), 
                                 duration=.25, fromData=.25, toData=0) 
        self.accept( "escape",sys.exit ) 
        self.accept( "space" , self.startJump) 
        self.accept( "s" , self.__setattr__,["walk",Back] ) 
        self.accept( "w" , self.__setattr__,["walk",Forward]) 
        self.accept( "s-up" , self.__setattr__,["walk",Stop] ) 
        self.accept( "w-up" , self.__setattr__,["walk",Stop] ) 
        self.accept( "a" , self.__setattr__,["strife",Left]) 
        self.accept( "d" , self.__setattr__,["strife",Right] ) 
        self.accept( "a-up" , self.__setattr__,["strife",Stop] ) 
        self.accept( "d-up" , self.__setattr__,["strife",Stop] ) 

        self.manGroundColNp = self.man.attachCollisionRay( 'manRay', 
                                                           0,0,.6, 0,0,-1, 
                                                           self.groundCollBit,self.collBitOff) 
        self.manGroundHandler = CollisionHandlerGravity() 
        self.manGroundHandler.addCollider(self.manGroundColNp,self.man) 
        base.cTrav.addCollider(self.manGroundColNp, self.manGroundHandler) 
コード例 #23
0
    def pickUp(self, toon, elapsedSeconds = 0.0):
        self._wasPickedUp = True
        if self._animSeq is not None:
            self._animSeq.finish()
            self._animSeq = None
        if self._animate:

            def lerpFlyToToon(t):
                vec = toon.getPos(render) - self.getPos(render)
                vec[2] += toon.getHeight()
                self.setPos(self.getPos() + vec * t)
                self.setScale(1.0 - t * 0.8)

            self._animSeq = Sequence(LerpFunc(lerpFlyToToon, fromData=0.0, toData=1.0, duration=self._animDuration), Wait(0.1), Func(self.hide))
            self._animSeq.start(elapsedSeconds)
        else:
            self.hide()
コード例 #24
0
    def load(self):
        StateData.load(self)

        self.topBar = DirectFrame(parent = render2d, 
            frameSize = (2,-2,0.3,-0.3), 
            frameColor=(0, 0, 0, 1), pos=(0,1,1.4))
        self.btmBar = DirectFrame(parent = render2d, 
            frameSize = (2,-2,0.3,-0.3), 
            frameColor=(0,0,0,1), pos=(0,-1,-1.4))
    
        self.ival = ParallelEndTogether(
            LerpPosInterval(self.topBar,
                duration=self.barDur,
                pos=(0,1,1.0),
                startPos=(0,1,1.4),
                blendType='easeOut'
            ),
                                        
            LerpPosInterval(self.btmBar,
                duration=self.barDur,
                pos=(0,-1,-1.0),
                startPos=(0,-1,-1.4),
                blendType='easeOut'
            ),
            
            LerpFunc(
                self.__lerpFov,
                duration = self.barDur,
                blendType = 'easeOut',
                fromData = self.origFov,
                toData = self.fov
                
            )
        )

        self.hide()
コード例 #25
0
    def setup(self):
        # Store current values
        self.entry_background_color = VBase4(base.win.get_clear_color())
        self.entry_cam_pos = VBase3(base.cam.get_pos())
        self.entry_cam_hpr = VBase3(base.cam.get_hpr())
        self.entry_cam_scale = VBase3(base.cam.get_scale())
        self.entry_cam_fov = VBase2(base.cam.node().get_lens().get_fov())

        # Set values for splash
        base.win.set_clear_color((0,0,0,1))
        cam_dist = 2
        base.cam.set_pos(0, -2.2 * cam_dist, 0)
        base.cam.set_hpr(0, 0, 0)
        base.cam.set_scale(1)
        base.cam.node().get_lens().set_fov(45/cam_dist)

        # Set up the splash itself
        self.logo_animation = Actor(asset_path / "panda3d_logo.bam")
        self.logo_animation.reparent_to(render)
        self.logo_animation.set_two_sided(True)

        shader = Shader.load(
            Shader.SL_GLSL,
            vertex=asset_path / "panda3d_logo.vert",
            fragment=asset_path / "panda3d_logo.frag",
        )
        self.logo_animation.set_shader(shader)
        self.logo_animation.set_shader_input("fade", 0.0)
        self.logo_animation.set_shader_input("pattern", self.pattern.value)
        self.logo_animation.set_shader_input("colors", self.colors.value)
        self.logo_animation.set_shader_input("pattern_freq", self.pattern_freq)
        self.logo_animation.set_shader_input("cycle_freq", self.cycle_freq)
        self.logo_sound = base.loader.loadSfx(asset_path / "panda3d_logo.wav")

        # Build interval
        def shader_time(t):
            self.logo_animation.set_shader_input("time", t)
        def fade_background_to_white(t):
            base.win.set_clear_color((t,t,t,1))
            self.logo_animation.set_shader_input("time", t/3.878)
            self.logo_animation.set_shader_input("fade", t)
        def fade_to_black(t):
            base.win.set_clear_color((1-t,1-t,1-t,1))
            #self.logo_animation.set_shader_input("time", t/3.878)
            #self.logo_animation.set_shader_input("fade", t)

        # Timing:
        # 0.000     Start
        # 3.878     Logo is assembled, fade to black-on-whitey
        # 4.878     Black on white achieved
        # <+1.500>  Begin fade to black
        # <+1.741>  Black on black achieved
        # 8.119 Sound ends
        effects = Parallel(
            self.logo_animation.actorInterval(
                "splash",
                loop=False,
            ),
            SoundInterval(
                self.logo_sound,
                loop=False,
            ),
            Sequence(
                LerpFunc(
                    shader_time,
                    fromData=0,
                    toData=1,
                    duration=3.878,
                ),
                LerpFunc(
                    fade_background_to_white,
                    fromData=0,
                    toData=1,
                    duration=1.0,
                ),
                Wait(1.5),
                LerpFunc(
                    fade_to_black,
                    fromData=0,
                    toData=1,
                    duration=1.741,
                ),
            ),
        )
        return effects
コード例 #26
0
    def setup(self):
        x_size, y_size = base.win.get_x_size(), base.win.get_y_size()
        bg_buffer = base.win.makeTextureBuffer(
            "Background Scene",
            x_size,
            y_size,
        )
        bg_buffer.set_clear_color_active(True)
        bg_buffer.set_clear_color(VBase4(0, 1, 0, 1))
        bg_buffer.set_sort(-100)  # render buffer before main scene.

        bg_texture = bg_buffer.get_texture()
        self.bg_texture = bg_texture
        bg_camera = base.make_camera(bg_buffer)

        self.setup_background_scene(bg_camera)

        # Foreground Scene
        base.win.set_clear_color((0, 0, 0, 1))
        cam_dist = 2
        base.cam.set_pos(0, -2.2 * cam_dist, 0)
        base.cam.node().get_lens().set_fov(45/cam_dist)

        self.logo_animation = Actor(asset_path / "panda3d_logo.bam")
        self.logo_animation.reparent_to(render)
        self.logo_animation.set_two_sided(True)

        shader = Shader.load(
            Shader.SL_GLSL,
            vertex=asset_path / "splash_window.vert",
            fragment=asset_path / "splash_window.frag",
        )
        self.logo_animation.set_shader(shader)
        self.logo_animation.set_shader_input("background", bg_texture)
        self.logo_animation.set_shader_input("fade", 0.0)
        self.logo_sound = base.loader.loadSfx(asset_path / "panda3d_logo.wav")

        # Build interval
        def fade_background_to_white(t):
            base.win.set_clear_color((t,t,t,1))
            self.logo_animation.set_shader_input("fade", t)
        def set_background_texture(t):
            self.logo_animation.set_shader_input(
                "background",
                self.bg_texture,
            )
                    
        effects = Parallel(
            self.logo_animation.actorInterval(
                "splash",
                loop=False,
            ),
            SoundInterval(
                self.logo_sound,
                loop=False,
            ),
            Sequence(
                LerpFunc(
                    set_background_texture,
                    fromData=0,
                    toData=1,
                    duration=3.878,
                ),
                LerpFunc(
                    fade_background_to_white,
                    fromData=0,
                    toData=1,
                    duration=1.0,
                ),
            ),
        )
        return effects
class FPS(object, DirectObject):
    def __init__(self):
        self.winXhalf = base.win.getXSize() / 2
        self.winYhalf = base.win.getYSize() / 2
        winprops = WindowProperties()
        winprops.setCursorHidden(True)
        base.win.requestProperties(winprops)
        self.model = loader.loadModel('models/Guns/45.x')
        self.model.reparentTo(base.camera)
        self.model.setPos(USP45_POS)
        self.model.setHpr(USP45_HPR)
        self.model.setScale(PISTOL_SCALE)
        self.gun = 1

        self.initSound()
        self.initCollision()
        self.loadLevel()
        self.initPlayer()
        self.setupMouseCollision()
        self.loadCrosshairs()
        self.loadRalph()

    def initSound(self):
        self.deathSnd = base.loader.loadSfx("models/sounds/and.ogg")
        self.spawnSnd = base.loader.loadSfx("models/sounds/faster.ogg")
        self.fireSnd = base.loader.loadSfx("models/sounds/rifle.ogg")

    def loadCrosshairs(self):
        self.crosshairs = OnscreenImage(image='models/crosshair.png',
                                        pos=base.win.getPointer(0))
        self.crosshairs.setTransparency(TransparencyAttrib.MAlpha)
        self.crosshairs.setScale(.04, .04, .04)

    def initCollision(self):
        #initialize traverser
        base.cTrav = CollisionTraverser()
        base.cTrav.setRespectPrevTransform(True)
        base.cTrav.showCollisions(render)
        self.mPicker = CollisionTraverser()
        self.mPicker.showCollisions(render)
        self.mCQue = CollisionHandlerQueue()
        #         base.cTrav.showCollisions(render)
        #initialize pusher
        self.pusher = CollisionHandlerPusher()
        # collision bits
        self.groundCollBit = BitMask32.bit(0)
        self.collBitOff = BitMask32.allOff()
        self.zombieColBitFrom = BitMask32.bit(2)
        self.zombieColBitInto = BitMask32.bit(2)
        self.zombieColBitOff = BitMask32.allOff()

    def loadLevel(self):

        self.level = loader.loadModel('models/world')
        self.level.reparentTo(render)
        self.level.setPos(0, 0, 0)
        self.level.setColor(1, 1, 1, .5)
        self.level.setCollideMask(self.groundCollBit)

        self.box = loader.loadModel("models/box")
        self.box.reparentTo(render)
        self.box.setPos(-29.83, 0, 0)
        self.box.setScale(1)
        self.box.setCollideMask(self.groundCollBit)
        self.box1 = loader.loadModel("models/box")
        self.box1.reparentTo(render)
        self.box1.setPos(-51.14, -17.90, 0)
        self.box1.setScale(1)
        self.box1.setCollideMask(self.groundCollBit)

    def loadRalph(self):
        ralphStartPos = Vec3(-98.64, -20.60, 0)
        self.ralph = Actor("models/ralph", {
            "run": "models/ralph-run",
            "walk": "models/ralph-walk"
        })
        self.ralph.reparentTo(render)
        self.ralph.setPos(ralphStartPos)
        self.ralph.setScale(.3)
        self.ralphLife = 10
        ralphaiStartPos = Vec3(-50, 20, 0)
        self.ralphai = Actor("models/ralph", {
            "run": "models/ralph-run",
            "walk": "models/ralph-walk"
        })
        self.cTrav = CollisionTraverser()

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

        self.ralphHeadSphere = CollisionSphere(0, -.2, 4.5, .7)
        self.ralphHeadCol = CollisionNode('ralphHeadColSphere')
        self.ralphHeadCol.addSolid(self.ralphHeadSphere)
        self.ralphHeadCol.setFromCollideMask(self.zombieColBitFrom)
        self.ralphHeadCol.setIntoCollideMask(self.zombieColBitInto)
        self.ralphHeadColNp = self.ralph.attachNewNode(self.ralphHeadCol)
        self.mPicker.addCollider(self.ralphHeadColNp, self.mCQue)

        self.ralphBodySphere = CollisionSphere(0, -.2, 2, 1)
        self.ralphBodyCol = CollisionNode('ralphBodyColSphere')
        self.ralphBodyCol.addSolid(self.ralphBodySphere)
        self.ralphBodyCol.setFromCollideMask(self.zombieColBitFrom)
        self.ralphBodyCol.setIntoCollideMask(self.zombieColBitInto)
        self.ralphBodyColNp = self.ralph.attachNewNode(self.ralphBodyCol)
        self.mPicker.addCollider(self.ralphBodyColNp, self.mCQue)
        self.ralphHeadColNp.show()
        self.ralphBodyColNp.show()

        base.taskMgr.doMethodLater(.7, self.spawnSound, "spawnSound")
        self.isMoving = False
        self.setAI()

    def spawnSound(self, task):
        self.spawnSnd.play()
        return task.done

    def Scar(self):
        self.model.removeNode()
        self.model = loader.loadModel('models/Guns/SCAR.x')
        self.model.reparentTo(base.camera)
        self.model.setPos(SCAR_POS)
        self.model.setHpr(SCAR_HPR)
        self.model.setScale(RIFLE_SCALE)
        self.gun = 4

    def M4(self):
        self.model.removeNode()
        self.model = loader.loadModel('models/Guns/M4.x')
        self.model.reparentTo(base.camera)
        self.model.setPos(M4_POS)
        self.model.setHpr(M4_HPR)
        self.model.setScale(RIFLE_SCALE)
        self.gun = 3

    def Shotgun(self):
        self.model.removeNode()
        self.model = loader.loadModel('models/Guns/Shotgun.x')
        self.model.reparentTo(base.camera)
        self.model.setPos(SHOTGUN_POS)
        self.model.setHpr(SHOTGUN_HPR)
        self.model.setScale(RIFLE_SCALE)
        self.gun = 2

    def Pistol(self):
        self.model.removeNode()
        self.model = loader.loadModel('models/Guns/45.x')
        self.model.reparentTo(base.camera)
        self.model.setPos(USP45_POS)
        self.model.setHpr(USP45_HPR)
        self.model.setScale(PISTOL_SCALE)
        self.gun = 1

    def setupMouseCollision(self):

        self.mRay = CollisionRay()
        self.mRayNode = CollisionNode('pickRay')
        self.mRayNode.addSolid(self.mRay)
        self.mRayNode.setFromCollideMask(self.zombieColBitFrom)
        self.mRayNode.setIntoCollideMask(self.zombieColBitOff)
        self.mPickNp = base.camera.attachNewNode(self.mRayNode)
        self.mPicker.addCollider(self.mPickNp, self.mCQue)

        self.mPickNp.show()

    def initPlayer(self):
        #load man
        self.man = render.attachNewNode(
            'man')  # keep this node scaled to identity
        self.man.setPos(0, 0, 10)

        # camera
        base.camera.reparentTo(self.man)
        base.camera.setPos(0, 0, 1.7)
        base.camLens.setNearFar(.1, 1000)
        base.disableMouse()
        #create a collsion solid around the man
        manC = self.man.attachCollisionSphere('manSphere', 0, 0, 1, .4,
                                              self.groundCollBit,
                                              self.collBitOff)
        self.pusher.addCollider(manC, self.man)
        base.cTrav.addCollider(manC, self.pusher)

        speed = 4
        Forward = Vec3(0, speed * 2, 0)
        Back = Vec3(0, -speed, 0)
        Left = Vec3(-speed, 0, 0)
        Right = Vec3(speed, 0, 0)
        Stop = Vec3(0)
        self.walk = Stop
        self.strife = Stop
        self.jump = 0
        taskMgr.add(self.move, 'move-task')
        self.jumping = LerpFunc(Functor(self.__setattr__, "jump"),
                                duration=.5,
                                fromData=.4,
                                toData=0)

        self.accept("escape", sys.exit)
        self.accept("space", self.startJump)
        self.accept("s", self.__setattr__, ["walk", Back])
        self.accept("w", self.__setattr__, ["walk", Forward])
        self.accept("s-up", self.__setattr__, ["walk", Stop])
        self.accept("w-up", self.__setattr__, ["walk", Stop])
        self.accept("a", self.__setattr__, ["strife", Left])
        self.accept("d", self.__setattr__, ["strife", Right])
        self.accept("a-up", self.__setattr__, ["strife", Stop])
        self.accept("d-up", self.__setattr__, ["strife", Stop])
        self.accept("wheel_up", self.nextWeapon)
        self.accept("wheel_down", self.prevWeapon)
        self.accept("1", self.Pistol)
        self.accept("2", self.Shotgun)
        self.accept("3", self.M4)
        self.accept("4", self.Scar)
        self.accept('mouse1', self.onMouseTask)
        #add mouse collision to our world
        self.setupMouseCollision()
        self.manGroundColNp = self.man.attachCollisionRay(
            'manRay', 0, 0, .6, 0, 0, -1, self.groundCollBit, self.collBitOff)
        self.manGroundHandler = CollisionHandlerGravity()
        self.manGroundHandler.addCollider(self.manGroundColNp, self.man)
        base.cTrav.addCollider(self.manGroundColNp, self.manGroundHandler)

    def nextWeapon(self):
        if self.gun == 1:
            self.Shotgun()
        elif self.gun == 2:
            self.M4()
        elif self.gun == 3:
            self.Scar()
        elif self.gun == 4:
            self.Pistol()

    def prevWeapon(self):
        if self.gun == 1:
            self.Scar()
        elif self.gun == 2:
            self.Pistol()
        elif self.gun == 3:
            self.Shotgun()
        elif self.gun == 4:
            self.M4()

    def startJump(self):
        if self.manGroundHandler.isOnGround():
            self.jumping.start()

    def move(self, task):
        dt = globalClock.getDt()
        # mouse
        md = base.win.getPointer(0)
        x = md.getX()
        y = md.getY()
        if base.win.movePointer(0, self.winXhalf, self.winYhalf):
            self.man.setH(self.man, (x - self.winXhalf) * -0.1)
            base.camera.setP(
                clampScalar(-90, 90,
                            base.camera.getP() - (y - self.winYhalf) * 0.1))
        # move where the keys set it
        moveVec = (self.walk + self.strife) * dt  # horisontal
        moveVec.setZ(self.jump)  # vertical
        self.man.setFluidPos(self.man, moveVec)
        # jump damping
        if self.jump > 0:
            self.jump = clampScalar(0, 1, self.jump * .9)

        return task.cont

    def onMouseTask(self):

        mpos = base.mouseWatcherNode.getMouse()
        self.mRay.setDirection(render.getRelativeVector(camera, Vec3(0, 1, 0)))
        self.mRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
        self.mPicker.traverse(render)
        self.fireSnd.play()
        entries = []
        for i in range(self.mCQue.getNumEntries()):
            entry = self.mCQue.getEntry(i)
            print entry
            entries.append(entry)
        if (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                   == 'terrain'):
            print 'terrain'

        entries = []
        for i in range(self.mCQue.getNumEntries()):
            entry = self.mCQue.getEntry(i)
            print entry
            entries.append(entry)
        if (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                   == 'ralphHeadColSphere'):
            self.ralphLife -= 10
            base.taskMgr.doMethodLater(.3, self.deathSound, "deathSound")

        entries = []
        for i in range(self.mCQue.getNumEntries()):
            entry = self.mCQue.getEntry(i)
            print entry
            entries.append(entry)
        if (len(entries) > 0) and (entries[0].getIntoNode().getName()
                                   == 'ralphBodyColSphere'):
            self.ralphLife -= 5
            if self.ralphLife < 5:
                base.taskMgr.doMethodLater(.3, self.deathSound, "deathSound")

        if self.ralphLife <= 0:
            self.ralph.cleanup()
            self.ralphai.cleanup()
            self.loadRalph()

    def deathSound(self, task):
        self.deathSnd.play()
        return task.done

    def setAI(self):
        #Creating AI World
        self.AIworld = AIWorld(render)
        self.AIchar = AICharacter("ralph", self.ralph, 130, 0.05, 25)
        self.AIworld.addAiChar(self.AIchar)
        self.AIbehaviors = self.AIchar.getAiBehaviors()

        self.AIbehaviors.initPathFind("models/navmesh.csv")
        self.setMove()
        #AI World update
        taskMgr.add(self.AIUpdate, "AIUpdate")

    def setMove(self):
        self.AIbehaviors.addStaticObstacle(self.box)
        self.AIbehaviors.addStaticObstacle(self.box1)
        self.AIbehaviors.pathFindTo(self.man)
        self.ralph.loop("run")

    #to update the AIWorld
    def AIUpdate(self, task):
        self.AIworld.update()
        self.ralphMove()

        return Task.cont

    def ralphMove(self):

        startpos = self.ralph.getPos()

        # Now check for collisions.

        self.cTrav.traverse(render)

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

        self.ralph.setP(0)
        return Task.cont
コード例 #28
0
class ArcBall(NodePath, DirectObject):
    def __init__(self,
                 name,
                 radius=1,
                 scrollFactor=1,
                 camera=base.cam,
                 frame=Vec4(-1, 1, -1, 1),
                 keepUpright=0,
                 mouseDownEvent='mouse1',
                 mouseUpEvent='mouse1-up',
                 *args,
                 **kwargs):
        NodePath.__init__(self, name, *args, **kwargs)
        DirectObject.__init__(self)
        self._rNode = self.attachNewNode('rotateNode')
        self._setRadius(radius, False)
        self._setScrollFactor(scrollFactor, False)
        self._setCamera(camera, False)
        self._setFrame(frame, False)
        self._setKeepUpright(keepUpright)
        self._setMouseEvents(mouseDownEvent, mouseUpEvent)
        self.setRotateMode(0)
        self._setControlButtonState(0)
        self._setTiltLimit(25 * math.pi / 180, False)
        self.saveNorth()
        self._colBitMask = BitMask32(1 << 16)
        self._colNode = self.attachNewNode(CollisionNode(name + '-cNode'))
        self._colNode.node().addSolid(CollisionSphere(0, 0, 0, 1))
        self._colNode.node().setIntoCollideMask(self._colBitMask)
        self._mouseEnabled = True
        self._initCollisions()
        self.geom_node_path = self.attachNewNode('arrow')
        self.geom_node_path.setBin('fixed', 100)
        self.geom_node_path.setDepthTest(0)
        self.geom_node_path.setTransparency(1)
        self.head_geom_node = GeomNode('head')
        self.head_geom_node_path = self.geom_node_path.attachNewNode(
            self.head_geom_node)
        self.tail_geom_node = GeomNode('tail')
        self.tail_geom_node_path = self.geom_node_path.attachNewNode(
            self.tail_geom_node)
        self._ballIval = None

    def removeNode(self):
        self.ignoreAll()
        NodePath.removeNode(self)

    def _setRadius(self, radius, reset=True):
        self._radius = radius

    def _setScrollFactor(self, scrollFactor, reset=True):
        self._scrollFactor = float(scrollFactor)

    def _setCamera(self, cam, reset=True):
        self.cam = cam
        self.camNode = cam.node()
        self.camLens = self.camNode.getLens()

    def _setFrame(self, frame, reset=True):
        self._frame = frame
        self.saveTransforms()

    def _setKeepUpright(self, keepUpright):
        self._keepUpright = keepUpright

    def _setControlButtonState(self, state):
        self._ctrlBtnState = state

    def _setTiltLimit(self, limit=math.pi / 6, reset=True):
        self._tiltLimit = limit
        if reset:
            self._applyConstraints()

    def _setMouseEvents(self, down, up):
        if hasattr(self, '_mouseDownEventStr'):
            self.ignore(self._mouseDownEventStr)

        if hasattr(self, '_mouseUpEventStr'):
            self.ignore(self._mouseUpEventStr)

        self._mouseDownEventStr = down
        self._mouseUpEventStr = up
        self.accept(self._mouseDownEventStr, self._mouseDown)
        self.accept(self._mouseUpEventStr, self._mouseUp)

    def setRadius(self, radius):
        self._setRadius(radius)

    def setScrollFactor(self, scrollFactor):
        self._setScrollFactor(scrollFactor)

    def setCamera(self, camera):
        self._setCamera(camera)

    def setFrame(self, frame):
        self._setFrame(frame)

    def setKeepUpright(self, keepUpright):
        self._setKeepUpright(keepUpright)

    def setMouseEvents(self, downEvent, upEvent):
        self._setMouseEvents(downEvent, upEvent)

    def setMouseEnabled(self, enabled):
        self._mouseEnabled = enabled
        if not self._mouseEnabled:
            self._mouseUp()

    def setRotateMode(self, mode):
        self.rMode = mode

    def enable(self):
        self.setMouseEnabled(True)

    def disable(self):
        if self._ballIval:
            self._ballIval.pause()
            self._ballIval = None

        self.setMouseEnabled(False)

    def getRotateRoot(self):
        return self._rNode

    def attachForRotation(self, nodepath):
        nodepath.reparentTo(self._rNode)

    def getInternalHpr(self, *args, **kwargs):
        return self._rNode.getHpr(*args, **kwargs)

    def setInternalHpr(self, *args, **kwargs):
        self._rNode.setHpr(*args, **kwargs)

    def getInternalQuat(self, *args, **kwargs):
        return self._rNode.getQuat(*args, **kwargs)

    def setInternalQuat(self, *args, **kwargs):
        self._rNode.setQuat(*args, **kwargs)

    def _mouseDown(self, *args):
        if self._mouseEnabled:
            self._startRotateTask()

    def _mouseUp(self, *args):
        self._stopRotateTask()

    def _initCollisions(self):
        self.traverser = CollisionTraverser()
        self.colHandlerQueue = CollisionHandlerQueue()
        self.camRayNode = self.cam.attachNewNode(CollisionNode('camRayNode'))
        self.camRay = CollisionRay()
        self.camRayNode.node().addSolid(self.camRay)
        self.traverser.addCollider(self.camRayNode, self.colHandlerQueue)

    def _mouseRayCollide(self, rayBitMask=BitMask32.allOn()):
        if base.mouseWatcherNode.hasMouse():
            mousePt = base.mouseWatcherNode.getMouse()
            mousePt = self._transMouseToHomogenousFramePt(mousePt)
            self.camRay.setFromLens(self.camNode, mousePt[0], mousePt[1])
            self.camRayNode.node().setFromCollideMask(rayBitMask)
            self.traverser.traverse(self)
            self.traverser.traverse(self.getTop())
        else:
            self.colHandlerQueue.clearEntries()

    def _camRayCollide(self, rayBitMask=BitMask32.allOn()):
        self.camRay.setOrigin(Point3(0))
        self.camRay.setDirection(Vec3(0, 1, 0))
        self.camRayNode.node().setFromCollideMask(rayBitMask)
        self.traverser.traverse(self)
        self.traverser.traverse(self.getTop())

    def getHorizonCollisionPt(self, raySpace=None, rayDirection=None):
        raySpaceToSelf = raySpace.getTransform(self)
        rayOrig = raySpaceToSelf.getMat().xformPoint(Point3(0))
        rayDist = rayOrig.length()
        ray = raySpaceToSelf.getMat().xformPoint(rayDirection)
        a = rayOrig * self._radius * self._radius / rayDist * rayDist
        b = -rayOrig.cross(ray).cross(-rayOrig)
        b.normalize()
        b *= math.sqrt(1 - 1 / rayDist / rayDist)
        return a + b

    def _getCollisionPt(self):
        entryCount = self.colHandlerQueue.getNumEntries()
        for x in range(entryCount):
            entry = self.colHandlerQueue.getEntry(x)
            if entry.getIntoNode().getName() == self.getName() + '-cNode':
                return entry.getSurfacePoint(entry.getIntoNodePath())
                continue

        camRay = self.camRayNode.node().getSolid(0).getDirection()
        pt = self.getHorizonCollisionPt(self.cam, camRay)
        return pt

    def getMouseRayCollisionPt(self, rayBitMask=None):
        if not rayBitMask:
            rayBitMask = self._colBitMask

        self._mouseRayCollide(rayBitMask)
        return self._getCollisionPt()

    def getCamRayCollisionPt(self, rayBitMask=None):
        if not rayBitMask:
            rayBitMask = self._colBitMask

        self._camRayCollide(rayBitMask)
        return self._getCollisionPt()

    def _getCollisionEntry(self):
        entryCount = self.colHandlerQueue.getNumEntries()
        if entryCount:
            self.colHandlerQueue.sort()
            return self.colHandlerQueue.getEntry(0)
        else:
            return None

    def getMouseRayCollisionEntry(self, rayBitMask=None):
        if not rayBitMask:
            rayBitMask = self._colBitMask

        self._mouseRayCollide(rayBitMask)
        return self._getCollisionEntry()

    def saveTransforms(self):
        frame = self._frame
        ll = Point3(frame[0], frame[2], 0)
        ur = Point3(frame[1], frame[3], 0)
        aspectTs = TransformState.makeScale2d(
            Point2(1 / base.camLens.getAspectRatio(), 1))
        ll = aspectTs.getMat().xformPoint(ll)
        ur = aspectTs.getMat().xformPoint(ur)
        posTs = TransformState.makePos2d(
            Point2(ll[0] + ur[0], ll[1] + ur[1]) / -2.0)
        scaleTs = TransformState.makeScale2d(
            Point2(2.0 / (ur[0] - ll[0]), 2.0 / (ur[1] - ll[1])))
        frameTs = scaleTs.compose(posTs)
        self._mouseToHomogenousFrameMat = Mat4(frameTs.getMat())
        self._mouseToHomogenousFrameMatInv = Mat4(
            frameTs.getInverse().getMat())
        self._camLensProjMat = Mat4(self.camLens.getProjectionMat())
        self._camLensProjMatInv = Mat4(self._camLensProjMat)
        self._camLensProjMatInv.invertInPlace()

    def _transMouseToHomogenousFramePt(self, pt):
        pt = Point3(pt[0], pt[1], 0)
        return self._mouseToHomogenousFrameMat.xformPoint(pt)

    def _transHomogenousFrameToMousePt(self, pt):
        return self._mouseToHomogenousFrameMatInv.xformPoint(pt)

    def _transCamSpaceToHomogenousFramePt(self, pt):
        pt = self._camLensProjMat.xform(Vec4(pt[0], pt[1], pt[2], 1))
        pt /= pt[3]
        return pt

    def _transHomogenousFrameToCamSpacePt(self, pt):
        pt = self._camLensProjMatInv.xform(Vec4(pt[0], pt[1], pt[2], 1))
        pt /= pt[3]
        return pt

    def setNorth(self, northVec):
        self._north = northVec

    def saveNorth(self):
        upSpaceNodePath = self
        Z = Vec3.unitZ()
        upSpaceToRNode = TransformState.makeHpr(
            upSpaceNodePath.getHpr(self._rNode))
        self._north = upSpaceToRNode.getMat().xformPoint(Z)

    def _applyConstraints(self):
        self._rotate(self.getOrthTiltLimitQuat(self._tiltLimit), 1.0)
        if self._keepUpright:
            self.clampOrientationAboutSpherePt(self.getCamRayCollisionPt())

    def getTiltLimitQuat(self, thetaLimit):
        Y = Vec3.unitY()
        Z = Vec3.unitZ()
        upSpaceNodePath = self
        rNodeNorth = Z
        arcballNorth = -Y
        rNodeToUpSpace = TransformState.makeHpr(
            self._rNode.getHpr(upSpaceNodePath))
        northPole = rNodeToUpSpace.getMat().xformPoint(rNodeNorth)
        dot = northPole.dot(arcballNorth)
        theta = math.acos(clampScalar(-1, 1, dot))
        if theta < thetaLimit:
            return Quat.identQuat()
        else:
            axis = northPole.cross(arcballNorth)
            axis.normalize()
            theta -= thetaLimit
            return Quat(math.cos(theta / 2.0), axis * math.sin(theta / 2.0))

    def getOrthTiltLimitQuat(self, thetaLimit=10):
        X = Vec3.unitX()
        Y = Vec3.unitY()
        Z = Vec3.unitZ()
        upSpaceNodePath = self
        rNodeNorth = Z
        arcballNorth = -Y
        baseQuat = self._rNode.getQuat(upSpaceNodePath)
        quatX = Quat.identQuat()
        quatY = Quat.identQuat()
        rNodeToUpSpace = TransformState.makeQuat(baseQuat)
        northPole = rNodeToUpSpace.getMat().xformPoint(rNodeNorth)
        dot = northPole.dot(X)
        proj = northPole - X * dot
        theta = math.acos(
            clampScalar(-1.0, 1.0,
                        proj.dot(arcballNorth) / proj.length()))
        if theta > thetaLimit:
            theta -= thetaLimit
            if northPole.dot(Z) < 0.0:
                theta *= -1

            quatX = Quat(math.cos(theta / 2.0), X * math.sin(theta / 2.0))
            baseQuat *= quatX
            rNodeToUpSpace = TransformState.makeQuat(baseQuat)
            northPole = rNodeToUpSpace.getMat().xformPoint(rNodeNorth)

        dot = northPole.dot(Z)
        proj = northPole - Z * dot
        theta = math.acos(
            clampScalar(-1.0, 1.0,
                        proj.dot(arcballNorth) / proj.length()))
        if theta > thetaLimit:
            theta -= thetaLimit
            if northPole.dot(X) >= 0.0:
                theta *= -1

            quatY = Quat(math.cos(theta / 2.0), Z * math.sin(theta / 2.0))
            baseQuat *= quatY

        return quatX * quatY

    def getUprightCorrectionQuat(self, pt):
        Y = Vec3.unitY()
        Z = Vec3.unitZ()
        rNodeNorth = self._north
        upSpaceNodePath = self
        axis = pt / pt.length()
        up = Z
        rNodeToUpSpace = TransformState.makeHpr(
            self._rNode.getHpr(upSpaceNodePath))
        northPole = rNodeToUpSpace.getMat().xformPoint(rNodeNorth)
        right = up.cross(axis)
        final = axis.cross(right)
        dot = northPole.dot(axis)
        proj = northPole - axis * dot
        theta = math.acos(
            clampScalar(-1.0, 1.0,
                        proj.dot(final) / proj.length() * final.length()))
        if northPole.dot(right) < 0.0:
            theta *= -1

        return Quat(math.cos(theta / 2.0), Vec3(axis) * math.sin(theta / 2.0))

    def _rotate(self, q, factor=1.0):
        q = nLerp(Quat(1, Vec3(0)), q, factor)
        self._rNode.setQuat(self._rNode.getQuat() * q)

    def _rotatePtToPt(self, p0, p1, factor=1.0):
        self._rotate(self._getPtToPtQuat(p0, p1), factor)

    def _getPtToPtQuat(self, p0, p1, factor=1.0):
        p0.normalize()
        p1.normalize()
        theta = math.acos(clampScalar(-1, 1, p0.dot(p1)))
        axis = p0.cross(p1)
        axis.normalize()
        if factor == 1.0:
            return Quat(math.cos(theta / 2.0), axis * math.sin(theta / 2.0))
        elif 0.0 < factor:
            pass
        elif factor == 1.0:
            q = nLerp(
                Quat.identQuat(),
                Quat(math.cos(theta / 2.0), axis * math.sin(theta / 2.0)),
                factor)
            return q

    def _getRotateAboutAxisQuat(self, axis, p0, p1, factor=1.0):
        axis = axis / axis.length()
        dot0 = axis.dot(p0)
        proj0 = p0 - axis * dot0
        dot1 = axis.dot(p1)
        proj1 = p1 - axis * dot1
        axis = proj0.cross(proj1)
        area = axis.length()
        axis.normalize()
        theta = math.acos(
            clampScalar(-1, 1,
                        proj0.dot(proj1) / proj0.length() * proj1.length()))
        return (Quat(math.cos(theta / 2.0),
                     axis * math.sin(theta / 2.0)), area)

    def _rotateQuatByQuat(self, q0, q1, factor=1.0):
        self._rNode.setQuat(nLerp(q0, q0 * q1, factor))

    def clampOrientationAboutSpherePt(self, pt):
        q = self.getUprightCorrectionQuat(pt)
        self._rotate(q, 1.0)

    def rotatePtToCenter(self, pt):
        centerPt = self.getCamRayCollisionPt()
        self._rotatePtToPt(pt, centerPt)
        self._applyConstraints()

    def rotateSpherePtToCenter(self, spherePt):
        pt = self._colNode.getRelativePoint(self._rNode, spherePt)
        self.rotatePtToCenter(pt)

    def clampSpherePtToHorizon(self, pt):
        camRaySpherePt = self.findCamRaySpherePt(pt)
        if camRaySpherePt and not pt.almostEqual(camRaySpherePt, 0.0001):
            camToSphere = self.cam.getTransform(self._rNode)
            OC = camToSphere.getMat().xformPoint(Vec3(0, 0, 0))
            theta = math.acos(
                clampScalar(-1.0, 1.0, self._radius / OC.length()))
            axis = OC.cross(pt)
            axis.normalize()
            q = Quat(math.cos(theta / 2), axis * math.sin(theta / 2))
            ts = TransformState.makeQuat(q)
            OC.normalize()
            OC *= self._radius
            newPt = ts.getMat().xformPoint(OC)
            dTheta = math.acos(clampScalar(-1.0, 1.0, pt.dot(newPt)))
            return (newPt, dTheta)
        else:
            return (pt, 0)

    def reorientNorth(self, time=0.0):
        self.setNorth(Vec3(0, 1, 0))
        curQ = self.getInternalQuat()
        pt = self.getCamRayCollision()
        upQ = self.getUprightCorrectionQuat(pt)

        def rotateFunc(t):
            self._rotateQuatByQuat(curQ, upQ, t)

        if self._ballIval:
            self._ballIval.pause()

        self._ballIval = LerpFunc(rotateFunc, duration=time)
        self._ballIval.start()

    def showRotationSphere(self):
        if not hasattr(self, '_ArcBall_rotGuide'):
            self._rotGuide = loader.loadModel('models/misc/sphere')
            self._rotGuide.setName('RotationGuide')
            self._rotGuide.setRenderModeWireframe()
            self._rotGuide.setTwoSided(1)
            self._rotGuide.setTextureOff(1)
            self._rotGuide.setColor(Vec4(1, 0, 0, 1))
            self._rotGuide.reparentTo(self.getRotateRoot())

        self._rotGuide.setScale(self._radius)
        self._rotGuide.show()

    def hideRotationSphere(self):
        if hasattr(self, '_ArcBall_rotGuide'):
            self._rotGuide.hide()

    def _startRotateTask(self, *args):
        self.saveTransforms()
        modePairs = ((0, 2), (1, 3))
        if not self._ctrlBtnState:
            rMode = modePairs[self.rMode][0]
        else:
            rMode = modePairs[self.rMode][1]
        if self.rMode in [1]:
            props = WindowProperties()
            props.setCursorHidden(1)
            base.win.requestProperties(props)

        task = taskMgr.add(self._rotateTask, self.getName() + '-rotateTask')
        task.rMode = rMode

    def _rotateTask(self, task):
        if not hasattr(task, 'startPt'):
            task.startPt = self.getMouseRayCollisionPt()
            task.camPt = self.getCamRayCollisionPt()
            task.quat = self._rNode.getQuat()

        if task.rMode == 0:
            pt = self.getMouseRayCollisionPt()
            q = self._getPtToPtQuat(task.startPt, pt)
            self._rotateQuatByQuat(task.quat, q, 1.0)
            self._applyConstraints()
        elif task.rMode == 1:
            dt = globalClock.getDt()
            pt = self.getMouseRayCollisionPt()
            self._rotatePtToPt(pt, task.startPt, dt * self._scrollFactor * 5)
            self._applyConstraints()
            self.createStraightArrow(task.startPt, pt, 0.02)
        elif task.rMode == 2:
            pt = self.getMouseRayCollisionPt()
            (q, area) = self._getRotateAboutAxisQuat(task.camPt, task.startPt,
                                                     pt)
            self._rotateQuatByQuat(task.quat, q, 1.0)
            self.saveNorth()
        elif task.rMode == 3:
            dt = globalClock.getDt()
            pt = self.getMouseRayCollisionPt()
            (q, area) = self._getRotateAboutAxisQuat(task.camPt, pt,
                                                     task.startPt)
            self._rotate(q, dt * self._scrollFactor * area * 300)
            self.createCurvedArrow(task.camPt, pt, task.startPt, 0.02)
            self.saveNorth()

        return task.cont

    def _stopRotateTask(self, *args):
        taskMgr.remove(self.getName() + '-rotateTask')
        self.tail_geom_node.removeAllGeoms()
        self.head_geom_node.removeAllGeoms()
        if self.rMode in [1]:
            props = WindowProperties()
            props.setCursorHidden(0)
            base.win.requestProperties(props)

    def createStraightArrow(self, p0, p1, width):
        p0.normalize()
        p1.normalize()
        dot = p0.dot(p1)
        cross = p0.cross(p1)
        arcLen = math.acos(clampScalar(-1, 1, dot))
        self.tail_geom_node.removeAllGeoms()
        self.head_geom_node.removeAllGeoms()
        if arcLen > 0.0:
            cross.normalize()
            cross *= width / 2.0
            theta = 2 * math.asin(width / 2.0)
            div = arcLen / theta
            steps = int(div)
            remainder = div - steps
            pts = []
            for n in range(steps + 1):
                pts.append(sLerp(p1, p0, n / div, arcLen) * self._radius)

            format = GeomVertexFormat.getV3c4t2()
            vertex_data = GeomVertexData('arc_ball', format, Geom.UHStatic)
            vertex_writer = GeomVertexWriter(vertex_data, 'vertex')
            color_writer = GeomVertexWriter(vertex_data, 'color')
            texture_writer = GeomVertexWriter(vertex_data, 'texcoord')
            triStrip = GeomTristrips(Geom.UHStatic)
            if len(pts) == 1:
                vertex_writer.addData3f(p1[0] - cross[0], p1[1] - cross[1],
                                        p1[2] - cross[2])
                vertex_writer.addData3f(p1[0] + cross[0], p1[1] + cross[1],
                                        p1[2] + cross[2])
                color_writer.addData4f(0, 1, 0, 1)
                color_writer.addData4f(0, 1, 0, 1)
                texture_writer.addData2f(1, 1)
                texture_writer.addData2f(0, 1)
                vertex_writer.addData3f(p0[0] - cross[0], p0[1] - cross[1],
                                        p0[2] - cross[2])
                vertex_writer.addData3f(p0[0] + cross[0], p0[1] + cross[1],
                                        p0[2] + cross[2])
                color_writer.addData4f(0, 1, 0, 1)
                color_writer.addData4f(0, 1, 0, 1)
                texture_writer.addData2f(1, 1 - remainder)
                texture_writer.addData2f(0, 1 - remainder)
                triStrip.addNextVertices(4)
            else:
                for pt in pts[:2]:
                    vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1],
                                            pt[2] - cross[2])
                    vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1],
                                            pt[2] + cross[2])
                    color_writer.addData4f(0, 1, 0, 1)
                    color_writer.addData4f(0, 1, 0, 1)

                texture_writer.addData2f(1, 1)
                texture_writer.addData2f(0, 1)
                texture_writer.addData2f(1, 0)
                texture_writer.addData2f(0, 0)
                triStrip.addNextVertices(4)
            geometry = Geom(vertex_data)
            geometry.addPrimitive(triStrip)
            self.head_geom_node.addGeom(geometry)
            format = GeomVertexFormat.getV3c4t2()
            vertex_data = GeomVertexData('arc_ball', format, Geom.UHStatic)
            vertex_writer = GeomVertexWriter(vertex_data, 'vertex')
            color_writer = GeomVertexWriter(vertex_data, 'color')
            texture_writer = GeomVertexWriter(vertex_data, 'texcoord')
            triStrip = GeomTristrips(Geom.UHStatic)
            for pt in pts[1:]:
                vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1],
                                        pt[2] - cross[2])
                vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1],
                                        pt[2] + cross[2])
                color_writer.addData4f(0, 1, 0, 1)
                color_writer.addData4f(0, 1, 0, 1)

            numPts = len(pts[1:])
            for x in range(numPts / 2):
                texture_writer.addData2f(1, 1)
                texture_writer.addData2f(0, 1)
                texture_writer.addData2f(1, 0)
                texture_writer.addData2f(0, 0)

            if numPts % 2:
                texture_writer.addData2f(1, 1)
                texture_writer.addData2f(0, 1)

            vertex_writer.addData3f(p0[0] - cross[0], p0[1] - cross[1],
                                    p0[2] - cross[2])
            vertex_writer.addData3f(p0[0] + cross[0], p0[1] + cross[1],
                                    p0[2] + cross[2])
            color_writer.addData4f(0, 1, 0, 1)
            color_writer.addData4f(0, 1, 0, 1)
            if numPts % 2:
                texture_writer.addData2f(1, 1 - remainder)
                texture_writer.addData2f(0, 1 - remainder)
            else:
                texture_writer.addData2f(1, remainder)
                texture_writer.addData2f(0, remainder)
            triStrip.addNextVertices(numPts * 2 + 2)
            geometry = Geom(vertex_data)
            geometry.addPrimitive(triStrip)
            self.tail_geom_node.addGeom(geometry)

    def createCurvedArrow(self, axis, p0, p1, width, numPanels=10):
        N = numPanels
        self.tail_geom_node.removeAllGeoms()
        self.head_geom_node.removeAllGeoms()
        axis = axis / axis.length()
        dot0 = axis.dot(p0)
        proj0 = p0 - axis * dot0
        dot1 = axis.dot(p1)
        proj1 = p1 - axis * dot1
        theta = math.acos(
            clampScalar(-1, 1,
                        proj0.dot(proj1) / proj0.length() * proj1.length()))
        if not proj0.almostEqual(proj1, 0.0001) and theta != 0:
            if proj0.lengthSquared() >= proj1.lengthSquared():
                A = proj0
                C = proj1
            else:
                A = proj1
                C = proj0
            a = A.length()
            aUnit = A / a
            x = A.dot(C) / a
            yy = C.lengthSquared() - x * x
            bUnit = A.cross(C).cross(A)
            bUnit.normalize()
            b = math.sqrt(max(0.0, yy / (1 - x * x / a * a)))
            t = math.atan2(a, b / math.tan(theta))
            aUnit *= a
            bUnit *= b
            pts = [
                aUnit * math.cos(x * t / N) + bUnit * math.sin(x * t / N)
                for x in range(N + 1)
            ]
            pts = [
                pt + axis *
                math.sqrt(self._radius * self._radius - pt.lengthSquared())
                for pt in pts
            ]
            if A != proj0:
                pts.reverse()

            format = GeomVertexFormat.getV3c4t2()
            vertex_data = GeomVertexData('arc_ball', format, Geom.UHStatic)
            vertex_writer = GeomVertexWriter(vertex_data, 'vertex')
            color_writer = GeomVertexWriter(vertex_data, 'color')
            texture_writer = GeomVertexWriter(vertex_data, 'texcoord')
            triStrip = GeomTristrips(Geom.UHStatic)
            cross = pts[0].cross(pts[1] - pts[0])
            cross.normalize()
            cross *= width / 2.0
            pt = pts[0]
            vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1],
                                    pt[2] + cross[2])
            vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1],
                                    pt[2] - cross[2])
            color_writer.addData4f(0, 1, 0, 1)
            color_writer.addData4f(0, 1, 0, 1)
            texture_writer.addData2f(0, 1)
            texture_writer.addData2f(1, 1)
            diffA = pts[1] - pts[0]
            diffB = pts[2] - pts[1]
            cross = pts[1].cross((diffB + diffA) / 2.0)
            cross.normalize()
            cross *= width / 2.0
            pt = pts[1]
            vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1],
                                    pt[2] + cross[2])
            vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1],
                                    pt[2] - cross[2])
            color_writer.addData4f(0, 1, 0, 1)
            color_writer.addData4f(0, 1, 0, 1)
            texture_writer.addData2f(0, 0)
            texture_writer.addData2f(1, 0)
            triStrip.addNextVertices(4)
            geometry = Geom(vertex_data)
            geometry.addPrimitive(triStrip)
            self.head_geom_node.addGeom(geometry)
            format = GeomVertexFormat.getV3c4t2()
            vertex_data = GeomVertexData('arc_ball', format, Geom.UHStatic)
            vertex_writer = GeomVertexWriter(vertex_data, 'vertex')
            color_writer = GeomVertexWriter(vertex_data, 'color')
            texture_writer = GeomVertexWriter(vertex_data, 'texcoord')
            triStrip = GeomTristrips(Geom.UHStatic)
            for x in range(len(pts[1:-1])):
                cross = pts[x + 1].cross(pts[x + 2] - pts[x])
                cross.normalize()
                cross *= width / 2.0
                pt = pts[x + 1]
                vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1],
                                        pt[2] + cross[2])
                vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1],
                                        pt[2] - cross[2])
                color_writer.addData4f(0, 1, 0, 1)
                color_writer.addData4f(0, 1, 0, 1)
                if x % 2:
                    texture_writer.addData2f(0, 1)
                    texture_writer.addData2f(1, 1)
                else:
                    texture_writer.addData2f(0, 0)
                    texture_writer.addData2f(1, 0)
                triStrip.addNextVertices(2)

            cross = pts[-1].cross(pts[-1] - pts[-2])
            cross.normalize()
            cross *= width / 2.0
            pt = pts[-1]
            vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1],
                                    pt[2] + cross[2])
            vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1],
                                    pt[2] - cross[2])
            color_writer.addData4f(0, 1, 0, 1)
            color_writer.addData4f(0, 1, 0, 1)
            if N % 2:
                texture_writer.addData2f(0, 0)
                texture_writer.addData2f(1, 0)
            else:
                texture_writer.addData2f(0, 1)
                texture_writer.addData2f(1, 1)
            triStrip.addNextVertices(2)
            geometry = Geom(vertex_data)
            geometry.addPrimitive(triStrip)
            self.tail_geom_node.addGeom(geometry)

    def _startArrowTask(self):
        taskMgr.add(self._arrowTask, self.getName() + '-arrowTask')

    def _arrowTask(self, task):
        if not hasattr(task, 'p0'):
            task.p0 = self.getMouseRayCollisionPt()
            task.p0.normalize()

        p1 = self.getMouseRayCollisionPt()
        p1.normalize()
        self.createStraightArrow(task.p0, p1, 0.02)
        return task.cont

    def _stopArrowTask(self):
        taskMgr.remove(self.getName() + '-arrowTask')
コード例 #29
0
class ArcBall(NodePath, DirectObject):

    def __init__(self, name, radius = 1, scrollFactor = 1, camera = base.cam, frame = Vec4(-1, 1, -1, 1), keepUpright = 0, mouseDownEvent = 'mouse1', mouseUpEvent = 'mouse1-up', *args, **kwargs):
        NodePath.__init__(self, name, *args, **kwargs)
        DirectObject.__init__(self)
        self._rNode = self.attachNewNode('rotateNode')
        self._setRadius(radius, False)
        self._setScrollFactor(scrollFactor, False)
        self._setCamera(camera, False)
        self._setFrame(frame, False)
        self._setKeepUpright(keepUpright)
        self._setMouseEvents(mouseDownEvent, mouseUpEvent)
        self.setRotateMode(0)
        self._setControlButtonState(0)
        self._setTiltLimit(25 * math.pi / 180, False)
        self.saveNorth()
        self._colBitMask = BitMask32(1 << 16)
        self._colNode = self.attachNewNode(CollisionNode(name + '-cNode'))
        self._colNode.node().addSolid(CollisionSphere(0, 0, 0, 1))
        self._colNode.node().setIntoCollideMask(self._colBitMask)
        self._mouseEnabled = True
        self._initCollisions()
        self.geom_node_path = self.attachNewNode('arrow')
        self.geom_node_path.setBin('fixed', 100)
        self.geom_node_path.setDepthTest(0)
        self.geom_node_path.setTransparency(1)
        self.head_geom_node = GeomNode('head')
        self.head_geom_node_path = self.geom_node_path.attachNewNode(self.head_geom_node)
        self.tail_geom_node = GeomNode('tail')
        self.tail_geom_node_path = self.geom_node_path.attachNewNode(self.tail_geom_node)
        self._ballIval = None


    def removeNode(self):
        self.ignoreAll()
        NodePath.removeNode(self)


    def _setRadius(self, radius, reset = True):
        self._radius = radius


    def _setScrollFactor(self, scrollFactor, reset = True):
        self._scrollFactor = float(scrollFactor)


    def _setCamera(self, cam, reset = True):
        self.cam = cam
        self.camNode = cam.node()
        self.camLens = self.camNode.getLens()


    def _setFrame(self, frame, reset = True):
        self._frame = frame
        self.saveTransforms()


    def _setKeepUpright(self, keepUpright):
        self._keepUpright = keepUpright


    def _setControlButtonState(self, state):
        self._ctrlBtnState = state


    def _setTiltLimit(self, limit = math.pi / 6, reset = True):
        self._tiltLimit = limit
        if reset:
            self._applyConstraints()



    def _setMouseEvents(self, down, up):
        if hasattr(self, '_mouseDownEventStr'):
            self.ignore(self._mouseDownEventStr)

        if hasattr(self, '_mouseUpEventStr'):
            self.ignore(self._mouseUpEventStr)

        self._mouseDownEventStr = down
        self._mouseUpEventStr = up
        self.accept(self._mouseDownEventStr, self._mouseDown)
        self.accept(self._mouseUpEventStr, self._mouseUp)


    def setRadius(self, radius):
        self._setRadius(radius)


    def setScrollFactor(self, scrollFactor):
        self._setScrollFactor(scrollFactor)


    def setCamera(self, camera):
        self._setCamera(camera)


    def setFrame(self, frame):
        self._setFrame(frame)


    def setKeepUpright(self, keepUpright):
        self._setKeepUpright(keepUpright)


    def setMouseEvents(self, downEvent, upEvent):
        self._setMouseEvents(downEvent, upEvent)


    def setMouseEnabled(self, enabled):
        self._mouseEnabled = enabled
        if not self._mouseEnabled:
            self._mouseUp()



    def setRotateMode(self, mode):
        self.rMode = mode


    def enable(self):
        self.setMouseEnabled(True)


    def disable(self):
        if self._ballIval:
            self._ballIval.pause()
            self._ballIval = None

        self.setMouseEnabled(False)


    def getRotateRoot(self):
        return self._rNode


    def attachForRotation(self, nodepath):
        nodepath.reparentTo(self._rNode)


    def getInternalHpr(self, *args, **kwargs):
        return self._rNode.getHpr(*args, **kwargs)


    def setInternalHpr(self, *args, **kwargs):
        self._rNode.setHpr(*args, **kwargs)


    def getInternalQuat(self, *args, **kwargs):
        return self._rNode.getQuat(*args, **kwargs)


    def setInternalQuat(self, *args, **kwargs):
        self._rNode.setQuat(*args, **kwargs)


    def _mouseDown(self, *args):
        if self._mouseEnabled:
            self._startRotateTask()



    def _mouseUp(self, *args):
        self._stopRotateTask()


    def _initCollisions(self):
        self.traverser = CollisionTraverser()
        self.colHandlerQueue = CollisionHandlerQueue()
        self.camRayNode = self.cam.attachNewNode(CollisionNode('camRayNode'))
        self.camRay = CollisionRay()
        self.camRayNode.node().addSolid(self.camRay)
        self.traverser.addCollider(self.camRayNode, self.colHandlerQueue)


    def _mouseRayCollide(self, rayBitMask = BitMask32.allOn()):
        if base.mouseWatcherNode.hasMouse():
            mousePt = base.mouseWatcherNode.getMouse()
            mousePt = self._transMouseToHomogenousFramePt(mousePt)
            self.camRay.setFromLens(self.camNode, mousePt[0], mousePt[1])
            self.camRayNode.node().setFromCollideMask(rayBitMask)
            self.traverser.traverse(self)
            self.traverser.traverse(self.getTop())
        else:
            self.colHandlerQueue.clearEntries()


    def _camRayCollide(self, rayBitMask = BitMask32.allOn()):
        self.camRay.setOrigin(Point3(0))
        self.camRay.setDirection(Vec3(0, 1, 0))
        self.camRayNode.node().setFromCollideMask(rayBitMask)
        self.traverser.traverse(self)
        self.traverser.traverse(self.getTop())


    def getHorizonCollisionPt(self, raySpace = None, rayDirection = None):
        raySpaceToSelf = raySpace.getTransform(self)
        rayOrig = raySpaceToSelf.getMat().xformPoint(Point3(0))
        rayDist = rayOrig.length()
        ray = raySpaceToSelf.getMat().xformPoint(rayDirection)
        a = rayOrig * self._radius * self._radius / rayDist * rayDist
        b = -rayOrig.cross(ray).cross(-rayOrig)
        b.normalize()
        b *= math.sqrt(1 - 1 / rayDist / rayDist)
        return a + b


    def _getCollisionPt(self):
        entryCount = self.colHandlerQueue.getNumEntries()
        for x in range(entryCount):
            entry = self.colHandlerQueue.getEntry(x)
            if entry.getIntoNode().getName() == self.getName() + '-cNode':
                return entry.getSurfacePoint(entry.getIntoNodePath())
                continue

        camRay = self.camRayNode.node().getSolid(0).getDirection()
        pt = self.getHorizonCollisionPt(self.cam, camRay)
        return pt


    def getMouseRayCollisionPt(self, rayBitMask = None):
        if not rayBitMask:
            rayBitMask = self._colBitMask

        self._mouseRayCollide(rayBitMask)
        return self._getCollisionPt()


    def getCamRayCollisionPt(self, rayBitMask = None):
        if not rayBitMask:
            rayBitMask = self._colBitMask

        self._camRayCollide(rayBitMask)
        return self._getCollisionPt()


    def _getCollisionEntry(self):
        entryCount = self.colHandlerQueue.getNumEntries()
        if entryCount:
            self.colHandlerQueue.sort()
            return self.colHandlerQueue.getEntry(0)
        else:
            return None


    def getMouseRayCollisionEntry(self, rayBitMask = None):
        if not rayBitMask:
            rayBitMask = self._colBitMask

        self._mouseRayCollide(rayBitMask)
        return self._getCollisionEntry()


    def saveTransforms(self):
        frame = self._frame
        ll = Point3(frame[0], frame[2], 0)
        ur = Point3(frame[1], frame[3], 0)
        aspectTs = TransformState.makeScale2d(Point2(1 / base.camLens.getAspectRatio(), 1))
        ll = aspectTs.getMat().xformPoint(ll)
        ur = aspectTs.getMat().xformPoint(ur)
        posTs = TransformState.makePos2d(Point2(ll[0] + ur[0], ll[1] + ur[1]) / -2.0)
        scaleTs = TransformState.makeScale2d(Point2(2.0 / (ur[0] - ll[0]), 2.0 / (ur[1] - ll[1])))
        frameTs = scaleTs.compose(posTs)
        self._mouseToHomogenousFrameMat = Mat4(frameTs.getMat())
        self._mouseToHomogenousFrameMatInv = Mat4(frameTs.getInverse().getMat())
        self._camLensProjMat = Mat4(self.camLens.getProjectionMat())
        self._camLensProjMatInv = Mat4(self._camLensProjMat)
        self._camLensProjMatInv.invertInPlace()


    def _transMouseToHomogenousFramePt(self, pt):
        pt = Point3(pt[0], pt[1], 0)
        return self._mouseToHomogenousFrameMat.xformPoint(pt)


    def _transHomogenousFrameToMousePt(self, pt):
        return self._mouseToHomogenousFrameMatInv.xformPoint(pt)


    def _transCamSpaceToHomogenousFramePt(self, pt):
        pt = self._camLensProjMat.xform(Vec4(pt[0], pt[1], pt[2], 1))
        pt /= pt[3]
        return pt


    def _transHomogenousFrameToCamSpacePt(self, pt):
        pt = self._camLensProjMatInv.xform(Vec4(pt[0], pt[1], pt[2], 1))
        pt /= pt[3]
        return pt


    def setNorth(self, northVec):
        self._north = northVec


    def saveNorth(self):
        upSpaceNodePath = self
        Z = Vec3.unitZ()
        upSpaceToRNode = TransformState.makeHpr(upSpaceNodePath.getHpr(self._rNode))
        self._north = upSpaceToRNode.getMat().xformPoint(Z)


    def _applyConstraints(self):
        self._rotate(self.getOrthTiltLimitQuat(self._tiltLimit), 1.0)
        if self._keepUpright:
            self.clampOrientationAboutSpherePt(self.getCamRayCollisionPt())



    def getTiltLimitQuat(self, thetaLimit):
        Y = Vec3.unitY()
        Z = Vec3.unitZ()
        upSpaceNodePath = self
        rNodeNorth = Z
        arcballNorth = -Y
        rNodeToUpSpace = TransformState.makeHpr(self._rNode.getHpr(upSpaceNodePath))
        northPole = rNodeToUpSpace.getMat().xformPoint(rNodeNorth)
        dot = northPole.dot(arcballNorth)
        theta = math.acos(clampScalar(-1, 1, dot))
        if theta < thetaLimit:
            return Quat.identQuat()
        else:
            axis = northPole.cross(arcballNorth)
            axis.normalize()
            theta -= thetaLimit
            return Quat(math.cos(theta / 2.0), axis * math.sin(theta / 2.0))


    def getOrthTiltLimitQuat(self, thetaLimit = 10):
        X = Vec3.unitX()
        Y = Vec3.unitY()
        Z = Vec3.unitZ()
        upSpaceNodePath = self
        rNodeNorth = Z
        arcballNorth = -Y
        baseQuat = self._rNode.getQuat(upSpaceNodePath)
        quatX = Quat.identQuat()
        quatY = Quat.identQuat()
        rNodeToUpSpace = TransformState.makeQuat(baseQuat)
        northPole = rNodeToUpSpace.getMat().xformPoint(rNodeNorth)
        dot = northPole.dot(X)
        proj = northPole - X * dot
        theta = math.acos(clampScalar(-1.0, 1.0, proj.dot(arcballNorth) / proj.length()))
        if theta > thetaLimit:
            theta -= thetaLimit
            if northPole.dot(Z) < 0.0:
                theta *= -1

            quatX = Quat(math.cos(theta / 2.0), X * math.sin(theta / 2.0))
            baseQuat *= quatX
            rNodeToUpSpace = TransformState.makeQuat(baseQuat)
            northPole = rNodeToUpSpace.getMat().xformPoint(rNodeNorth)

        dot = northPole.dot(Z)
        proj = northPole - Z * dot
        theta = math.acos(clampScalar(-1.0, 1.0, proj.dot(arcballNorth) / proj.length()))
        if theta > thetaLimit:
            theta -= thetaLimit
            if northPole.dot(X) >= 0.0:
                theta *= -1

            quatY = Quat(math.cos(theta / 2.0), Z * math.sin(theta / 2.0))
            baseQuat *= quatY

        return quatX * quatY


    def getUprightCorrectionQuat(self, pt):
        Y = Vec3.unitY()
        Z = Vec3.unitZ()
        rNodeNorth = self._north
        upSpaceNodePath = self
        axis = pt / pt.length()
        up = Z
        rNodeToUpSpace = TransformState.makeHpr(self._rNode.getHpr(upSpaceNodePath))
        northPole = rNodeToUpSpace.getMat().xformPoint(rNodeNorth)
        right = up.cross(axis)
        final = axis.cross(right)
        dot = northPole.dot(axis)
        proj = northPole - axis * dot
        theta = math.acos(clampScalar(-1.0, 1.0, proj.dot(final) / proj.length() * final.length()))
        if northPole.dot(right) < 0.0:
            theta *= -1

        return Quat(math.cos(theta / 2.0), Vec3(axis) * math.sin(theta / 2.0))


    def _rotate(self, q, factor = 1.0):
        q = nLerp(Quat(1, Vec3(0)), q, factor)
        self._rNode.setQuat(self._rNode.getQuat() * q)


    def _rotatePtToPt(self, p0, p1, factor = 1.0):
        self._rotate(self._getPtToPtQuat(p0, p1), factor)


    def _getPtToPtQuat(self, p0, p1, factor = 1.0):
        p0.normalize()
        p1.normalize()
        theta = math.acos(clampScalar(-1, 1, p0.dot(p1)))
        axis = p0.cross(p1)
        axis.normalize()
        if factor == 1.0:
            return Quat(math.cos(theta / 2.0), axis * math.sin(theta / 2.0))
        elif 0.0 < factor:
            pass
        elif factor == 1.0:
            q = nLerp(Quat.identQuat(), Quat(math.cos(theta / 2.0), axis * math.sin(theta / 2.0)), factor)
            return q



    def _getRotateAboutAxisQuat(self, axis, p0, p1, factor = 1.0):
        axis = axis / axis.length()
        dot0 = axis.dot(p0)
        proj0 = p0 - axis * dot0
        dot1 = axis.dot(p1)
        proj1 = p1 - axis * dot1
        axis = proj0.cross(proj1)
        area = axis.length()
        axis.normalize()
        theta = math.acos(clampScalar(-1, 1, proj0.dot(proj1) / proj0.length() * proj1.length()))
        return (Quat(math.cos(theta / 2.0), axis * math.sin(theta / 2.0)), area)


    def _rotateQuatByQuat(self, q0, q1, factor = 1.0):
        self._rNode.setQuat(nLerp(q0, q0 * q1, factor))


    def clampOrientationAboutSpherePt(self, pt):
        q = self.getUprightCorrectionQuat(pt)
        self._rotate(q, 1.0)


    def rotatePtToCenter(self, pt):
        centerPt = self.getCamRayCollisionPt()
        self._rotatePtToPt(pt, centerPt)
        self._applyConstraints()


    def rotateSpherePtToCenter(self, spherePt):
        pt = self._colNode.getRelativePoint(self._rNode, spherePt)
        self.rotatePtToCenter(pt)


    def clampSpherePtToHorizon(self, pt):
        camRaySpherePt = self.findCamRaySpherePt(pt)
        if camRaySpherePt and not pt.almostEqual(camRaySpherePt, 0.0001):
            camToSphere = self.cam.getTransform(self._rNode)
            OC = camToSphere.getMat().xformPoint(Vec3(0, 0, 0))
            theta = math.acos(clampScalar(-1.0, 1.0, self._radius / OC.length()))
            axis = OC.cross(pt)
            axis.normalize()
            q = Quat(math.cos(theta / 2), axis * math.sin(theta / 2))
            ts = TransformState.makeQuat(q)
            OC.normalize()
            OC *= self._radius
            newPt = ts.getMat().xformPoint(OC)
            dTheta = math.acos(clampScalar(-1.0, 1.0, pt.dot(newPt)))
            return (newPt, dTheta)
        else:
            return (pt, 0)


    def reorientNorth(self, time = 0.0):
        self.setNorth(Vec3(0, 1, 0))
        curQ = self.getInternalQuat()
        pt = self.getCamRayCollision()
        upQ = self.getUprightCorrectionQuat(pt)

        def rotateFunc(t):
            self._rotateQuatByQuat(curQ, upQ, t)

        if self._ballIval:
            self._ballIval.pause()

        self._ballIval = LerpFunc(rotateFunc, duration = time)
        self._ballIval.start()


    def showRotationSphere(self):
        if not hasattr(self, '_ArcBall_rotGuide'):
            self._rotGuide = loader.loadModel('models/misc/sphere')
            self._rotGuide.setName('RotationGuide')
            self._rotGuide.setRenderModeWireframe()
            self._rotGuide.setTwoSided(1)
            self._rotGuide.setTextureOff(1)
            self._rotGuide.setColor(Vec4(1, 0, 0, 1))
            self._rotGuide.reparentTo(self.getRotateRoot())

        self._rotGuide.setScale(self._radius)
        self._rotGuide.show()


    def hideRotationSphere(self):
        if hasattr(self, '_ArcBall_rotGuide'):
            self._rotGuide.hide()



    def _startRotateTask(self, *args):
        self.saveTransforms()
        modePairs = ((0, 2), (1, 3))
        if not self._ctrlBtnState:
            rMode = modePairs[self.rMode][0]
        else:
            rMode = modePairs[self.rMode][1]
        if self.rMode in [
            1]:
            props = WindowProperties()
            props.setCursorHidden(1)
            base.win.requestProperties(props)

        task = taskMgr.add(self._rotateTask, self.getName() + '-rotateTask')
        task.rMode = rMode


    def _rotateTask(self, task):
        if not hasattr(task, 'startPt'):
            task.startPt = self.getMouseRayCollisionPt()
            task.camPt = self.getCamRayCollisionPt()
            task.quat = self._rNode.getQuat()

        if task.rMode == 0:
            pt = self.getMouseRayCollisionPt()
            q = self._getPtToPtQuat(task.startPt, pt)
            self._rotateQuatByQuat(task.quat, q, 1.0)
            self._applyConstraints()
        elif task.rMode == 1:
            dt = globalClock.getDt()
            pt = self.getMouseRayCollisionPt()
            self._rotatePtToPt(pt, task.startPt, dt * self._scrollFactor * 5)
            self._applyConstraints()
            self.createStraightArrow(task.startPt, pt, 0.02)
        elif task.rMode == 2:
            pt = self.getMouseRayCollisionPt()
            (q, area) = self._getRotateAboutAxisQuat(task.camPt, task.startPt, pt)
            self._rotateQuatByQuat(task.quat, q, 1.0)
            self.saveNorth()
        elif task.rMode == 3:
            dt = globalClock.getDt()
            pt = self.getMouseRayCollisionPt()
            (q, area) = self._getRotateAboutAxisQuat(task.camPt, pt, task.startPt)
            self._rotate(q, dt * self._scrollFactor * area * 300)
            self.createCurvedArrow(task.camPt, pt, task.startPt, 0.02)
            self.saveNorth()

        return task.cont


    def _stopRotateTask(self, *args):
        taskMgr.remove(self.getName() + '-rotateTask')
        self.tail_geom_node.removeAllGeoms()
        self.head_geom_node.removeAllGeoms()
        if self.rMode in [
            1]:
            props = WindowProperties()
            props.setCursorHidden(0)
            base.win.requestProperties(props)



    def createStraightArrow(self, p0, p1, width):
        p0.normalize()
        p1.normalize()
        dot = p0.dot(p1)
        cross = p0.cross(p1)
        arcLen = math.acos(clampScalar(-1, 1, dot))
        self.tail_geom_node.removeAllGeoms()
        self.head_geom_node.removeAllGeoms()
        if arcLen > 0.0:
            cross.normalize()
            cross *= width / 2.0
            theta = 2 * math.asin(width / 2.0)
            div = arcLen / theta
            steps = int(div)
            remainder = div - steps
            pts = []
            for n in range(steps + 1):
                pts.append(sLerp(p1, p0, n / div, arcLen) * self._radius)

            format = GeomVertexFormat.getV3c4t2()
            vertex_data = GeomVertexData('arc_ball', format, Geom.UHStatic)
            vertex_writer = GeomVertexWriter(vertex_data, 'vertex')
            color_writer = GeomVertexWriter(vertex_data, 'color')
            texture_writer = GeomVertexWriter(vertex_data, 'texcoord')
            triStrip = GeomTristrips(Geom.UHStatic)
            if len(pts) == 1:
                vertex_writer.addData3f(p1[0] - cross[0], p1[1] - cross[1], p1[2] - cross[2])
                vertex_writer.addData3f(p1[0] + cross[0], p1[1] + cross[1], p1[2] + cross[2])
                color_writer.addData4f(0, 1, 0, 1)
                color_writer.addData4f(0, 1, 0, 1)
                texture_writer.addData2f(1, 1)
                texture_writer.addData2f(0, 1)
                vertex_writer.addData3f(p0[0] - cross[0], p0[1] - cross[1], p0[2] - cross[2])
                vertex_writer.addData3f(p0[0] + cross[0], p0[1] + cross[1], p0[2] + cross[2])
                color_writer.addData4f(0, 1, 0, 1)
                color_writer.addData4f(0, 1, 0, 1)
                texture_writer.addData2f(1, 1 - remainder)
                texture_writer.addData2f(0, 1 - remainder)
                triStrip.addNextVertices(4)
            else:
                for pt in pts[:2]:
                    vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1], pt[2] - cross[2])
                    vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1], pt[2] + cross[2])
                    color_writer.addData4f(0, 1, 0, 1)
                    color_writer.addData4f(0, 1, 0, 1)

                texture_writer.addData2f(1, 1)
                texture_writer.addData2f(0, 1)
                texture_writer.addData2f(1, 0)
                texture_writer.addData2f(0, 0)
                triStrip.addNextVertices(4)
            geometry = Geom(vertex_data)
            geometry.addPrimitive(triStrip)
            self.head_geom_node.addGeom(geometry)
            format = GeomVertexFormat.getV3c4t2()
            vertex_data = GeomVertexData('arc_ball', format, Geom.UHStatic)
            vertex_writer = GeomVertexWriter(vertex_data, 'vertex')
            color_writer = GeomVertexWriter(vertex_data, 'color')
            texture_writer = GeomVertexWriter(vertex_data, 'texcoord')
            triStrip = GeomTristrips(Geom.UHStatic)
            for pt in pts[1:]:
                vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1], pt[2] - cross[2])
                vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1], pt[2] + cross[2])
                color_writer.addData4f(0, 1, 0, 1)
                color_writer.addData4f(0, 1, 0, 1)

            numPts = len(pts[1:])
            for x in range(numPts / 2):
                texture_writer.addData2f(1, 1)
                texture_writer.addData2f(0, 1)
                texture_writer.addData2f(1, 0)
                texture_writer.addData2f(0, 0)

            if numPts % 2:
                texture_writer.addData2f(1, 1)
                texture_writer.addData2f(0, 1)

            vertex_writer.addData3f(p0[0] - cross[0], p0[1] - cross[1], p0[2] - cross[2])
            vertex_writer.addData3f(p0[0] + cross[0], p0[1] + cross[1], p0[2] + cross[2])
            color_writer.addData4f(0, 1, 0, 1)
            color_writer.addData4f(0, 1, 0, 1)
            if numPts % 2:
                texture_writer.addData2f(1, 1 - remainder)
                texture_writer.addData2f(0, 1 - remainder)
            else:
                texture_writer.addData2f(1, remainder)
                texture_writer.addData2f(0, remainder)
            triStrip.addNextVertices(numPts * 2 + 2)
            geometry = Geom(vertex_data)
            geometry.addPrimitive(triStrip)
            self.tail_geom_node.addGeom(geometry)



    def createCurvedArrow(self, axis, p0, p1, width, numPanels = 10):
        N = numPanels
        self.tail_geom_node.removeAllGeoms()
        self.head_geom_node.removeAllGeoms()
        axis = axis / axis.length()
        dot0 = axis.dot(p0)
        proj0 = p0 - axis * dot0
        dot1 = axis.dot(p1)
        proj1 = p1 - axis * dot1
        theta = math.acos(clampScalar(-1, 1, proj0.dot(proj1) / proj0.length() * proj1.length()))
        if not proj0.almostEqual(proj1, 0.0001) and theta != 0:
            if proj0.lengthSquared() >= proj1.lengthSquared():
                A = proj0
                C = proj1
            else:
                A = proj1
                C = proj0
            a = A.length()
            aUnit = A / a
            x = A.dot(C) / a
            yy = C.lengthSquared() - x * x
            bUnit = A.cross(C).cross(A)
            bUnit.normalize()
            b = math.sqrt(max(0.0, yy / (1 - x * x / a * a)))
            t = math.atan2(a, b / math.tan(theta))
            aUnit *= a
            bUnit *= b
            pts = [ aUnit * math.cos(x * t / N) + bUnit * math.sin(x * t / N) for x in range(N + 1) ]
            pts = [ pt + axis * math.sqrt(self._radius * self._radius - pt.lengthSquared()) for pt in pts ]
            if A != proj0:
                pts.reverse()

            format = GeomVertexFormat.getV3c4t2()
            vertex_data = GeomVertexData('arc_ball', format, Geom.UHStatic)
            vertex_writer = GeomVertexWriter(vertex_data, 'vertex')
            color_writer = GeomVertexWriter(vertex_data, 'color')
            texture_writer = GeomVertexWriter(vertex_data, 'texcoord')
            triStrip = GeomTristrips(Geom.UHStatic)
            cross = pts[0].cross(pts[1] - pts[0])
            cross.normalize()
            cross *= width / 2.0
            pt = pts[0]
            vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1], pt[2] + cross[2])
            vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1], pt[2] - cross[2])
            color_writer.addData4f(0, 1, 0, 1)
            color_writer.addData4f(0, 1, 0, 1)
            texture_writer.addData2f(0, 1)
            texture_writer.addData2f(1, 1)
            diffA = pts[1] - pts[0]
            diffB = pts[2] - pts[1]
            cross = pts[1].cross((diffB + diffA) / 2.0)
            cross.normalize()
            cross *= width / 2.0
            pt = pts[1]
            vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1], pt[2] + cross[2])
            vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1], pt[2] - cross[2])
            color_writer.addData4f(0, 1, 0, 1)
            color_writer.addData4f(0, 1, 0, 1)
            texture_writer.addData2f(0, 0)
            texture_writer.addData2f(1, 0)
            triStrip.addNextVertices(4)
            geometry = Geom(vertex_data)
            geometry.addPrimitive(triStrip)
            self.head_geom_node.addGeom(geometry)
            format = GeomVertexFormat.getV3c4t2()
            vertex_data = GeomVertexData('arc_ball', format, Geom.UHStatic)
            vertex_writer = GeomVertexWriter(vertex_data, 'vertex')
            color_writer = GeomVertexWriter(vertex_data, 'color')
            texture_writer = GeomVertexWriter(vertex_data, 'texcoord')
            triStrip = GeomTristrips(Geom.UHStatic)
            for x in range(len(pts[1:-1])):
                cross = pts[x + 1].cross(pts[x + 2] - pts[x])
                cross.normalize()
                cross *= width / 2.0
                pt = pts[x + 1]
                vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1], pt[2] + cross[2])
                vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1], pt[2] - cross[2])
                color_writer.addData4f(0, 1, 0, 1)
                color_writer.addData4f(0, 1, 0, 1)
                if x % 2:
                    texture_writer.addData2f(0, 1)
                    texture_writer.addData2f(1, 1)
                else:
                    texture_writer.addData2f(0, 0)
                    texture_writer.addData2f(1, 0)
                triStrip.addNextVertices(2)

            cross = pts[-1].cross(pts[-1] - pts[-2])
            cross.normalize()
            cross *= width / 2.0
            pt = pts[-1]
            vertex_writer.addData3f(pt[0] + cross[0], pt[1] + cross[1], pt[2] + cross[2])
            vertex_writer.addData3f(pt[0] - cross[0], pt[1] - cross[1], pt[2] - cross[2])
            color_writer.addData4f(0, 1, 0, 1)
            color_writer.addData4f(0, 1, 0, 1)
            if N % 2:
                texture_writer.addData2f(0, 0)
                texture_writer.addData2f(1, 0)
            else:
                texture_writer.addData2f(0, 1)
                texture_writer.addData2f(1, 1)
            triStrip.addNextVertices(2)
            geometry = Geom(vertex_data)
            geometry.addPrimitive(triStrip)
            self.tail_geom_node.addGeom(geometry)



    def _startArrowTask(self):
        taskMgr.add(self._arrowTask, self.getName() + '-arrowTask')


    def _arrowTask(self, task):
        if not hasattr(task, 'p0'):
            task.p0 = self.getMouseRayCollisionPt()
            task.p0.normalize()

        p1 = self.getMouseRayCollisionPt()
        p1.normalize()
        self.createStraightArrow(task.p0, p1, 0.02)
        return task.cont


    def _stopArrowTask(self):
        taskMgr.remove(self.getName() + '-arrowTask')
コード例 #30
0
ファイル: main.py プロジェクト: court-jus/Gate
class FPS(object,DirectObject): 
    def __init__(self): 
        self.winXhalf = base.win.getXSize()/2 
        self.winYhalf = base.win.getYSize()/2 
        self.initCollision() 
        self.loadLevel() 
        self.initPlayer() 

    def initCollision(self): 
        #initialize traverser 
        base.cTrav = CollisionTraverser() 
        base.cTrav.setRespectPrevTransform(True) 
#         base.cTrav.showCollisions(render) 
        #initialize pusher 
        self.pusher = CollisionHandlerPusher() 
        # collision bits 
        self.groundCollBit = BitMask32.bit(0) 
        self.collBitOff = BitMask32.allOff() 

    def loadLevel(self): 

        #load level 
        # must have 
        #<Group> *something* { 
        #  <Collide> { Polyset keep descend } in the egg file 
        level = loader.loadModel("models/environment") 
        level.reparentTo(render) 
        level.setPos(0,0,0) 
        level.setColor(1,1,1,.5) 

    def initPlayer(self): 
        #load man 
        self.man = render.attachNewNode('man') # keep this node scaled to identity 
        self.man.setPos(0,0,0) 
        # should be avatar model 
#         model = loader.loadModel('teapot') 
#         model.reparentTo(self.man) 
#         model.setScale(.05) 
        # camera 
        base.camera.reparentTo(self.man) 
        base.camera.setPos(0,0,1.7) 
        base.camLens.setNearFar(.1,1000) 
        base.disableMouse() 
        #create a collsion solid around the man 
        manC = self.man.attachCollisionSphere('manSphere', 0,0,1, .4, self.groundCollBit,self.collBitOff) 
        self.pusher.addCollider(manC,self.man) 
        base.cTrav.addCollider(manC,self.pusher) 

        speed = 4 
        Forward = Vec3(0,speed*2,0) 
        Back = Vec3(0,-speed,0) 
        Left = Vec3(-speed,0,0) 
        Right = Vec3(speed,0,0) 
        Stop = Vec3(0) 
        self.walk = Stop 
        self.strife = Stop 
        self.jump = 0 
        taskMgr.add(self.move, 'move-task') 
        self.jumping = LerpFunc( Functor(self.__setattr__,"jump"), 
                                 duration=.25, fromData=.25, toData=0) 
        self.accept( "escape",sys.exit ) 
        self.accept( "space" , self.startJump) 
        self.accept( "s" , self.__setattr__,["walk",Back] ) 
        self.accept( "w" , self.__setattr__,["walk",Forward]) 
        self.accept( "s-up" , self.__setattr__,["walk",Stop] ) 
        self.accept( "w-up" , self.__setattr__,["walk",Stop] ) 
        self.accept( "a" , self.__setattr__,["strife",Left]) 
        self.accept( "d" , self.__setattr__,["strife",Right] ) 
        self.accept( "a-up" , self.__setattr__,["strife",Stop] ) 
        self.accept( "d-up" , self.__setattr__,["strife",Stop] ) 

        self.manGroundColNp = self.man.attachCollisionRay( 'manRay', 
                                                           0,0,.6, 0,0,-1, 
                                                           self.groundCollBit,self.collBitOff) 
        self.manGroundHandler = CollisionHandlerGravity() 
        self.manGroundHandler.addCollider(self.manGroundColNp,self.man) 
        base.cTrav.addCollider(self.manGroundColNp, self.manGroundHandler) 

    def startJump(self): 
        if self.manGroundHandler.isOnGround(): 
           self.jumping.start() 

    def move(self,task): 
        dt=globalClock.getDt() 
        # mouse 
        md = base.win.getPointer(0) 
        x = md.getX() 
        y = md.getY() 
        if base.win.movePointer(0, self.winXhalf, self.winYhalf): 
            self.man.setH(self.man, (x - self.winXhalf)*-0.1) 
            base.camera.setP( clampScalar(-90,90, base.camera.getP() - (y - self.winYhalf)*0.1) ) 
        # move where the keys set it 
        moveVec=(self.walk+self.strife)*dt # horisontal 
        moveVec.setZ( self.jump )          # vertical 
        self.man.setFluidPos(self.man,moveVec) 
        # jump damping 
        if self.jump>0: 
           self.jump = clampScalar( 0,1, self.jump*.9 ) 

        return task.cont