""" PhysicsWalker.py is for avatars. A walker control such as this one provides: - creation of the collision nodes - handling the keyboard and mouse input for avatar movement - moving the avatar it does not: - play sounds - play animations although it does send messeges that allow a listener to play sounds or animations based on walker events. """ from ShowBaseGlobal import * import DirectNotifyGlobal import DirectObject import PhysicsManager import math #import LineStream class PhysicsWalker(DirectObject.DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory("PhysicsWalker") wantAvatarPhysicsIndicator = base.config.GetBool('want-avatar-physics-indicator', 0) useLifter = 0 useHeightRay = 0 # special methods def __init__(self, gravity = -32.1740, standableGround=0.707, hardLandingForce=16.0): assert(self.debugPrint("PhysicsWalker(gravity=%s, standableGround=%s)"%( gravity, standableGround))) DirectObject.DirectObject.__init__(self) self.__gravity=gravity self.__standableGround=standableGround self.__hardLandingForce=hardLandingForce self.needToDeltaPos = 0 self.physVelocityIndicator=None self.avatarControlForwardSpeed=0 self.avatarControlJumpForce=0 self.avatarControlReverseSpeed=0 self.avatarControlRotateSpeed=0 self.__oldAirborneHeight=None self.getAirborneHeight=None self.__oldContact=None self.__oldPosDelta=Vec3(0) self.__oldDt=0 self.__speed=0.0 self.__rotationSpeed=0.0 self.__slideSpeed=0.0 self.__vel=Vec3(0.0) self.collisionsActive = 0 self.isAirborne = 0 self.highMark = 0 def spawnTest(self): assert(self.debugPrint("\n\nspawnTest()\n")) if not self.wantAvatarPhysicsIndicator: return from PandaModules import * from IntervalGlobal import * import MovingPlatform if hasattr(self, "platform"): # Remove the prior instantiation: self.moveIval.pause() del self.moveIval self.platform.destroy() del self.platform model = loader.loadModelCopy('phase_9/models/cogHQ/platform1') fakeId = id(self) self.platform = MovingPlatform.MovingPlatform() self.platform.setupCopyModel(fakeId, model, 'platformcollision') self.platformRoot = render.attachNewNode("physicsWalker-spawnTest-%s"%fakeId) self.platformRoot.setPos(toonbase.localToon, Vec3(0.0, 3.0, 1.0)) self.platformRoot.setHpr(toonbase.localToon, Vec3.zero()) self.platform.reparentTo(self.platformRoot) startPos = Vec3(0.0, -15.0, 0.0) endPos = Vec3(0.0, 15.0, 0.0) distance = Vec3(startPos-endPos).length() duration = distance/4 self.moveIval = Sequence( WaitInterval(0.3), LerpPosInterval(self.platform, duration, endPos, startPos=startPos, name='platformOut%s' % fakeId, fluid = 1), WaitInterval(0.3), LerpPosInterval(self.platform, duration, startPos, startPos=endPos, name='platformBack%s' % fakeId, fluid = 1), name='platformIval%s' % fakeId, ) self.moveIval.loop() def setWalkSpeed(self, forward, jump, reverse, rotate): assert(self.debugPrint("setWalkSpeed()")) self.avatarControlForwardSpeed=forward self.avatarControlJumpForce=jump self.avatarControlReverseSpeed=reverse self.avatarControlRotateSpeed=rotate def getSpeeds(self): #assert(self.debugPrint("getSpeeds()")) return (self.__speed, self.__rotationSpeed) def setupRay(self, floorBitmask, floorOffset): # This is a ray cast from your head down to detect floor polygons # A toon is about 4.0 feet high, so start it there self.cRay = CollisionRay(0.0, 0.0, 4.0, 0.0, 0.0, -1.0) cRayNode = CollisionNode('PW.cRayNode') cRayNode.addSolid(self.cRay) self.cRayNodePath = self.avatarNodePath.attachNewNode(cRayNode) self.cRayBitMask = floorBitmask cRayNode.setFromCollideMask(self.cRayBitMask) cRayNode.setIntoCollideMask(BitMask32.allOff()) if 1 or self.useLifter: # set up floor collision mechanism self.lifter = CollisionHandlerFloor() self.lifter.setInPattern("enter%in") self.lifter.setOutPattern("exit%in") self.lifter.setOffset(floorOffset) # Limit our rate-of-fall with the lifter. # If this is too low, we actually "fall" off steep stairs # and float above them as we go down. I increased this # from 8.0 to 16.0 to prevent this #self.lifter.setMaxVelocity(16.0) #self.bobNodePath = self.avatarNodePath.attachNewNode("bob") #self.lifter.addCollider(self.cRayNodePath, self.cRayNodePath) self.lifter.addCollider(self.cRayNodePath, self.avatarNodePath) else: # useCollisionHandlerQueue self.cRayQueue = CollisionHandlerQueue() self.cTrav.addCollider(self.cRayNodePath, self.cRayQueue) def determineHeight(self): """ returns the height of the avatar above the ground. If there is no floor below the avatar, 0.0 is returned. aka get airborne height. """ if self.useLifter: height = self.avatarNodePath.getPos(self.cRayNodePath) # If the shadow where not pointed strait down, we would need to # get magnitude of the vector. Since it is strait down, we'll # just get the z: #spammy --> assert self.debugPrint("getAirborneHeight() returning %s"%(height.getZ(),)) assert onScreenDebug.add("height", height.getZ()) return height.getZ() - self.floorOffset else: # useCollisionHandlerQueue """ returns the height of the avatar above the ground. If there is no floor below the avatar, 0.0 is returned. aka get airborne height. """ height = 0.0 #*#self.cRayTrav.traverse(render) if self.cRayQueue.getNumEntries() != 0: # ...we have a floor. # Choose the highest of the possibly several floors we're over: self.cRayQueue.sortEntries() floorPoint = self.cRayQueue.getEntry(0).getFromIntersectionPoint() height = -floorPoint.getZ() self.cRayQueue.clearEntries() if __debug__: onScreenDebug.add("height", height) return height def setupSphere(self, bitmask, avatarRadius): """ Set up the collision sphere """ # This is a sphere on the ground to detect barrier collisions self.avatarRadius = avatarRadius centerHeight = avatarRadius if self.useHeightRay: centerHeight *= 2.0 self.cSphere = CollisionSphere(0.0, 0.0, centerHeight, avatarRadius) cSphereNode = CollisionNode('PW.cSphereNode') cSphereNode.addSolid(self.cSphere) self.cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode) self.cSphereBitMask = bitmask cSphereNode.setFromCollideMask(self.cSphereBitMask) cSphereNode.setIntoCollideMask(BitMask32.allOff()) # set up collision mechanism self.pusher = PhysicsCollisionHandler() self.pusher.setInPattern("enter%in") self.pusher.setOutPattern("exit%in") self.pusher.addCollider(self.cSphereNodePath, self.avatarNodePath) def setupPhysics(self, avatarNodePath): assert(self.debugPrint("setupPhysics()")) # Connect to Physics Manager: self.actorNode=ActorNode("physicsActor") self.actorNode.getPhysicsObject().setOriented(1) self.actorNode.getPhysical(0).setViscosity(0.1) physicsActor=NodePath(self.actorNode) avatarNodePath.reparentTo(physicsActor) avatarNodePath.assign(physicsActor) self.phys=PhysicsManager.PhysicsManager() fn=ForceNode("gravity") fnp=NodePath(fn) #fnp.reparentTo(physicsActor) fnp.reparentTo(render) gravity=LinearVectorForce(0.0, 0.0, self.__gravity) fn.addForce(gravity) self.phys.addLinearForce(gravity) self.gravity = gravity fn=ForceNode("priorParent") fnp=NodePath(fn) fnp.reparentTo(render) priorParent=LinearVectorForce(0.0, 0.0, 0.0) fn.addForce(priorParent) self.phys.addLinearForce(priorParent) self.priorParentNp = fnp self.priorParent = priorParent fn=ForceNode("viscosity") fnp=NodePath(fn) #fnp.reparentTo(physicsActor) fnp.reparentTo(render) self.avatarViscosity=LinearFrictionForce(0.0, 1.0, 0) #self.avatarViscosity.setCoef(0.9) fn.addForce(self.avatarViscosity) self.phys.addLinearForce(self.avatarViscosity) self.phys.attachLinearIntegrator(LinearEulerIntegrator()) self.phys.attachPhysicalnode(physicsActor.node()) self.acForce=LinearVectorForce(0.0, 0.0, 0.0) fn=ForceNode("avatarControls") fnp=NodePath(fn) fnp.reparentTo(render) fn.addForce(self.acForce) self.phys.addLinearForce(self.acForce) #self.phys.removeLinearForce(self.acForce) #fnp.remove() return avatarNodePath def initializeCollisions(self, collisionTraverser, avatarNodePath, wallBitmask, floorBitmask, avatarRadius = 1.4, floorOffset = 1.0): """ Set up the avatar collisions """ assert(self.debugPrint("initializeCollisions()")) assert not avatarNodePath.isEmpty() self.cTrav = collisionTraverser self.floorOffset = floorOffset = 7.0 self.avatarNodePath = self.setupPhysics(avatarNodePath) if 1 or self.useHeightRay: #self.setupRay(floorBitmask, avatarRadius) self.setupRay(floorBitmask, 0.0) self.setupSphere(wallBitmask|floorBitmask, avatarRadius) self.setCollisionsActive(1) def setAirborneHeightFunc(self, getAirborneHeight): self.getAirborneHeight = getAirborneHeight def setAvatarPhysicsIndicator(self, indicator): """ indicator is a NodePath """ assert(self.debugPrint("setAvatarPhysicsIndicator()")) self.cSphereNodePath.show() if indicator: # Indicator Node: change=render.attachNewNode("change") #change.setPos(Vec3(1.0, 1.0, 1.0)) #change.setHpr(0.0, 0.0, 0.0) change.setScale(0.1) #change.setColor(Vec4(1.0, 1.0, 1.0, 1.0)) indicator.reparentTo(change) indicatorNode=render.attachNewNode("physVelocityIndicator") #indicatorNode.setScale(0.1) #indicatorNode.setP(90.0) indicatorNode.setPos(self.avatarNodePath, 0.0, 0.0, 6.0) indicatorNode.setColor(0.0, 0.0, 1.0, 1.0) change.reparentTo(indicatorNode) self.physVelocityIndicator=indicatorNode # Contact Node: contactIndicatorNode=render.attachNewNode("physContactIndicator") contactIndicatorNode.setScale(0.25) contactIndicatorNode.setP(90.0) contactIndicatorNode.setPos(self.avatarNodePath, 0.0, 0.0, 5.0) contactIndicatorNode.setColor(1.0, 0.0, 0.0, 1.0) indicator.instanceTo(contactIndicatorNode) self.physContactIndicator=contactIndicatorNode else: print "failed load of physics indicator" def avatarPhysicsIndicator(self, task): #assert(self.debugPrint("avatarPhysicsIndicator()")) # Velocity: self.physVelocityIndicator.setPos(self.avatarNodePath, 0.0, 0.0, 6.0) physObject=self.actorNode.getPhysicsObject() a=physObject.getVelocity() self.physVelocityIndicator.setScale(math.sqrt(a.length())) a+=self.physVelocityIndicator.getPos() self.physVelocityIndicator.lookAt(Point3(a)) # Contact: contact=self.actorNode.getContactVector() if contact==Vec3.zero(): self.physContactIndicator.hide() else: self.physContactIndicator.show() self.physContactIndicator.setPos(self.avatarNodePath, 0.0, 0.0, 5.0) #contact=self.actorNode.getContactVector() point=Point3(contact+self.physContactIndicator.getPos()) self.physContactIndicator.lookAt(point) return Task.cont def deleteCollisions(self): assert(self.debugPrint("deleteCollisions()")) del self.cTrav if self.useHeightRay: del self.cRayQueue self.cRayNodePath.removeNode() del self.cRayNodePath del self.cSphere self.cSphereNodePath.removeNode() del self.cSphereNodePath del self.pusher def setCollisionsActive(self, active = 1): assert(self.debugPrint("collisionsActive(active=%s)"%(active,))) if self.collisionsActive != active: self.collisionsActive = active if active: self.cTrav.addCollider(self.cSphereNodePath, self.pusher) if self.useHeightRay: if self.useLifter: self.cTrav.addCollider(self.cRayNodePath, self.lifter) else: self.cTrav.addCollider(self.cRayNodePath, self.cRayQueue) else: self.cTrav.removeCollider(self.cSphereNodePath) if self.useHeightRay: self.cTrav.removeCollider(self.cRayNodePath) # Now that we have disabled collisions, make one more pass # right now to ensure we aren't standing in a wall. self.oneTimeCollide() def getCollisionsActive(self): assert(self.debugPrint("getCollisionsActive() returning=%s"%( self.collisionsActive,))) return self.collisionsActive def oneTimeCollide(self): """ Makes one quick collision pass for the avatar, for instance as a one-time straighten-things-up operation after collisions have been disabled. """ assert(self.debugPrint("oneTimeCollide()")) tempCTrav = CollisionTraverser() tempCTrav.addCollider(self.cRayNodePath, self.lifter) tempCTrav.traverse(render) def handleAvatarControls(self, task): """ Check on the arrow keys and update the avatar. """ if __debug__: if self.wantAvatarPhysicsIndicator: onScreenDebug.append("localToon pos = %s\n"%(toonbase.localToon.getPos().pPrintValues(),)) onScreenDebug.append("localToon h = % 10.4f\n"%(toonbase.localToon.getH(),)) onScreenDebug.append("localToon anim = %s\n"%(toonbase.localToon.animFSM.getCurrentState().getName(),)) #assert(self.debugPrint("handleAvatarControls(task=%s)"%(task,))) physObject=self.actorNode.getPhysicsObject() #rotAvatarToPhys=Mat3.rotateMatNormaxis(-self.avatarNodePath.getH(), Vec3.up()) #rotPhysToAvatar=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up()) contact=self.actorNode.getContactVector() # hack fix for falling through the floor: if contact==Vec3.zero() and self.avatarNodePath.getZ()<-50.0: # reset: # DCR: don't reset X and Y; allow player to move self.avatarNodePath.setZ(50.0) self.resetPhys() # get the button states: forward = inputState.isSet("forward") reverse = inputState.isSet("reverse") turnLeft = inputState.isSet("turnLeft") turnRight = inputState.isSet("turnRight") slide = inputState.isSet("slide") slideLeft = inputState.isSet("slideLeft") slideRight = inputState.isSet("slideRight") jump = inputState.isSet("jump") pie = inputState.isSet("pie") # Determine what the speeds are based on the buttons: self.__speed=(forward and self.avatarControlForwardSpeed or reverse and -self.avatarControlReverseSpeed) avatarSlideSpeed=self.avatarControlForwardSpeed*0.5 #self.__slideSpeed=slide and ( # (turnLeft and -avatarSlideSpeed) or # (turnRight and avatarSlideSpeed)) self.__slideSpeed=( (slideLeft and -avatarSlideSpeed) or (slideRight and avatarSlideSpeed)) self.__rotationSpeed=not slide and ( (turnLeft and self.avatarControlRotateSpeed) or (turnRight and -self.avatarControlRotateSpeed)) # No moving allowed while throwing a pie. if pie: self.__speed = 0 self.__slideSpeed = 0 self.__rotationSpeed = 0 jump = 0 # How far did we move based on the amount of time elapsed? dt=min(ClockObject.getGlobalClock().getDt(), 0.1) if self.needToDeltaPos: self.setPriorParentVector() self.needToDeltaPos = 0 #self.__oldPosDelta = render.getRelativeVector( # self.avatarNodePath, # self.avatarNodePath.getPosDelta(render)) #self.__oldPosDelta = self.avatarNodePath.getRelativeVector( # render, # self.avatarNodePath.getPosDelta(render)) self.__oldPosDelta = self.avatarNodePath.getPosDelta(render) self.__oldDt = dt #posDelta = self.avatarNodePath.getPosDelta(render) #if posDelta==Vec3.zero(): # self.priorParent.setVector(self.__oldPosDelta) #else: # self.priorParent.setVector(Vec3.zero()) # # We must copy the vector to preserve it: # self.__oldPosDelta=Vec3(posDelta) if __debug__: if self.wantAvatarPhysicsIndicator: onScreenDebug.add("posDelta1", self.avatarNodePath.getPosDelta(render).pPrintValues()) if 0: onScreenDebug.add("posDelta3", render.getRelativeVector( self.avatarNodePath, self.avatarNodePath.getPosDelta(render)).pPrintValues()) if 0: onScreenDebug.add("gravity", self.gravity.getLocalVector().pPrintValues()) onScreenDebug.add("priorParent", self.priorParent.getLocalVector().pPrintValues()) onScreenDebug.add("avatarViscosity", "% 10.4f"%(self.avatarViscosity.getCoef(),)) onScreenDebug.add("physObject pos", physObject.getPosition().pPrintValues()) onScreenDebug.add("physObject hpr", physObject.getOrientation().getHpr().pPrintValues()) onScreenDebug.add("physObject orien", physObject.getOrientation().pPrintValues()) if 1: onScreenDebug.add("physObject vel", physObject.getVelocity().pPrintValues()) onScreenDebug.add("physObject len", "% 10.4f"%physObject.getVelocity().length()) if 0: onScreenDebug.add("posDelta4", self.priorParentNp.getRelativeVector( render, self.avatarNodePath.getPosDelta(render)).pPrintValues()) if 1: onScreenDebug.add("priorParent", self.priorParent.getLocalVector().pPrintValues()) if 0: onScreenDebug.add("priorParent po", self.priorParent.getVector(physObject).pPrintValues()) if 0: onScreenDebug.add("__posDelta", self.__oldPosDelta.pPrintValues()) if 1: onScreenDebug.add("contact", contact.pPrintValues()) #onScreenDebug.add("airborneHeight", "% 10.4f"%( # self.getAirborneHeight(),)) if 0: onScreenDebug.add("__oldContact", contact.pPrintValues()) onScreenDebug.add("__oldAirborneHeight", "% 10.4f"%( self.getAirborneHeight(),)) airborneHeight=self.getAirborneHeight() if airborneHeight > self.highMark: self.highMark = airborneHeight if __debug__: onScreenDebug.add("highMark", "% 10.4f"%(self.highMark,)) #if airborneHeight < 0.1: #contact!=Vec3.zero(): if 1: if (airborneHeight > self.avatarRadius*0.5 or physObject.getVelocity().getZ() > 0.0 ): # Check stair angles before chaning this. # ...the avatar is airborne (maybe a lot or a tiny amount). self.isAirborne = 1 else: # ...the avatar is very close to the ground (close enough to be # considered on the ground). if self.isAirborne and physObject.getVelocity().getZ() <= 0.0: # ...the avatar has landed. contactLength = contact.length() if contactLength>self.__hardLandingForce: #print "jumpHardLand" messenger.send("jumpHardLand") else: #print "jumpLand" messenger.send("jumpLand") self.priorParent.setVector(Vec3.zero()) self.isAirborne = 0 elif jump: #print "jump" #self.__jumpButton=0 messenger.send("jumpStart") if 0: # ...jump away from walls and with with the slope normal. jumpVec=Vec3(contact+Vec3.up()) #jumpVec=Vec3(rotAvatarToPhys.xform(jumpVec)) jumpVec.normalize() else: # ...jump straight up, even if next to a wall. jumpVec=Vec3.up() jumpVec*=self.avatarControlJumpForce physObject.addImpulse(Vec3(jumpVec)) self.isAirborne = 1 # Avoid double impulse before fully airborne. else: self.isAirborne = 0 if __debug__: onScreenDebug.add("isAirborne", "%d"%(self.isAirborne,)) else: if contact!=Vec3.zero(): # ...the avatar has touched something (but might not be on the ground). contactLength = contact.length() contact.normalize() angle=contact.dot(Vec3.up()) if angle>self.__standableGround: # ...avatar is on standable ground. if self.__oldContact==Vec3.zero(): #if self.__oldAirborneHeight > 0.1: #self.__oldContact==Vec3.zero(): # ...avatar was airborne. self.jumpCount-=1 if contactLength>self.__hardLandingForce: messenger.send("jumpHardLand") else: messenger.send("jumpLand") elif jump: self.jumpCount+=1 #self.__jumpButton=0 messenger.send("jumpStart") jump=Vec3(contact+Vec3.up()) #jump=Vec3(rotAvatarToPhys.xform(jump)) jump.normalize() jump*=self.avatarControlJumpForce physObject.addImpulse(Vec3(jump)) if contact!=self.__oldContact: # We must copy the vector to preserve it: self.__oldContact=Vec3(contact) self.__oldAirborneHeight=airborneHeight moveToGround = Vec3.zero() if not self.useHeightRay or self.isAirborne: # ...the airborne check is a hack to stop sliding. self.phys.doPhysics(dt) if __debug__: onScreenDebug.add("phys", "on") else: physObject.setVelocity(Vec3.zero()) #if airborneHeight>0.001 and contact==Vec3.zero(): # moveToGround = Vec3(0.0, 0.0, -airborneHeight) #moveToGround = Vec3(0.0, 0.0, -airborneHeight) moveToGround = Vec3(0.0, 0.0, -self.determineHeight()) if __debug__: onScreenDebug.add("phys", "off") # Check to see if we're moving at all: if self.__speed or self.__slideSpeed or self.__rotationSpeed or moveToGround!=Vec3.zero(): distance = dt * self.__speed slideDistance = dt * self.__slideSpeed rotation = dt * self.__rotationSpeed #debugTempH=self.avatarNodePath.getH() assert self.avatarNodePath.getQuat().isSameDirection(physObject.getOrientation()) assert self.avatarNodePath.getPos().almostEqual(physObject.getPosition(), 0.0001) # update pos: # Take a step in the direction of our previous heading. self.__vel=Vec3( Vec3.forward() * distance + Vec3.right() * slideDistance) # rotMat is the rotation matrix corresponding to # our previous heading. rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up()) step=rotMat.xform(self.__vel) physObject.setPosition(Point3( physObject.getPosition()+step+moveToGround)) # update hpr: o=physObject.getOrientation() r=LOrientationf() r.setHpr(Vec3(rotation, 0.0, 0.0)) physObject.setOrientation(o*r) # sync the change: self.actorNode.updateTransform() assert self.avatarNodePath.getQuat().isSameDirection(physObject.getOrientation()) assert self.avatarNodePath.getPos().almostEqual(physObject.getPosition(), 0.0001) #assert self.avatarNodePath.getH()==debugTempH-rotation messenger.send("avatarMoving") else: self.__vel.set(0.0, 0.0, 0.0) # Clear the contact vector so we can tell if we contact something next frame: self.actorNode.setContactVector(Vec3.zero()) return Task.cont def doDeltaPos(self): assert(self.debugPrint("doDeltaPos()")) self.needToDeltaPos = 1 def setPriorParentVector(self): assert(self.debugPrint("doDeltaPos()")) print "self.__oldDt", self.__oldDt, "self.__oldPosDelta", self.__oldPosDelta if __debug__: onScreenDebug.add("__oldDt", "% 10.4f"%self.__oldDt) onScreenDebug.add("self.__oldPosDelta", self.__oldPosDelta.pPrintValues()) velocity = self.__oldPosDelta*(1/self.__oldDt)*4.0 # *4.0 is a hack assert(self.debugPrint(" __oldPosDelta=%s"%(self.__oldPosDelta,))) assert(self.debugPrint(" velocity=%s"%(velocity,))) self.priorParent.setVector(Vec3(velocity)) if __debug__: if self.wantAvatarPhysicsIndicator: onScreenDebug.add("velocity", velocity.pPrintValues()) def resetPhys(self): assert(self.debugPrint("resetPhys()")) self.actorNode.getPhysicsObject().resetPosition(self.avatarNodePath.getPos()) self.priorParent.setVector(Vec3.zero()) self.highMark = 0 self.actorNode.setContactVector(Vec3.zero()) if __debug__: contact=self.actorNode.getContactVector() onScreenDebug.add("priorParent po", self.priorParent.getVector(self.actorNode.getPhysicsObject()).pPrintValues()) onScreenDebug.add("highMark", "% 10.4f"%(self.highMark,)) onScreenDebug.add("contact", contact.pPrintValues()) def enableAvatarControls(self): """ Activate the arrow keys, etc. """ assert(self.debugPrint("enableAvatarControls()")) print id(self), "PW.enableAvatarControls()" assert self.collisionsActive if __debug__: self.accept("control-f3", self.spawnTest) #*# self.accept("f3", self.resetPhys) # for debugging only. taskName = "AvatarControls%s"%(id(self),) # remove any old taskMgr.remove(taskName) # spawn the new task taskMgr.add(self.handleAvatarControls, taskName, 25) if self.physVelocityIndicator: taskMgr.add(self.avatarPhysicsIndicator, "AvatarControlsIndicator%s"%(id(self),), 35) def disableAvatarControls(self): """ Ignore the arrow keys, etc. """ assert(self.debugPrint("disableAvatarControls()")) print id(self), "PW.disableAvatarControls()" taskName = "AvatarControls%s"%(id(self),) taskMgr.remove(taskName) taskName = "AvatarControlsIndicator%s"%(id(self),) taskMgr.remove(taskName) if __debug__: self.ignore("control-f3") #*# self.ignore("f3") if __debug__: def setupAvatarPhysicsIndicator(self): if self.wantAvatarPhysicsIndicator: indicator=loader.loadModelCopy('phase_5/models/props/dagger') #self.walkControls.setAvatarPhysicsIndicator(indicator) def debugPrint(self, message): """for debugging""" return self.notify.debug( str(id(self))+' '+message)