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
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))
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)
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)
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 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()
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()
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()
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()
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()
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()
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
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)
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()
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 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()
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, )
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()
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))
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()
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 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()
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()
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
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
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')
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')
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